// SPDX-License-Identifier: GPL-2.0 /* * MediaTek 8365 ALSA SoC AFE platform driver * * Copyright (c) 2024 MediaTek Inc. * Authors: Jia Zeng * Alexandre Mergnat */ #include #include #include #include #include #include #include #include #include "mt8365-afe-common.h" #include "mt8365-afe-clk.h" #include "mt8365-reg.h" #include "../common/mtk-base-afe.h" #include "../common/mtk-afe-platform-driver.h" #include "../common/mtk-afe-fe-dai.h" #define AFE_BASE_END_OFFSET 8 static unsigned int mCM2Input; static const unsigned int mt8365_afe_backup_list[] = { AUDIO_TOP_CON0, AFE_CONN0, AFE_CONN1, AFE_CONN3, AFE_CONN4, AFE_CONN5, AFE_CONN6, AFE_CONN7, AFE_CONN8, AFE_CONN9, AFE_CONN10, AFE_CONN11, AFE_CONN12, AFE_CONN13, AFE_CONN14, AFE_CONN15, AFE_CONN16, AFE_CONN17, AFE_CONN18, AFE_CONN19, AFE_CONN20, AFE_CONN21, AFE_CONN26, AFE_CONN27, AFE_CONN28, AFE_CONN29, AFE_CONN30, AFE_CONN31, AFE_CONN32, AFE_CONN33, AFE_CONN34, AFE_CONN35, AFE_CONN36, AFE_CONN_24BIT, AFE_CONN_24BIT_1, AFE_DAC_CON0, AFE_DAC_CON1, AFE_DL1_BASE, AFE_DL1_END, AFE_DL2_BASE, AFE_DL2_END, AFE_VUL_BASE, AFE_VUL_END, AFE_AWB_BASE, AFE_AWB_END, AFE_VUL3_BASE, AFE_VUL3_END, AFE_HDMI_OUT_BASE, AFE_HDMI_OUT_END, AFE_HDMI_IN_2CH_BASE, AFE_HDMI_IN_2CH_END, AFE_ADDA_UL_DL_CON0, AFE_ADDA_DL_SRC2_CON0, AFE_ADDA_DL_SRC2_CON1, AFE_I2S_CON, AFE_I2S_CON1, AFE_I2S_CON2, AFE_I2S_CON3, AFE_ADDA_UL_SRC_CON0, AFE_AUD_PAD_TOP, AFE_HD_ENGEN_ENABLE, }; static const struct snd_pcm_hardware mt8365_afe_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .buffer_bytes_max = 256 * 1024, .period_bytes_min = 512, .period_bytes_max = 128 * 1024, .periods_min = 2, .periods_max = 256, .fifo_size = 0, }; struct mt8365_afe_rate { unsigned int rate; unsigned int reg_val; }; static const struct mt8365_afe_rate mt8365_afe_fs_rates[] = { { .rate = 8000, .reg_val = MT8365_FS_8K }, { .rate = 11025, .reg_val = MT8365_FS_11D025K }, { .rate = 12000, .reg_val = MT8365_FS_12K }, { .rate = 16000, .reg_val = MT8365_FS_16K }, { .rate = 22050, .reg_val = MT8365_FS_22D05K }, { .rate = 24000, .reg_val = MT8365_FS_24K }, { .rate = 32000, .reg_val = MT8365_FS_32K }, { .rate = 44100, .reg_val = MT8365_FS_44D1K }, { .rate = 48000, .reg_val = MT8365_FS_48K }, { .rate = 88200, .reg_val = MT8365_FS_88D2K }, { .rate = 96000, .reg_val = MT8365_FS_96K }, { .rate = 176400, .reg_val = MT8365_FS_176D4K }, { .rate = 192000, .reg_val = MT8365_FS_192K }, }; int mt8365_afe_fs_timing(unsigned int rate) { int i; for (i = 0; i < ARRAY_SIZE(mt8365_afe_fs_rates); i++) if (mt8365_afe_fs_rates[i].rate == rate) return mt8365_afe_fs_rates[i].reg_val; return -EINVAL; } bool mt8365_afe_rate_supported(unsigned int rate, unsigned int id) { switch (id) { case MT8365_AFE_IO_TDM_IN: if (rate >= 8000 && rate <= 192000) return true; break; case MT8365_AFE_IO_DMIC: if (rate >= 8000 && rate <= 48000) return true; break; default: break; } return false; } bool mt8365_afe_channel_supported(unsigned int channel, unsigned int id) { switch (id) { case MT8365_AFE_IO_TDM_IN: if (channel >= 1 && channel <= 8) return true; break; case MT8365_AFE_IO_DMIC: if (channel >= 1 && channel <= 8) return true; break; default: break; } return false; } static bool mt8365_afe_clk_group_44k(int sample_rate) { if (sample_rate == 11025 || sample_rate == 22050 || sample_rate == 44100 || sample_rate == 88200 || sample_rate == 176400) return true; else return false; } static bool mt8365_afe_clk_group_48k(int sample_rate) { return (!mt8365_afe_clk_group_44k(sample_rate)); } int mt8365_dai_set_priv(struct mtk_base_afe *afe, int id, int priv_size, const void *priv_data) { struct mt8365_afe_private *afe_priv = afe->platform_priv; void *temp_data; temp_data = devm_kzalloc(afe->dev, priv_size, GFP_KERNEL); if (!temp_data) return -ENOMEM; if (priv_data) memcpy(temp_data, priv_data, priv_size); afe_priv->dai_priv[id] = temp_data; return 0; } static int mt8365_afe_irq_direction_enable(struct mtk_base_afe *afe, int irq_id, int direction) { struct mtk_base_afe_irq *irq; if (irq_id >= MT8365_AFE_IRQ_NUM) return -1; irq = &afe->irqs[irq_id]; if (direction == MT8365_AFE_IRQ_DIR_MCU) { regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN, (1 << irq->irq_data->irq_clr_shift), 0); regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, (1 << irq->irq_data->irq_clr_shift), (1 << irq->irq_data->irq_clr_shift)); } else if (direction == MT8365_AFE_IRQ_DIR_DSP) { regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN, (1 << irq->irq_data->irq_clr_shift), (1 << irq->irq_data->irq_clr_shift)); regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, (1 << irq->irq_data->irq_clr_shift), 0); } else { regmap_update_bits(afe->regmap, AFE_IRQ_MCU_DSP_EN, (1 << irq->irq_data->irq_clr_shift), (1 << irq->irq_data->irq_clr_shift)); regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, (1 << irq->irq_data->irq_clr_shift), (1 << irq->irq_data->irq_clr_shift)); } return 0; } static int mt8365_memif_fs(struct snd_pcm_substream *substream, unsigned int rate) { return mt8365_afe_fs_timing(rate); } static int mt8365_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) { return mt8365_memif_fs(substream, rate); } static const struct mt8365_cm_ctrl_reg cm_ctrl_reg[MT8365_CM_NUM] = { [MT8365_CM1] = { .con0 = AFE_CM1_CON0, .con1 = AFE_CM1_CON1, .con2 = AFE_CM1_CON2, .con3 = AFE_CM1_CON3, .con4 = AFE_CM1_CON4, }, [MT8365_CM2] = { .con0 = AFE_CM2_CON0, .con1 = AFE_CM2_CON1, .con2 = AFE_CM2_CON2, .con3 = AFE_CM2_CON3, .con4 = AFE_CM2_CON4, } }; static int mt8365_afe_cm2_mux_conn(struct mtk_base_afe *afe) { struct mt8365_afe_private *afe_priv = afe->platform_priv; unsigned int input = afe_priv->cm2_mux_input; /* TDM_IN interconnect to CM2 */ regmap_update_bits(afe->regmap, AFE_CM2_CONN0, CM2_AFE_CM2_CONN_CFG1_MASK, CM2_AFE_CM2_CONN_CFG1(TDM_IN_CH0)); regmap_update_bits(afe->regmap, AFE_CM2_CONN0, CM2_AFE_CM2_CONN_CFG2_MASK, CM2_AFE_CM2_CONN_CFG2(TDM_IN_CH1)); regmap_update_bits(afe->regmap, AFE_CM2_CONN0, CM2_AFE_CM2_CONN_CFG3_MASK, CM2_AFE_CM2_CONN_CFG3(TDM_IN_CH2)); regmap_update_bits(afe->regmap, AFE_CM2_CONN0, CM2_AFE_CM2_CONN_CFG4_MASK, CM2_AFE_CM2_CONN_CFG4(TDM_IN_CH3)); regmap_update_bits(afe->regmap, AFE_CM2_CONN0, CM2_AFE_CM2_CONN_CFG5_MASK, CM2_AFE_CM2_CONN_CFG5(TDM_IN_CH4)); regmap_update_bits(afe->regmap, AFE_CM2_CONN0, CM2_AFE_CM2_CONN_CFG6_MASK, CM2_AFE_CM2_CONN_CFG6(TDM_IN_CH5)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG7_MASK, CM2_AFE_CM2_CONN_CFG7(TDM_IN_CH6)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG8_MASK, CM2_AFE_CM2_CONN_CFG8(TDM_IN_CH7)); /* ref data interconnect to CM2 */ if (input == MT8365_FROM_GASRC1) { regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG9_MASK, CM2_AFE_CM2_CONN_CFG9(GENERAL1_ASRC_OUT_LCH)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG10_MASK, CM2_AFE_CM2_CONN_CFG10(GENERAL1_ASRC_OUT_RCH)); } else if (input == MT8365_FROM_GASRC2) { regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG9_MASK, CM2_AFE_CM2_CONN_CFG9(GENERAL2_ASRC_OUT_LCH)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG10_MASK, CM2_AFE_CM2_CONN_CFG10(GENERAL2_ASRC_OUT_RCH)); } else if (input == MT8365_FROM_TDM_ASRC) { regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG9_MASK, CM2_AFE_CM2_CONN_CFG9(TDM_OUT_ASRC_CH0)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG10_MASK, CM2_AFE_CM2_CONN_CFG10(TDM_OUT_ASRC_CH1)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG11_MASK, CM2_AFE_CM2_CONN_CFG11(TDM_OUT_ASRC_CH2)); regmap_update_bits(afe->regmap, AFE_CM2_CONN1, CM2_AFE_CM2_CONN_CFG12_MASK, CM2_AFE_CM2_CONN_CFG12(TDM_OUT_ASRC_CH3)); regmap_update_bits(afe->regmap, AFE_CM2_CONN2, CM2_AFE_CM2_CONN_CFG13_MASK, CM2_AFE_CM2_CONN_CFG13(TDM_OUT_ASRC_CH4)); regmap_update_bits(afe->regmap, AFE_CM2_CONN2, CM2_AFE_CM2_CONN_CFG14_MASK, CM2_AFE_CM2_CONN_CFG14(TDM_OUT_ASRC_CH5)); regmap_update_bits(afe->regmap, AFE_CM2_CONN2, CM2_AFE_CM2_CONN_CFG15_MASK, CM2_AFE_CM2_CONN_CFG15(TDM_OUT_ASRC_CH6)); regmap_update_bits(afe->regmap, AFE_CM2_CONN2, CM2_AFE_CM2_CONN_CFG16_MASK, CM2_AFE_CM2_CONN_CFG16(TDM_OUT_ASRC_CH7)); } else { dev_err(afe->dev, "%s wrong CM2 input %d\n", __func__, input); return -1; } return 0; } static int mt8365_afe_get_cm_update_cnt(struct mtk_base_afe *afe, enum mt8365_cm_num cmNum, unsigned int rate, unsigned int channel) { unsigned int total_cnt, div_cnt, ch_pair, best_cnt; unsigned int ch_update_cnt[MT8365_CM_UPDATA_CNT_SET]; int i; /* calculate cm update cnt * total_cnt = clk / fs, clk is 26m or 24m or 22m * div_cnt = total_cnt / ch_pair, max ch 16ch ,2ch is a set * best_cnt < div_cnt ,we set best_cnt = div_cnt -10 * ch01 = best_cnt, ch23 = 2* ch01_up_cnt * ch45 = 3* ch01_up_cnt ...ch1415 = 8* ch01_up_cnt */ if (cmNum == MT8365_CM1) { total_cnt = MT8365_CLK_26M / rate; } else if (cmNum == MT8365_CM2) { if (mt8365_afe_clk_group_48k(rate)) total_cnt = MT8365_CLK_24M / rate; else total_cnt = MT8365_CLK_22M / rate; } else { return -1; } if (channel % 2) ch_pair = (channel / 2) + 1; else ch_pair = channel / 2; div_cnt = total_cnt / ch_pair; best_cnt = div_cnt - 10; if (best_cnt <= 0) return -1; for (i = 0; i < ch_pair; i++) ch_update_cnt[i] = (i + 1) * best_cnt; switch (channel) { case 16: fallthrough; case 15: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4, CM_AFE_CM_UPDATE_CNT2_MASK, CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[7])); fallthrough; case 14: fallthrough; case 13: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con4, CM_AFE_CM_UPDATE_CNT1_MASK, CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[6])); fallthrough; case 12: fallthrough; case 11: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3, CM_AFE_CM_UPDATE_CNT2_MASK, CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[5])); fallthrough; case 10: fallthrough; case 9: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con3, CM_AFE_CM_UPDATE_CNT1_MASK, CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[4])); fallthrough; case 8: fallthrough; case 7: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2, CM_AFE_CM_UPDATE_CNT2_MASK, CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[3])); fallthrough; case 6: fallthrough; case 5: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con2, CM_AFE_CM_UPDATE_CNT1_MASK, CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[2])); fallthrough; case 4: fallthrough; case 3: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1, CM_AFE_CM_UPDATE_CNT2_MASK, CM_AFE_CM_UPDATE_CNT2(ch_update_cnt[1])); fallthrough; case 2: fallthrough; case 1: regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con1, CM_AFE_CM_UPDATE_CNT1_MASK, CM_AFE_CM_UPDATE_CNT1(ch_update_cnt[0])); break; default: return -1; } return 0; } static int mt8365_afe_configure_cm(struct mtk_base_afe *afe, enum mt8365_cm_num cmNum, unsigned int channels, unsigned int rate) { unsigned int val, mask; unsigned int fs = mt8365_afe_fs_timing(rate); val = FIELD_PREP(CM_AFE_CM_CH_NUM_MASK, (channels - 1)) | FIELD_PREP(CM_AFE_CM_START_DATA_MASK, 0); mask = CM_AFE_CM_CH_NUM_MASK | CM_AFE_CM_START_DATA_MASK; if (cmNum == MT8365_CM1) { val |= FIELD_PREP(CM_AFE_CM1_IN_MODE_MASK, fs); mask |= CM_AFE_CM1_VUL_SEL | CM_AFE_CM1_IN_MODE_MASK; } else if (cmNum == MT8365_CM2) { if (mt8365_afe_clk_group_48k(rate)) val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 0); else val |= FIELD_PREP(CM_AFE_CM2_CLK_SEL, 1); val |= FIELD_PREP(CM_AFE_CM2_TDM_SEL, 1); mask |= CM_AFE_CM2_TDM_SEL | CM_AFE_CM1_IN_MODE_MASK | CM_AFE_CM2_CLK_SEL; mt8365_afe_cm2_mux_conn(afe); } else { return -1; } regmap_update_bits(afe->regmap, cm_ctrl_reg[cmNum].con0, mask, val); mt8365_afe_get_cm_update_cnt(afe, cmNum, rate, channels); return 0; } static int mt8365_afe_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct snd_pcm_runtime *runtime = substream->runtime; int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; int ret; memif->substream = substream; snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware); ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); mt8365_afe_enable_main_clk(afe); return ret; } static void mt8365_afe_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); int memif_num = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; memif->substream = NULL; mt8365_afe_disable_main_clk(afe); } static int mt8365_afe_fe_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8365_afe_private *afe_priv = afe->platform_priv; struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data; int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[dai_id]; struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id]; size_t request_size = params_buffer_bytes(params); unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); unsigned int base_end_offset = 8; int ret, fs; dev_info(afe->dev, "%s %s period = %d rate = %d channels = %d\n", __func__, memif->data->name, params_period_size(params), rate, channels); if (dai_id == MT8365_AFE_MEMIF_VUL2) { if (!ctrl_data->bypass_cm1) /* configure cm1 */ mt8365_afe_configure_cm(afe, MT8365_CM1, channels, rate); else regmap_update_bits(afe->regmap, AFE_CM1_CON0, CM_AFE_CM1_VUL_SEL, CM_AFE_CM1_VUL_SEL); } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN) { if (!ctrl_data->bypass_cm2) /* configure cm2 */ mt8365_afe_configure_cm(afe, MT8365_CM2, channels, rate); else regmap_update_bits(afe->regmap, AFE_CM2_CON0, CM_AFE_CM2_TDM_SEL, ~CM_AFE_CM2_TDM_SEL); base_end_offset = 4; } if (request_size > fe_data->sram_size) { ret = snd_pcm_lib_malloc_pages(substream, request_size); if (ret < 0) { dev_err(afe->dev, "%s %s malloc pages %zu bytes failed %d\n", __func__, memif->data->name, request_size, ret); return ret; } fe_data->use_sram = false; mt8365_afe_emi_clk_on(afe); } else { struct snd_dma_buffer *dma_buf = &substream->dma_buffer; dma_buf->dev.type = SNDRV_DMA_TYPE_DEV; dma_buf->dev.dev = substream->pcm->card->dev; dma_buf->area = (unsigned char *)fe_data->sram_vir_addr; dma_buf->addr = fe_data->sram_phy_addr; dma_buf->bytes = request_size; snd_pcm_set_runtime_buffer(substream, dma_buf); fe_data->use_sram = true; } memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); memif->buffer_size = substream->runtime->dma_bytes; /* start */ regmap_write(afe->regmap, memif->data->reg_ofs_base, memif->phys_buf_addr); /* end */ regmap_write(afe->regmap, memif->data->reg_ofs_base + base_end_offset, memif->phys_buf_addr + memif->buffer_size - 1); /* set channel */ if (memif->data->mono_shift >= 0) { unsigned int mono = (params_channels(params) == 1) ? 1 : 0; if (memif->data->mono_reg < 0) dev_info(afe->dev, "%s mono_reg is NULL\n", __func__); else regmap_update_bits(afe->regmap, memif->data->mono_reg, 1 << memif->data->mono_shift, mono << memif->data->mono_shift); } /* set rate */ if (memif->data->fs_shift < 0) return 0; fs = afe->memif_fs(substream, params_rate(params)); if (fs < 0) return -EINVAL; if (memif->data->fs_reg < 0) dev_info(afe->dev, "%s fs_reg is NULL\n", __func__); else regmap_update_bits(afe->regmap, memif->data->fs_reg, memif->data->fs_maskbit << memif->data->fs_shift, fs << memif->data->fs_shift); return 0; } static int mt8365_afe_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8365_afe_private *afe_priv = afe->platform_priv; int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mt8365_fe_dai_data *fe_data = &afe_priv->fe_data[dai_id]; int ret = 0; if (fe_data->use_sram) { snd_pcm_set_runtime_buffer(substream, NULL); } else { ret = snd_pcm_lib_free_pages(substream); mt8365_afe_emi_clk_off(afe); } return ret; } static int mt8365_afe_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mtk_base_afe_memif *memif = &afe->memif[dai_id]; /* set format */ if (memif->data->hd_reg >= 0) { switch (substream->runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: regmap_update_bits(afe->regmap, memif->data->hd_reg, 3 << memif->data->hd_shift, 0 << memif->data->hd_shift); break; case SNDRV_PCM_FORMAT_S32_LE: regmap_update_bits(afe->regmap, memif->data->hd_reg, 3 << memif->data->hd_shift, 3 << memif->data->hd_shift); if (dai_id == MT8365_AFE_MEMIF_TDM_IN) { regmap_update_bits(afe->regmap, memif->data->hd_reg, 3 << memif->data->hd_shift, 1 << memif->data->hd_shift); regmap_update_bits(afe->regmap, memif->data->hd_reg, 1 << memif->data->hd_align_mshift, 1 << memif->data->hd_align_mshift); } break; case SNDRV_PCM_FORMAT_S24_LE: regmap_update_bits(afe->regmap, memif->data->hd_reg, 3 << memif->data->hd_shift, 1 << memif->data->hd_shift); break; default: return -EINVAL; } } mt8365_afe_irq_direction_enable(afe, memif->irq_usage, MT8365_AFE_IRQ_DIR_MCU); return 0; } static int mt8365_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8365_afe_private *afe_priv = afe->platform_priv; int dai_id = snd_soc_rtd_to_cpu(rtd, 0)->id; struct mt8365_control_data *ctrl_data = &afe_priv->ctrl_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: /* enable channel merge */ if (dai_id == MT8365_AFE_MEMIF_VUL2 && !ctrl_data->bypass_cm1) { regmap_update_bits(afe->regmap, AFE_CM1_CON0, CM_AFE_CM_ON, CM_AFE_CM_ON); } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN && !ctrl_data->bypass_cm2) { regmap_update_bits(afe->regmap, AFE_CM2_CON0, CM_AFE_CM_ON, CM_AFE_CM_ON); } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: /* disable channel merge */ if (dai_id == MT8365_AFE_MEMIF_VUL2 && !ctrl_data->bypass_cm1) { regmap_update_bits(afe->regmap, AFE_CM1_CON0, CM_AFE_CM_ON, ~CM_AFE_CM_ON); } else if (dai_id == MT8365_AFE_MEMIF_TDM_IN && !ctrl_data->bypass_cm2) { regmap_update_bits(afe->regmap, AFE_CM2_CON0, CM_AFE_CM_ON, ~CM_AFE_CM_ON); } break; default: break; } return mtk_afe_fe_trigger(substream, cmd, dai); } static int mt8365_afe_hw_gain1_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); mt8365_afe_enable_main_clk(afe); return 0; } static void mt8365_afe_hw_gain1_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8365_afe_private *afe_priv = afe->platform_priv; struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; if (be->prepared[substream->stream]) { regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_EN_MASK, 0); be->prepared[substream->stream] = false; } mt8365_afe_disable_main_clk(afe); } static int mt8365_afe_hw_gain1_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct mt8365_afe_private *afe_priv = afe->platform_priv; struct mt8365_be_dai_data *be = &afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE]; int fs; unsigned int val1 = 0, val2 = 0; if (be->prepared[substream->stream]) { dev_info(afe->dev, "%s prepared already\n", __func__); return 0; } fs = mt8365_afe_fs_timing(substream->runtime->rate); regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_MODE_MASK, (unsigned int)fs << 4); regmap_read(afe->regmap, AFE_GAIN1_CON1, &val1); regmap_read(afe->regmap, AFE_GAIN1_CUR, &val2); if ((val1 & AFE_GAIN1_CON1_MASK) != (val2 & AFE_GAIN1_CUR_MASK)) regmap_update_bits(afe->regmap, AFE_GAIN1_CUR, AFE_GAIN1_CUR_MASK, val1); regmap_update_bits(afe->regmap, AFE_GAIN1_CON0, AFE_GAIN1_CON0_EN_MASK, 1); be->prepared[substream->stream] = true; return 0; } static const struct snd_pcm_hardware mt8365_hostless_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .period_bytes_min = 256, .period_bytes_max = 4 * 48 * 1024, .periods_min = 2, .periods_max = 256, .buffer_bytes_max = 8 * 48 * 1024, .fifo_size = 0, }; /* dai ops */ static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); struct snd_pcm_runtime *runtime = substream->runtime; int ret; snd_soc_set_runtime_hwparams(substream, &mt8365_hostless_hardware); ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); return ret; } /* FE DAIs */ static const struct snd_soc_dai_ops mt8365_afe_fe_dai_ops = { .startup = mt8365_afe_fe_startup, .shutdown = mt8365_afe_fe_shutdown, .hw_params = mt8365_afe_fe_hw_params, .hw_free = mt8365_afe_fe_hw_free, .prepare = mt8365_afe_fe_prepare, .trigger = mt8365_afe_fe_trigger, }; static const struct snd_soc_dai_ops mt8365_dai_hostless_ops = { .startup = mtk_dai_hostless_startup, }; static const struct snd_soc_dai_ops mt8365_afe_hw_gain1_ops = { .startup = mt8365_afe_hw_gain1_startup, .shutdown = mt8365_afe_hw_gain1_shutdown, .prepare = mt8365_afe_hw_gain1_prepare, }; static struct snd_soc_dai_driver mt8365_memif_dai_driver[] = { /* FE DAIs: memory intefaces to CPU */ { .name = "DL1", .id = MT8365_AFE_MEMIF_DL1, .playback = { .stream_name = "DL1", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "DL2", .id = MT8365_AFE_MEMIF_DL2, .playback = { .stream_name = "DL2", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "TDM_OUT", .id = MT8365_AFE_MEMIF_TDM_OUT, .playback = { .stream_name = "TDM_OUT", .channels_min = 1, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "AWB", .id = MT8365_AFE_MEMIF_AWB, .capture = { .stream_name = "AWB", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "VUL", .id = MT8365_AFE_MEMIF_VUL, .capture = { .stream_name = "VUL", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "VUL2", .id = MT8365_AFE_MEMIF_VUL2, .capture = { .stream_name = "VUL2", .channels_min = 1, .channels_max = 16, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "VUL3", .id = MT8365_AFE_MEMIF_VUL3, .capture = { .stream_name = "VUL3", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "TDM_IN", .id = MT8365_AFE_MEMIF_TDM_IN, .capture = { .stream_name = "TDM_IN", .channels_min = 1, .channels_max = 16, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_fe_dai_ops, }, { .name = "Hostless FM DAI", .id = MT8365_AFE_IO_VIRTUAL_FM, .playback = { .stream_name = "Hostless FM DL", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { .stream_name = "Hostless FM UL", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_dai_hostless_ops, }, { .name = "HW_GAIN1", .id = MT8365_AFE_IO_HW_GAIN1, .playback = { .stream_name = "HW Gain 1 In", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { .stream_name = "HW Gain 1 Out", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &mt8365_afe_hw_gain1_ops, .symmetric_rate = 1, .symmetric_channels = 1, .symmetric_sample_bits = 1, }, }; static const struct snd_kcontrol_new mt8365_afe_o00_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN0, 5, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN0, 7, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o01_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN1, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN1, 8, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o03_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN3, 5, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN3, 7, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN3, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I10 Switch", AFE_CONN3, 10, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o04_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN4, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN4, 8, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN4, 1, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I11 Switch", AFE_CONN4, 11, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o05_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN5, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN5, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN5, 5, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN5, 7, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN5, 9, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN5, 14, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN5, 16, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN5, 18, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN5, 20, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN5, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I10L Switch", AFE_CONN5, 10, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o06_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN6, 1, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN6, 4, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN6, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN6, 8, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN6, 22, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN6, 15, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN6, 17, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN6, 19, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN6, 21, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN6, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I11L Switch", AFE_CONN6, 11, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o07_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN7, 5, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN7, 7, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o08_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN8, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN8, 8, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o09_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN9, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN9, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN9, 9, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN9, 14, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN9, 16, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN9, 18, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN9, 20, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o10_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN10, 1, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN10, 4, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN10, 22, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN10, 15, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN10, 17, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN10, 19, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN10, 21, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o11_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN11, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN11, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I09 Switch", AFE_CONN11, 9, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN11, 14, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN11, 16, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN11, 18, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN11, 20, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o12_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN12, 1, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN12, 4, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I22 Switch", AFE_CONN12, 22, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN12, 15, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN12, 17, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN12, 19, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN12, 21, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o13_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN13, 0, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o14_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN14, 1, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o15_mix[] = { }; static const struct snd_kcontrol_new mt8365_afe_o16_mix[] = { }; static const struct snd_kcontrol_new mt8365_afe_o17_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN17, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o18_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN18, 4, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN18, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN18, 25, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o19_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN19, 4, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN19, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN19, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN19, 25, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN19, 26, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o20_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN20, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN20, 26, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o21_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN21, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN21, 25, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o22_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN22, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN22, 26, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o23_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN23, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN23, 25, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o24_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN24, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN24, 26, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN24, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN24, 25, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o25_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I27 Switch", AFE_CONN25, 27, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I23 Switch", AFE_CONN25, 23, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I25 Switch", AFE_CONN25, 25, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o26_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I28 Switch", AFE_CONN26, 28, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I24 Switch", AFE_CONN26, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN26, 26, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o27_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN27, 5, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN27, 7, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o28_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN28, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN28, 8, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o29_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN29, 5, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN29, 7, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o30_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN30, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN30, 8, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o31_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I29 Switch", AFE_CONN31, 29, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o32_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I30 Switch", AFE_CONN32, 30, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o33_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I31 Switch", AFE_CONN33, 31, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o34_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I32 Switch", AFE_CONN34_1, 0, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o35_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I33 Switch", AFE_CONN35_1, 1, 1, 0), }; static const struct snd_kcontrol_new mt8365_afe_o36_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I34 Switch", AFE_CONN36_1, 2, 1, 0), }; static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13, 0, 1, 0), }; static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14, 1, 1, 0), }; static int mt8365_afe_cm2_io_input_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { ucontrol->value.integer.value[0] = mCM2Input; return 0; } static int mt8365_afe_cm2_io_input_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct snd_soc_component *comp = snd_soc_dapm_to_component(dapm); struct mtk_base_afe *afe = snd_soc_component_get_drvdata(comp); struct mt8365_afe_private *afe_priv = afe->platform_priv; int ret; mCM2Input = ucontrol->value.enumerated.item[0]; afe_priv->cm2_mux_input = mCM2Input; ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); return ret; } static const char * const fmhwgain_text[] = { "OPEN", "FM_HW_GAIN_IO" }; static const char * const ain_text[] = { "INT ADC", "EXT ADC", }; static const char * const vul2_in_input_text[] = { "VUL2_IN_FROM_O17O18", "VUL2_IN_FROM_CM1", }; static const char * const mt8365_afe_cm2_mux_text[] = { "OPEN", "FROM_GASRC1_OUT", "FROM_GASRC2_OUT", "FROM_TDM_ASRC_OUT", }; static SOC_ENUM_SINGLE_VIRT_DECL(fmhwgain_enum, fmhwgain_text); static SOC_ENUM_SINGLE_DECL(ain_enum, AFE_ADDA_TOP_CON0, 0, ain_text); static SOC_ENUM_SINGLE_VIRT_DECL(vul2_in_input_enum, vul2_in_input_text); static SOC_ENUM_SINGLE_VIRT_DECL(mt8365_afe_cm2_mux_input_enum, mt8365_afe_cm2_mux_text); static const struct snd_kcontrol_new fmhwgain_mux = SOC_DAPM_ENUM("FM HW Gain Source", fmhwgain_enum); static const struct snd_kcontrol_new ain_mux = SOC_DAPM_ENUM("AIN Source", ain_enum); static const struct snd_kcontrol_new vul2_in_input_mux = SOC_DAPM_ENUM("VUL2 Input", vul2_in_input_enum); static const struct snd_kcontrol_new mt8365_afe_cm2_mux_input_mux = SOC_DAPM_ENUM_EXT("CM2_MUX Source", mt8365_afe_cm2_mux_input_enum, mt8365_afe_cm2_io_input_mux_get, mt8365_afe_cm2_io_input_mux_put); static const struct snd_soc_dapm_widget mt8365_memif_widgets[] = { /* inter-connections */ SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I05", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I06", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I07", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I08", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I05L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I06L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I07L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I08L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I09", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I10", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I11", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I10L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I11L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I20", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I21", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I22", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I23", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I24", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I25", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I27", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I28", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I29", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I30", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I31", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I32", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I33", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("I34", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, mt8365_afe_o00_mix, ARRAY_SIZE(mt8365_afe_o00_mix)), SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, mt8365_afe_o01_mix, ARRAY_SIZE(mt8365_afe_o01_mix)), SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, mt8365_afe_o03_mix, ARRAY_SIZE(mt8365_afe_o03_mix)), SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, mt8365_afe_o04_mix, ARRAY_SIZE(mt8365_afe_o04_mix)), SND_SOC_DAPM_MIXER("O05", SND_SOC_NOPM, 0, 0, mt8365_afe_o05_mix, ARRAY_SIZE(mt8365_afe_o05_mix)), SND_SOC_DAPM_MIXER("O06", SND_SOC_NOPM, 0, 0, mt8365_afe_o06_mix, ARRAY_SIZE(mt8365_afe_o06_mix)), SND_SOC_DAPM_MIXER("O07", SND_SOC_NOPM, 0, 0, mt8365_afe_o07_mix, ARRAY_SIZE(mt8365_afe_o07_mix)), SND_SOC_DAPM_MIXER("O08", SND_SOC_NOPM, 0, 0, mt8365_afe_o08_mix, ARRAY_SIZE(mt8365_afe_o08_mix)), SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, mt8365_afe_o09_mix, ARRAY_SIZE(mt8365_afe_o09_mix)), SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, mt8365_afe_o10_mix, ARRAY_SIZE(mt8365_afe_o10_mix)), SND_SOC_DAPM_MIXER("O11", SND_SOC_NOPM, 0, 0, mt8365_afe_o11_mix, ARRAY_SIZE(mt8365_afe_o11_mix)), SND_SOC_DAPM_MIXER("O12", SND_SOC_NOPM, 0, 0, mt8365_afe_o12_mix, ARRAY_SIZE(mt8365_afe_o12_mix)), SND_SOC_DAPM_MIXER("O13", SND_SOC_NOPM, 0, 0, mt8365_afe_o13_mix, ARRAY_SIZE(mt8365_afe_o13_mix)), SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, mt8365_afe_o14_mix, ARRAY_SIZE(mt8365_afe_o14_mix)), SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, mt8365_afe_o15_mix, ARRAY_SIZE(mt8365_afe_o15_mix)), SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, mt8365_afe_o16_mix, ARRAY_SIZE(mt8365_afe_o16_mix)), SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, mt8365_afe_o17_mix, ARRAY_SIZE(mt8365_afe_o17_mix)), SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, mt8365_afe_o18_mix, ARRAY_SIZE(mt8365_afe_o18_mix)), SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, mt8365_afe_o19_mix, ARRAY_SIZE(mt8365_afe_o19_mix)), SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, mt8365_afe_o20_mix, ARRAY_SIZE(mt8365_afe_o20_mix)), SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, mt8365_afe_o21_mix, ARRAY_SIZE(mt8365_afe_o21_mix)), SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, mt8365_afe_o22_mix, ARRAY_SIZE(mt8365_afe_o22_mix)), SND_SOC_DAPM_MIXER("O23", SND_SOC_NOPM, 0, 0, mt8365_afe_o23_mix, ARRAY_SIZE(mt8365_afe_o23_mix)), SND_SOC_DAPM_MIXER("O24", SND_SOC_NOPM, 0, 0, mt8365_afe_o24_mix, ARRAY_SIZE(mt8365_afe_o24_mix)), SND_SOC_DAPM_MIXER("O25", SND_SOC_NOPM, 0, 0, mt8365_afe_o25_mix, ARRAY_SIZE(mt8365_afe_o25_mix)), SND_SOC_DAPM_MIXER("O26", SND_SOC_NOPM, 0, 0, mt8365_afe_o26_mix, ARRAY_SIZE(mt8365_afe_o26_mix)), SND_SOC_DAPM_MIXER("O27", SND_SOC_NOPM, 0, 0, mt8365_afe_o27_mix, ARRAY_SIZE(mt8365_afe_o27_mix)), SND_SOC_DAPM_MIXER("O28", SND_SOC_NOPM, 0, 0, mt8365_afe_o28_mix, ARRAY_SIZE(mt8365_afe_o28_mix)), SND_SOC_DAPM_MIXER("O29", SND_SOC_NOPM, 0, 0, mt8365_afe_o29_mix, ARRAY_SIZE(mt8365_afe_o29_mix)), SND_SOC_DAPM_MIXER("O30", SND_SOC_NOPM, 0, 0, mt8365_afe_o30_mix, ARRAY_SIZE(mt8365_afe_o30_mix)), SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, mt8365_afe_o31_mix, ARRAY_SIZE(mt8365_afe_o31_mix)), SND_SOC_DAPM_MIXER("O32", SND_SOC_NOPM, 0, 0, mt8365_afe_o32_mix, ARRAY_SIZE(mt8365_afe_o32_mix)), SND_SOC_DAPM_MIXER("O33", SND_SOC_NOPM, 0, 0, mt8365_afe_o33_mix, ARRAY_SIZE(mt8365_afe_o33_mix)), SND_SOC_DAPM_MIXER("O34", SND_SOC_NOPM, 0, 0, mt8365_afe_o34_mix, ARRAY_SIZE(mt8365_afe_o34_mix)), SND_SOC_DAPM_MIXER("O35", SND_SOC_NOPM, 0, 0, mt8365_afe_o35_mix, ARRAY_SIZE(mt8365_afe_o35_mix)), SND_SOC_DAPM_MIXER("O36", SND_SOC_NOPM, 0, 0, mt8365_afe_o36_mix, ARRAY_SIZE(mt8365_afe_o36_mix)), SND_SOC_DAPM_MIXER("CM2_Mux IO", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("CM1_IO", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("O17O18", SND_SOC_NOPM, 0, 0, NULL, 0), /* inter-connections */ SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0, mtk_hw_gain1_in_ch1_mix, ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)), SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0, mtk_hw_gain1_in_ch2_mix, ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)), SND_SOC_DAPM_INPUT("DL Source"), SND_SOC_DAPM_MUX("CM2_Mux_IO Input Mux", SND_SOC_NOPM, 0, 0, &mt8365_afe_cm2_mux_input_mux), SND_SOC_DAPM_MUX("AIN Mux", SND_SOC_NOPM, 0, 0, &ain_mux), SND_SOC_DAPM_MUX("VUL2 Input Mux", SND_SOC_NOPM, 0, 0, &vul2_in_input_mux), SND_SOC_DAPM_MUX("FM HW Gain Mux", SND_SOC_NOPM, 0, 0, &fmhwgain_mux), SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"), SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"), }; static const struct snd_soc_dapm_route mt8365_memif_routes[] = { /* downlink */ {"I00", NULL, "2ND I2S Capture"}, {"I01", NULL, "2ND I2S Capture"}, {"I05", NULL, "DL1"}, {"I06", NULL, "DL1"}, {"I07", NULL, "DL2"}, {"I08", NULL, "DL2"}, {"O03", "I05 Switch", "I05"}, {"O04", "I06 Switch", "I06"}, {"O00", "I05 Switch", "I05"}, {"O01", "I06 Switch", "I06"}, {"O07", "I05 Switch", "I05"}, {"O08", "I06 Switch", "I06"}, {"O27", "I05 Switch", "I05"}, {"O28", "I06 Switch", "I06"}, {"O29", "I05 Switch", "I05"}, {"O30", "I06 Switch", "I06"}, {"O03", "I07 Switch", "I07"}, {"O04", "I08 Switch", "I08"}, {"O00", "I07 Switch", "I07"}, {"O01", "I08 Switch", "I08"}, {"O07", "I07 Switch", "I07"}, {"O08", "I08 Switch", "I08"}, /* uplink */ {"AWB", NULL, "O05"}, {"AWB", NULL, "O06"}, {"VUL", NULL, "O09"}, {"VUL", NULL, "O10"}, {"VUL3", NULL, "O11"}, {"VUL3", NULL, "O12"}, {"AIN Mux", "EXT ADC", "I2S Capture"}, {"I03", NULL, "AIN Mux"}, {"I04", NULL, "AIN Mux"}, {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1", "Hostless FM DL"}, {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2", "Hostless FM DL"}, {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"}, {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"}, {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"}, {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"}, {"FM HW Gain Mux", "FM_HW_GAIN_IO", "HW Gain 1 Out"}, {"Hostless FM UL", NULL, "FM HW Gain Mux"}, {"Hostless FM UL", NULL, "FM 2ND I2S Mux"}, {"O05", "I05 Switch", "I05L"}, {"O06", "I06 Switch", "I06L"}, {"O05", "I07 Switch", "I07L"}, {"O06", "I08 Switch", "I08L"}, {"O05", "I03 Switch", "I03"}, {"O06", "I04 Switch", "I04"}, {"O05", "I00 Switch", "I00"}, {"O06", "I01 Switch", "I01"}, {"O05", "I09 Switch", "I09"}, {"O06", "I22 Switch", "I22"}, {"O05", "I14 Switch", "I14"}, {"O06", "I15 Switch", "I15"}, {"O05", "I16 Switch", "I16"}, {"O06", "I17 Switch", "I17"}, {"O05", "I18 Switch", "I18"}, {"O06", "I19 Switch", "I19"}, {"O05", "I20 Switch", "I20"}, {"O06", "I21 Switch", "I21"}, {"O05", "I23 Switch", "I23"}, {"O06", "I24 Switch", "I24"}, {"O09", "I03 Switch", "I03"}, {"O10", "I04 Switch", "I04"}, {"O09", "I00 Switch", "I00"}, {"O10", "I01 Switch", "I01"}, {"O09", "I09 Switch", "I09"}, {"O10", "I22 Switch", "I22"}, {"O09", "I14 Switch", "I14"}, {"O10", "I15 Switch", "I15"}, {"O09", "I16 Switch", "I16"}, {"O10", "I17 Switch", "I17"}, {"O09", "I18 Switch", "I18"}, {"O10", "I19 Switch", "I19"}, {"O09", "I20 Switch", "I20"}, {"O10", "I21 Switch", "I21"}, {"O11", "I03 Switch", "I03"}, {"O12", "I04 Switch", "I04"}, {"O11", "I00 Switch", "I00"}, {"O12", "I01 Switch", "I01"}, {"O11", "I09 Switch", "I09"}, {"O12", "I22 Switch", "I22"}, {"O11", "I14 Switch", "I14"}, {"O12", "I15 Switch", "I15"}, {"O11", "I16 Switch", "I16"}, {"O12", "I17 Switch", "I17"}, {"O11", "I18 Switch", "I18"}, {"O12", "I19 Switch", "I19"}, {"O11", "I20 Switch", "I20"}, {"O12", "I21 Switch", "I21"}, /* CM2_Mux*/ {"CM2_Mux IO", NULL, "CM2_Mux_IO Input Mux"}, /* VUL2 */ {"VUL2", NULL, "VUL2 Input Mux"}, {"VUL2 Input Mux", "VUL2_IN_FROM_O17O18", "O17O18"}, {"VUL2 Input Mux", "VUL2_IN_FROM_CM1", "CM1_IO"}, {"O17O18", NULL, "O17"}, {"O17O18", NULL, "O18"}, {"CM1_IO", NULL, "O17"}, {"CM1_IO", NULL, "O18"}, {"CM1_IO", NULL, "O19"}, {"CM1_IO", NULL, "O20"}, {"CM1_IO", NULL, "O21"}, {"CM1_IO", NULL, "O22"}, {"CM1_IO", NULL, "O23"}, {"CM1_IO", NULL, "O24"}, {"CM1_IO", NULL, "O25"}, {"CM1_IO", NULL, "O26"}, {"CM1_IO", NULL, "O31"}, {"CM1_IO", NULL, "O32"}, {"CM1_IO", NULL, "O33"}, {"CM1_IO", NULL, "O34"}, {"CM1_IO", NULL, "O35"}, {"CM1_IO", NULL, "O36"}, {"O17", "I14 Switch", "I14"}, {"O18", "I15 Switch", "I15"}, {"O19", "I16 Switch", "I16"}, {"O20", "I17 Switch", "I17"}, {"O21", "I18 Switch", "I18"}, {"O22", "I19 Switch", "I19"}, {"O23", "I20 Switch", "I20"}, {"O24", "I21 Switch", "I21"}, {"O25", "I23 Switch", "I23"}, {"O26", "I24 Switch", "I24"}, {"O25", "I25 Switch", "I25"}, {"O26", "I26 Switch", "I26"}, {"O17", "I03 Switch", "I03"}, {"O18", "I04 Switch", "I04"}, {"O18", "I23 Switch", "I23"}, {"O18", "I25 Switch", "I25"}, {"O19", "I04 Switch", "I04"}, {"O19", "I23 Switch", "I23"}, {"O19", "I24 Switch", "I24"}, {"O19", "I25 Switch", "I25"}, {"O19", "I26 Switch", "I26"}, {"O20", "I24 Switch", "I24"}, {"O20", "I26 Switch", "I26"}, {"O21", "I23 Switch", "I23"}, {"O21", "I25 Switch", "I25"}, {"O22", "I24 Switch", "I24"}, {"O22", "I26 Switch", "I26"}, {"O23", "I23 Switch", "I23"}, {"O23", "I25 Switch", "I25"}, {"O24", "I24 Switch", "I24"}, {"O24", "I26 Switch", "I26"}, {"O24", "I23 Switch", "I23"}, {"O24", "I25 Switch", "I25"}, {"O13", "I00 Switch", "I00"}, {"O14", "I01 Switch", "I01"}, {"O03", "I10 Switch", "I10"}, {"O04", "I11 Switch", "I11"}, }; static const struct mtk_base_memif_data memif_data[MT8365_AFE_MEMIF_NUM] = { { .name = "DL1", .id = MT8365_AFE_MEMIF_DL1, .reg_ofs_base = AFE_DL1_BASE, .reg_ofs_cur = AFE_DL1_CUR, .fs_reg = AFE_DAC_CON1, .fs_shift = 0, .fs_maskbit = 0xf, .mono_reg = AFE_DAC_CON1, .mono_shift = 21, .hd_reg = AFE_MEMIF_PBUF_SIZE, .hd_shift = 16, .enable_reg = AFE_DAC_CON0, .enable_shift = 1, .msb_reg = -1, .msb_shift = -1, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "DL2", .id = MT8365_AFE_MEMIF_DL2, .reg_ofs_base = AFE_DL2_BASE, .reg_ofs_cur = AFE_DL2_CUR, .fs_reg = AFE_DAC_CON1, .fs_shift = 4, .fs_maskbit = 0xf, .mono_reg = AFE_DAC_CON1, .mono_shift = 22, .hd_reg = AFE_MEMIF_PBUF_SIZE, .hd_shift = 18, .enable_reg = AFE_DAC_CON0, .enable_shift = 2, .msb_reg = -1, .msb_shift = -1, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "TDM OUT", .id = MT8365_AFE_MEMIF_TDM_OUT, .reg_ofs_base = AFE_HDMI_OUT_BASE, .reg_ofs_cur = AFE_HDMI_OUT_CUR, .fs_reg = -1, .fs_shift = -1, .fs_maskbit = -1, .mono_reg = -1, .mono_shift = -1, .hd_reg = AFE_MEMIF_PBUF_SIZE, .hd_shift = 28, .enable_reg = AFE_HDMI_OUT_CON0, .enable_shift = 0, .msb_reg = -1, .msb_shift = -1, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "AWB", .id = MT8365_AFE_MEMIF_AWB, .reg_ofs_base = AFE_AWB_BASE, .reg_ofs_cur = AFE_AWB_CUR, .fs_reg = AFE_DAC_CON1, .fs_shift = 12, .fs_maskbit = 0xf, .mono_reg = AFE_DAC_CON1, .mono_shift = 24, .hd_reg = AFE_MEMIF_PBUF_SIZE, .hd_shift = 20, .enable_reg = AFE_DAC_CON0, .enable_shift = 6, .msb_reg = AFE_MEMIF_MSB, .msb_shift = 17, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "VUL", .id = MT8365_AFE_MEMIF_VUL, .reg_ofs_base = AFE_VUL_BASE, .reg_ofs_cur = AFE_VUL_CUR, .fs_reg = AFE_DAC_CON1, .fs_shift = 16, .fs_maskbit = 0xf, .mono_reg = AFE_DAC_CON1, .mono_shift = 27, .hd_reg = AFE_MEMIF_PBUF_SIZE, .hd_shift = 22, .enable_reg = AFE_DAC_CON0, .enable_shift = 3, .msb_reg = AFE_MEMIF_MSB, .msb_shift = 20, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "VUL2", .id = MT8365_AFE_MEMIF_VUL2, .reg_ofs_base = AFE_VUL_D2_BASE, .reg_ofs_cur = AFE_VUL_D2_CUR, .fs_reg = AFE_DAC_CON0, .fs_shift = 20, .fs_maskbit = 0xf, .mono_reg = -1, .mono_shift = -1, .hd_reg = AFE_MEMIF_PBUF_SIZE, .hd_shift = 14, .enable_reg = AFE_DAC_CON0, .enable_shift = 9, .msb_reg = AFE_MEMIF_MSB, .msb_shift = 21, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "VUL3", .id = MT8365_AFE_MEMIF_VUL3, .reg_ofs_base = AFE_VUL3_BASE, .reg_ofs_cur = AFE_VUL3_CUR, .fs_reg = AFE_DAC_CON1, .fs_shift = 8, .fs_maskbit = 0xf, .mono_reg = AFE_DAC_CON0, .mono_shift = 13, .hd_reg = AFE_MEMIF_PBUF2_SIZE, .hd_shift = 10, .enable_reg = AFE_DAC_CON0, .enable_shift = 12, .msb_reg = AFE_MEMIF_MSB, .msb_shift = 27, .agent_disable_reg = -1, .agent_disable_shift = -1, }, { .name = "TDM IN", .id = MT8365_AFE_MEMIF_TDM_IN, .reg_ofs_base = AFE_HDMI_IN_2CH_BASE, .reg_ofs_cur = AFE_HDMI_IN_2CH_CUR, .fs_reg = -1, .fs_shift = -1, .fs_maskbit = -1, .mono_reg = AFE_HDMI_IN_2CH_CON0, .mono_shift = 1, .hd_reg = AFE_MEMIF_PBUF2_SIZE, .hd_shift = 8, .hd_align_mshift = 5, .enable_reg = AFE_HDMI_IN_2CH_CON0, .enable_shift = 0, .msb_reg = AFE_MEMIF_MSB, .msb_shift = 28, .agent_disable_reg = -1, .agent_disable_shift = -1, }, }; static const struct mtk_base_irq_data irq_data[MT8365_AFE_IRQ_NUM] = { { .id = MT8365_AFE_IRQ1, .irq_cnt_reg = AFE_IRQ_MCU_CNT1, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 0, .irq_fs_reg = AFE_IRQ_MCU_CON, .irq_fs_shift = 4, .irq_fs_maskbit = 0xf, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 0, }, { .id = MT8365_AFE_IRQ2, .irq_cnt_reg = AFE_IRQ_MCU_CNT2, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 1, .irq_fs_reg = AFE_IRQ_MCU_CON, .irq_fs_shift = 8, .irq_fs_maskbit = 0xf, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 1, }, { .id = MT8365_AFE_IRQ3, .irq_cnt_reg = AFE_IRQ_MCU_CNT3, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 2, .irq_fs_reg = AFE_IRQ_MCU_CON, .irq_fs_shift = 16, .irq_fs_maskbit = 0xf, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 2, }, { .id = MT8365_AFE_IRQ4, .irq_cnt_reg = AFE_IRQ_MCU_CNT4, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 3, .irq_fs_reg = AFE_IRQ_MCU_CON, .irq_fs_shift = 20, .irq_fs_maskbit = 0xf, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 3, }, { .id = MT8365_AFE_IRQ5, .irq_cnt_reg = AFE_IRQ_MCU_CNT5, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON2, .irq_en_shift = 3, .irq_fs_reg = -1, .irq_fs_shift = 0, .irq_fs_maskbit = 0x0, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 4, }, { .id = MT8365_AFE_IRQ6, .irq_cnt_reg = -1, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x0, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 13, .irq_fs_reg = -1, .irq_fs_shift = 0, .irq_fs_maskbit = 0x0, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 5, }, { .id = MT8365_AFE_IRQ7, .irq_cnt_reg = AFE_IRQ_MCU_CNT7, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 14, .irq_fs_reg = AFE_IRQ_MCU_CON, .irq_fs_shift = 24, .irq_fs_maskbit = 0xf, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 6, }, { .id = MT8365_AFE_IRQ8, .irq_cnt_reg = AFE_IRQ_MCU_CNT8, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON, .irq_en_shift = 15, .irq_fs_reg = AFE_IRQ_MCU_CON, .irq_fs_shift = 28, .irq_fs_maskbit = 0xf, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 7, }, { .id = MT8365_AFE_IRQ9, .irq_cnt_reg = -1, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x0, .irq_en_reg = AFE_IRQ_MCU_CON2, .irq_en_shift = 2, .irq_fs_reg = -1, .irq_fs_shift = 0, .irq_fs_maskbit = 0x0, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 8, }, { .id = MT8365_AFE_IRQ10, .irq_cnt_reg = AFE_IRQ_MCU_CNT10, .irq_cnt_shift = 0, .irq_cnt_maskbit = 0x3ffff, .irq_en_reg = AFE_IRQ_MCU_CON2, .irq_en_shift = 4, .irq_fs_reg = -1, .irq_fs_shift = 0, .irq_fs_maskbit = 0x0, .irq_clr_reg = AFE_IRQ_MCU_CLR, .irq_clr_shift = 9, }, }; static int memif_specified_irqs[MT8365_AFE_MEMIF_NUM] = { [MT8365_AFE_MEMIF_DL1] = MT8365_AFE_IRQ1, [MT8365_AFE_MEMIF_DL2] = MT8365_AFE_IRQ2, [MT8365_AFE_MEMIF_TDM_OUT] = MT8365_AFE_IRQ5, [MT8365_AFE_MEMIF_AWB] = MT8365_AFE_IRQ3, [MT8365_AFE_MEMIF_VUL] = MT8365_AFE_IRQ4, [MT8365_AFE_MEMIF_VUL2] = MT8365_AFE_IRQ7, [MT8365_AFE_MEMIF_VUL3] = MT8365_AFE_IRQ8, [MT8365_AFE_MEMIF_TDM_IN] = MT8365_AFE_IRQ10, }; static const struct regmap_config mt8365_afe_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, .max_register = MAX_REGISTER, .cache_type = REGCACHE_NONE, }; static irqreturn_t mt8365_afe_irq_handler(int irq, void *dev_id) { struct mtk_base_afe *afe = dev_id; unsigned int reg_value; unsigned int mcu_irq_mask; int i, ret; ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, ®_value); if (ret) { dev_err_ratelimited(afe->dev, "%s irq status err\n", __func__); reg_value = AFE_IRQ_STATUS_BITS; goto err_irq; } ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_irq_mask); if (ret) { dev_err_ratelimited(afe->dev, "%s irq mcu_en err\n", __func__); reg_value = AFE_IRQ_STATUS_BITS; goto err_irq; } /* only clr cpu irq */ reg_value &= mcu_irq_mask; for (i = 0; i < MT8365_AFE_MEMIF_NUM; i++) { struct mtk_base_afe_memif *memif = &afe->memif[i]; struct mtk_base_afe_irq *mcu_irq; if (memif->irq_usage < 0) continue; mcu_irq = &afe->irqs[memif->irq_usage]; if (!(reg_value & (1 << mcu_irq->irq_data->irq_clr_shift))) continue; snd_pcm_period_elapsed(memif->substream); } err_irq: /* clear irq */ regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, reg_value & AFE_IRQ_STATUS_BITS); return IRQ_HANDLED; } static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev) { return 0; } static int mt8365_afe_runtime_resume(struct device *dev) { return 0; } static int __maybe_unused mt8365_afe_suspend(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); struct regmap *regmap = afe->regmap; int i; mt8365_afe_enable_main_clk(afe); if (!afe->reg_back_up) afe->reg_back_up = devm_kcalloc(dev, afe->reg_back_up_list_num, sizeof(unsigned int), GFP_KERNEL); for (i = 0; i < afe->reg_back_up_list_num; i++) regmap_read(regmap, afe->reg_back_up_list[i], &afe->reg_back_up[i]); mt8365_afe_disable_main_clk(afe); return 0; } static int __maybe_unused mt8365_afe_resume(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); struct regmap *regmap = afe->regmap; int i = 0; if (!afe->reg_back_up) return 0; mt8365_afe_enable_main_clk(afe); for (i = 0; i < afe->reg_back_up_list_num; i++) regmap_write(regmap, afe->reg_back_up_list[i], afe->reg_back_up[i]); mt8365_afe_disable_main_clk(afe); return 0; } static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); if (pm_runtime_status_suspended(dev) || afe->suspended) return 0; mt8365_afe_suspend(dev); afe->suspended = true; return 0; } static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); if (pm_runtime_status_suspended(dev) || !afe->suspended) return 0; mt8365_afe_resume(dev); afe->suspended = false; return 0; } static int mt8365_afe_init_registers(struct mtk_base_afe *afe) { size_t i; static struct { unsigned int reg; unsigned int mask; unsigned int val; } init_regs[] = { { AFE_CONN_24BIT, GENMASK(31, 0), GENMASK(31, 0) }, { AFE_CONN_24BIT_1, GENMASK(21, 0), GENMASK(21, 0) }, }; mt8365_afe_enable_main_clk(afe); for (i = 0; i < ARRAY_SIZE(init_regs); i++) regmap_update_bits(afe->regmap, init_regs[i].reg, init_regs[i].mask, init_regs[i].val); mt8365_afe_disable_main_clk(afe); return 0; } static int mt8365_dai_memif_register(struct mtk_base_afe *afe) { struct mtk_base_afe_dai *dai; dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); if (!dai) return -ENOMEM; list_add(&dai->list, &afe->sub_dais); dai->dai_drivers = mt8365_memif_dai_driver; dai->num_dai_drivers = ARRAY_SIZE(mt8365_memif_dai_driver); dai->dapm_widgets = mt8365_memif_widgets; dai->num_dapm_widgets = ARRAY_SIZE(mt8365_memif_widgets); dai->dapm_routes = mt8365_memif_routes; dai->num_dapm_routes = ARRAY_SIZE(mt8365_memif_routes); return 0; } typedef int (*dai_register_cb)(struct mtk_base_afe *); static const dai_register_cb dai_register_cbs[] = { mt8365_dai_pcm_register, mt8365_dai_i2s_register, mt8365_dai_adda_register, mt8365_dai_dmic_register, mt8365_dai_memif_register, }; static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev) { struct mtk_base_afe *afe; struct mt8365_afe_private *afe_priv; struct device *dev; int ret, i, sel_irq; unsigned int irq_id; struct resource *res; afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); if (!afe) return -ENOMEM; platform_set_drvdata(pdev, afe); afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), GFP_KERNEL); if (!afe->platform_priv) return -ENOMEM; afe_priv = afe->platform_priv; afe->dev = &pdev->dev; dev = afe->dev; spin_lock_init(&afe_priv->afe_ctrl_lock); mutex_init(&afe_priv->afe_clk_mutex); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); afe->base_addr = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(afe->base_addr)) return PTR_ERR(afe->base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { afe_priv->afe_sram_vir_addr = devm_ioremap_resource(&pdev->dev, res); if (!IS_ERR(afe_priv->afe_sram_vir_addr)) { afe_priv->afe_sram_phy_addr = res->start; afe_priv->afe_sram_size = resource_size(res); } } /* initial audio related clock */ ret = mt8365_afe_init_audio_clk(afe); if (ret) return dev_err_probe(afe->dev, ret, "mt8365_afe_init_audio_clk fail\n"); afe->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "top_audio_sel", afe->base_addr, &mt8365_afe_regmap_config); if (IS_ERR(afe->regmap)) return PTR_ERR(afe->regmap); /* memif % irq initialize*/ afe->memif_size = MT8365_AFE_MEMIF_NUM; afe->memif = devm_kcalloc(afe->dev, afe->memif_size, sizeof(*afe->memif), GFP_KERNEL); if (!afe->memif) return -ENOMEM; afe->irqs_size = MT8365_AFE_IRQ_NUM; afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size, sizeof(*afe->irqs), GFP_KERNEL); if (!afe->irqs) return -ENOMEM; for (i = 0; i < afe->irqs_size; i++) afe->irqs[i].irq_data = &irq_data[i]; ret = platform_get_irq(pdev, 0); if (ret < 0) return ret; irq_id = ret; ret = devm_request_irq(afe->dev, irq_id, mt8365_afe_irq_handler, 0, "Afe_ISR_Handle", (void *)afe); if (ret) return dev_err_probe(afe->dev, ret, "could not request_irq\n"); /* init sub_dais */ INIT_LIST_HEAD(&afe->sub_dais); for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { ret = dai_register_cbs[i](afe); if (ret) { dev_warn(afe->dev, "dai register i %d fail, ret %d\n", i, ret); return ret; } } /* init dai_driver and component_driver */ ret = mtk_afe_combine_sub_dai(afe); if (ret) { dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n", ret); return ret; } for (i = 0; i < afe->memif_size; i++) { afe->memif[i].data = &memif_data[i]; sel_irq = memif_specified_irqs[i]; if (sel_irq >= 0) { afe->memif[i].irq_usage = sel_irq; afe->memif[i].const_irq = 1; afe->irqs[sel_irq].irq_occupyed = true; } else { afe->memif[i].irq_usage = -1; } } afe->mtk_afe_hardware = &mt8365_afe_hardware; afe->memif_fs = mt8365_memif_fs; afe->irq_fs = mt8365_irq_fs; ret = devm_pm_runtime_enable(&pdev->dev); if (ret) return ret; pm_runtime_get_sync(&pdev->dev); afe->reg_back_up_list = mt8365_afe_backup_list; afe->reg_back_up_list_num = ARRAY_SIZE(mt8365_afe_backup_list); afe->runtime_resume = mt8365_afe_runtime_resume; afe->runtime_suspend = mt8365_afe_runtime_suspend; /* open afe pdn for dapm read/write audio register */ mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_AFE); /* Set 26m parent clk */ mt8365_afe_set_clk_parent(afe, afe_priv->clocks[MT8365_CLK_TOP_AUD_SEL], afe_priv->clocks[MT8365_CLK_CLK26M]); ret = devm_snd_soc_register_component(&pdev->dev, &mtk_afe_pcm_platform, afe->dai_drivers, afe->num_dai_drivers); if (ret) { dev_warn(dev, "err_platform\n"); return ret; } mt8365_afe_init_registers(afe); return 0; } static void mt8365_afe_pcm_dev_remove(struct platform_device *pdev) { struct mtk_base_afe *afe = platform_get_drvdata(pdev); mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE); pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) mt8365_afe_runtime_suspend(&pdev->dev); } static const struct of_device_id mt8365_afe_pcm_dt_match[] = { { .compatible = "mediatek,mt8365-afe-pcm", }, { } }; MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match); static const struct dev_pm_ops mt8365_afe_pm_ops = { SET_RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend, mt8365_afe_dev_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend, mt8365_afe_resume) }; static struct platform_driver mt8365_afe_pcm_driver = { .driver = { .name = "mt8365-afe-pcm", .of_match_table = mt8365_afe_pcm_dt_match, .pm = &mt8365_afe_pm_ops, }, .probe = mt8365_afe_pcm_dev_probe, .remove = mt8365_afe_pcm_dev_remove, }; module_platform_driver(mt8365_afe_pcm_driver); MODULE_DESCRIPTION("MediaTek ALSA SoC AFE platform driver"); MODULE_AUTHOR("Jia Zeng "); MODULE_AUTHOR("Alexandre Mergnat "); MODULE_LICENSE("GPL");