This commit adds the PCM driver for the MediaTek MT8516 SoC.
Signed-off-by: Fabien Parent fparent@baylibre.com --- sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/mt8516/Makefile | 6 + sound/soc/mediatek/mt8516/mt8516-afe-pcm.c | 792 ++++++++++++++++++++ sound/soc/mediatek/mt8516/mt8516-afe-regs.h | 218 ++++++ 5 files changed, 1027 insertions(+) create mode 100644 sound/soc/mediatek/mt8516/Makefile create mode 100644 sound/soc/mediatek/mt8516/mt8516-afe-pcm.c create mode 100644 sound/soc/mediatek/mt8516/mt8516-afe-regs.h
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index b35410e4020e..f0bae957d475 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -116,6 +116,16 @@ config SND_SOC_MT8183 Select Y if you have such device. If unsure select "N".
+config SND_SOC_MT8516 + tristate "ASoC support for Mediatek MT8516 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for Mediatek MT8516 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MTK_BTCVSD tristate "ALSA BT SCO CVSD/MSBC Driver" help diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 76032cae6d51..a48500d69a8b 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ +obj-$(CONFIG_SND_SOC_MT8516) += mt8516/ diff --git a/sound/soc/mediatek/mt8516/Makefile b/sound/soc/mediatek/mt8516/Makefile new file mode 100644 index 000000000000..6e49b01d02c2 --- /dev/null +++ b/sound/soc/mediatek/mt8516/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +snd-soc-mt8516-afe-objs := \ + mt8516-afe-pcm.o + +obj-$(CONFIG_SND_SOC_MT8516) += snd-soc-mt8516-afe.o diff --git a/sound/soc/mediatek/mt8516/mt8516-afe-pcm.c b/sound/soc/mediatek/mt8516/mt8516-afe-pcm.c new file mode 100644 index 000000000000..84fbb5dbbd14 --- /dev/null +++ b/sound/soc/mediatek/mt8516/mt8516-afe-pcm.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 BayLibre, SAS + * Copyright (c) 2019 MediaTek, Inc + * Author: Fabien Parent fparent@baylibre.com + */ + +#include <sound/soc.h> +#include <sound/pcm_params.h> +#include <linux/module.h> +#include <linux/of.h> + +#include "mt8516-afe-regs.h" + +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" +#include "../common/mtk-base-afe.h" + +enum { + MT8516_AFE_MEMIF_DL1, + MT8516_AFE_MEMIF_DL2, + MT8516_AFE_MEMIF_VUL, + MT8516_AFE_MEMIF_DAI, + MT8516_AFE_MEMIF_AWB, + MT8516_AFE_MEMIF_MOD_DAI, + MT8516_AFE_MEMIF_HDMI, + MT8516_AFE_MEMIF_TDM_IN, + MT8516_AFE_MEMIF_MULTILINE_IN, + MT8516_AFE_MEMIF_NUM, +}; + +enum { + MT8516_AFE_IRQ_1 = 0, + MT8516_AFE_IRQ_2, + MT8516_AFE_IRQ_5, /* dedicated for HDMI */ + MT8516_AFE_IRQ_7, + MT8516_AFE_IRQ_10, /* dedicated for TDM IN */ + MT8516_AFE_IRQ_13, /* dedicated for ULM*/ + MT8516_AFE_IRQ_NUM +}; + +struct mt8516_afe_rate { + unsigned int rate; + unsigned int regvalue; +}; + +static const struct mt8516_afe_rate mt8516_afe_i2s_rates[] = { + { .rate = 8000, .regvalue = 0 }, + { .rate = 11025, .regvalue = 1 }, + { .rate = 12000, .regvalue = 2 }, + { .rate = 16000, .regvalue = 4 }, + { .rate = 22050, .regvalue = 5 }, + { .rate = 24000, .regvalue = 6 }, + { .rate = 32000, .regvalue = 8 }, + { .rate = 44100, .regvalue = 9 }, + { .rate = 48000, .regvalue = 10 }, + { .rate = 88000, .regvalue = 11 }, + { .rate = 96000, .regvalue = 12 }, + { .rate = 176400, .regvalue = 13 }, + { .rate = 192000, .regvalue = 14 }, +}; + +static int mt8516_afe_i2s_fs(struct snd_pcm_substream *substream, + unsigned int sample_rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt8516_afe_i2s_rates); i++) + if (mt8516_afe_i2s_rates[i].rate == sample_rate) + return mt8516_afe_i2s_rates[i].regvalue; + + return -EINVAL; +} + + +static int mt8516_afe_irq_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + return mt8516_afe_i2s_fs(substream, rate); +} + +static const unsigned int mt8516_afe_backup_list[] = { + AUDIO_TOP_CON0, + AUDIO_TOP_CON1, + AUDIO_TOP_CON3, + AFE_CONN0, + AFE_CONN1, + AFE_CONN2, + AFE_CONN3, + AFE_CONN5, + AFE_CONN_24BIT, + AFE_I2S_CON, + AFE_I2S_CON1, + AFE_I2S_CON2, + AFE_I2S_CON3, + AFE_ADDA_PREDIS_CON0, + AFE_ADDA_PREDIS_CON1, + AFE_ADDA_DL_SRC2_CON0, + AFE_ADDA_DL_SRC2_CON1, + AFE_ADDA_UL_SRC_CON0, + AFE_ADDA_UL_SRC_CON0, + AFE_ADDA_NEWIF_CFG1, + AFE_ADDA_TOP_CON0, + AFE_ADDA_UL_DL_CON0, + AFE_MEMIF_PBUF_SIZE, + AFE_MEMIF_PBUF2_SIZE, + 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_DAI_BASE, + AFE_DAI_END, + AFE_HDMI_OUT_BASE, + AFE_HDMI_OUT_END, + AFE_HDMI_IN_2CH_BASE, + AFE_HDMI_IN_2CH_END, +}; + +static const struct snd_pcm_hardware mt8516_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID, + .buffer_bytes_max = 1024 * 1024, + .period_bytes_min = 256, + .period_bytes_max = 512 * 1024, + .periods_min = 2, + .periods_max = 256, + .fifo_size = 0, +}; + +static const struct snd_kcontrol_new mt8516_afe_o03_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I07 Switch", AFE_CONN1, 23, 1, 0), +}; + +static const struct snd_kcontrol_new mt8516_afe_o04_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I08 Switch", AFE_CONN2, 8, 1, 0), +}; + +static const struct snd_kcontrol_new mt8516_afe_o09_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN5, 8, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0), +}; + +static const struct snd_kcontrol_new mt8516_afe_o10_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN5, 13, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0), +}; + +static const struct snd_soc_dapm_widget mt8516_memif_widgets[] = { + /* inter-connections */ + 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("O03", SND_SOC_NOPM, 0, 0, + mt8516_afe_o03_mix, ARRAY_SIZE(mt8516_afe_o03_mix)), + SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, + mt8516_afe_o04_mix, ARRAY_SIZE(mt8516_afe_o04_mix)), + SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, + mt8516_afe_o09_mix, ARRAY_SIZE(mt8516_afe_o09_mix)), + SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, + mt8516_afe_o10_mix, ARRAY_SIZE(mt8516_afe_o10_mix)), +}; + +static const struct snd_soc_dapm_route mt8516_memif_routes[] = { + /* downlink */ + {"I05", NULL, "DL1"}, + {"I06", NULL, "DL1"}, + {"I07", NULL, "DL2"}, + {"I08", NULL, "DL2"}, + {"O03", "I05 Switch", "I05"}, + {"O04", "I06 Switch", "I06"}, + {"O03", "I07 Switch", "I07"}, + {"O04", "I08 Switch", "I08"}, + + /* uplink */ + {"I03", NULL, "AIN Mux"}, + {"I04", NULL, "AIN Mux"}, + + {"O09", "I03 Switch", "I03"}, + {"O10", "I04 Switch", "I04"}, + {"VUL", NULL, "O09"}, + {"VUL", NULL, "O10"}, +}; + +static struct mtk_base_irq_data mt8516_irq_data[MT8516_AFE_IRQ_NUM] = { + [MT8516_AFE_IRQ_1] = { + .id = MT8516_AFE_IRQ_1, + .irq_cnt_reg = AFE_IRQ_CNT1, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 4, + .irq_fs_maskbit = 0xf, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 0, + .irq_clr_reg = AFE_IRQ_CLR, + .irq_clr_shift = 0, + }, + [MT8516_AFE_IRQ_2] = { + .id = MT8516_AFE_IRQ_2, + .irq_cnt_reg = AFE_IRQ_CNT2, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 8, + .irq_fs_maskbit = 0xf, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 1, + .irq_clr_reg = AFE_IRQ_CLR, + .irq_clr_shift = 1, + }, + [MT8516_AFE_IRQ_5] = { + .id = MT8516_AFE_IRQ_5, + .irq_cnt_reg = AFE_IRQ_CNT5, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = -1, + .irq_fs_shift = -1, + .irq_en_reg = AFE_IRQ_MCU_CON2, + .irq_en_shift = 3, + .irq_clr_reg = AFE_IRQ_CLR, + .irq_clr_shift = 4, + }, + [MT8516_AFE_IRQ_7] = { + .id = MT8516_AFE_IRQ_7, + .irq_cnt_reg = AFE_IRQ_CNT7, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON, + .irq_fs_shift = 24, + .irq_fs_maskbit = 0xf, + .irq_en_reg = AFE_IRQ_MCU_CON, + .irq_en_shift = 14, + .irq_clr_reg = AFE_IRQ_CLR, + .irq_clr_shift = 6, + }, + [MT8516_AFE_IRQ_10] = { + .id = MT8516_AFE_IRQ_10, + .irq_cnt_reg = AFE_IRQ_CNT10, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = -1, + .irq_fs_shift = -1, + .irq_en_reg = AFE_IRQ_MCU_CON2, + .irq_en_shift = 4, + .irq_clr_reg = AFE_IRQ_CLR, + .irq_clr_shift = 9, + }, + [MT8516_AFE_IRQ_13] = { + .id = MT8516_AFE_IRQ_13, + .irq_cnt_reg = AFE_IRQ_CNT13, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = -1, + .irq_fs_shift = -1, + .irq_en_reg = AFE_IRQ_MCU_CON2, + .irq_en_shift = 7, + .irq_clr_reg = AFE_IRQ_CLR, + .irq_clr_shift = 12, + }, +}; + +static struct mtk_base_afe_irq mt8516_irqs[MT8516_AFE_IRQ_NUM] = { + { .irq_data = &mt8516_irq_data[MT8516_AFE_IRQ_1] }, + { .irq_data = &mt8516_irq_data[MT8516_AFE_IRQ_2] }, + { .irq_data = &mt8516_irq_data[MT8516_AFE_IRQ_5] }, + { .irq_data = &mt8516_irq_data[MT8516_AFE_IRQ_7] }, + { .irq_data = &mt8516_irq_data[MT8516_AFE_IRQ_10] }, + { .irq_data = &mt8516_irq_data[MT8516_AFE_IRQ_13] }, +}; + +static struct mtk_base_memif_data mt8516_memif_data[MT8516_AFE_MEMIF_NUM] = { + [MT8516_AFE_MEMIF_DL1] = { + .name = "DL1", + .id = MT8516_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, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 1, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_DL2] = { + .name = "DL2", + .id = MT8516_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, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 2, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_VUL] = { + .name = "VUL", + .id = MT8516_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, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 3, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_DAI] = { + .name = "DAI", + .id = MT8516_AFE_MEMIF_DAI, + .reg_ofs_base = AFE_DAI_BASE, + .reg_ofs_cur = AFE_DAI_CUR, + .fs_reg = AFE_DAC_CON0, + .fs_shift = 24, + .fs_maskbit = 0x3, + .mono_reg = AFE_DAC_CON1, + .mono_shift = -1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 4, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_AWB] = { + .name = "AWB", + .id = MT8516_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, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 6, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_MOD_DAI] = { + .name = "MOD_DAI", + .id = MT8516_AFE_MEMIF_MOD_DAI, + .reg_ofs_base = AFE_MOD_PCM_BASE, + .reg_ofs_cur = AFE_MOD_PCM_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 30, + .fs_maskbit = 0x3, + .mono_reg = AFE_DAC_CON1, + .mono_shift = -1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = 7, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_HDMI] = { + .name = "HDMI", + .id = MT8516_AFE_MEMIF_HDMI, + .reg_ofs_base = AFE_HDMI_OUT_BASE, + .reg_ofs_cur = AFE_HDMI_OUT_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = -1, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = -1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = -1, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_TDM_IN] = { + .name = "TDM_IN", + .id = MT8516_AFE_MEMIF_TDM_IN, + .reg_ofs_base = AFE_HDMI_IN_2CH_BASE, + .reg_ofs_cur = AFE_HDMI_IN_2CH_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = -1, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = -1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = -1, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, + [MT8516_AFE_MEMIF_MULTILINE_IN] = { + .name = "ULM", + .id = MT8516_AFE_MEMIF_MULTILINE_IN, + .reg_ofs_base = SPDIFIN_BASE_ADR, + .reg_ofs_cur = SPDIFIN_CUR_ADR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = -1, + .fs_maskbit = 0xf, + .mono_reg = AFE_DAC_CON1, + .mono_shift = -1, + .enable_reg = AFE_DAC_CON0, + .enable_shift = -1, + .hd_shift = -1, + .msb_shift = -1, + .agent_disable_shift = -1, + }, +}; + +struct mtk_base_afe_memif mt8516_memif[] = { + [MT8516_AFE_MEMIF_DL1] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_DL1], + .irq_usage = MT8516_AFE_IRQ_1, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_DL2] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_DL2], + .irq_usage = MT8516_AFE_IRQ_7, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_VUL] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_VUL], + .irq_usage = MT8516_AFE_IRQ_2, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_DAI] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_DAI], + .irq_usage = MT8516_AFE_IRQ_2, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_AWB] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_AWB], + .irq_usage = MT8516_AFE_IRQ_2, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_MOD_DAI] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_MOD_DAI], + .irq_usage = MT8516_AFE_IRQ_2, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_HDMI] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_HDMI], + .irq_usage = MT8516_AFE_IRQ_5, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_TDM_IN] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_TDM_IN], + .irq_usage = MT8516_AFE_IRQ_10, + .const_irq = 1, + }, + [MT8516_AFE_MEMIF_MULTILINE_IN] = { + .data = &mt8516_memif_data[MT8516_AFE_MEMIF_MULTILINE_IN], + .data = &mt8516_memif_data[8], + .irq_usage = MT8516_AFE_IRQ_13, + .const_irq = 1, + }, +}; + +static const struct regmap_config mt8516_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ABB_AFE_SDM_TEST, + .cache_type = REGCACHE_NONE, +}; + +static irqreturn_t mt8516_afe_irq_handler(int irq, void *dev_id) +{ + struct mtk_base_afe *afe = dev_id; + unsigned int reg_value; + unsigned int memif_status; + int i, ret; + + ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, ®_value); + if (ret) { + reg_value = AFE_IRQ_STATUS_BITS; + goto exit_irq; + } + + ret = regmap_read(afe->regmap, AFE_DAC_CON0, &memif_status); + if (ret) { + reg_value = AFE_IRQ_STATUS_BITS; + goto exit_irq; + } + + for (i = 0; i < MT8516_AFE_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + struct snd_pcm_substream *substream = memif->substream; + unsigned int irq_clr_shift = + afe->irqs[memif->irq_usage].irq_data->irq_clr_shift; + unsigned int enable_shift = memif->data->enable_shift; + + if (!substream) + continue; + + if (!(reg_value & (1 << irq_clr_shift))) + continue; + + if (enable_shift >= 0 && !((1 << enable_shift) & memif_status)) + continue; + + snd_pcm_period_elapsed(substream); + } + +exit_irq: + regmap_write(afe->regmap, AFE_IRQ_CLR, reg_value & AFE_IRQ_STATUS_BITS); + + return IRQ_HANDLED; +} + +static struct snd_soc_dai_driver mt8516_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT8516_AFE_MEMIF_DL1, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .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_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mtk_afe_fe_ops, + }, { + .name = "DL2", + .id = MT8516_AFE_MEMIF_DL2, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .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_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mtk_afe_fe_ops, + }, { + .name = "VUL", + .id = MT8516_AFE_MEMIF_VUL, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .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_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mtk_afe_fe_ops, + }, { + .name = "DAI", + .id = MT8516_AFE_MEMIF_DAI, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .capture = { + .stream_name = "DAI", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &mtk_afe_fe_ops, + }, { + .name = "HDMI", + .id = MT8516_AFE_MEMIF_HDMI, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .playback = { + .stream_name = "HDMI", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mtk_afe_fe_ops, + }, { + .name = "TDM_IN", + .id = MT8516_AFE_MEMIF_TDM_IN, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .capture = { + .stream_name = "TDM_IN", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mtk_afe_fe_ops, + }, { + .name = "ULM", + .id = MT8516_AFE_MEMIF_MULTILINE_IN, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, + .capture = { + .stream_name = "MULTILINE_IN", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 + | SNDRV_PCM_RATE_44100 + | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 + | SNDRV_PCM_RATE_96000 + | SNDRV_PCM_RATE_176400 + | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S24_LE + | SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +static int mt8516_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 = mt8516_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt8516_memif_dai_driver); + + dai->dapm_widgets = mt8516_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt8516_memif_widgets); + dai->dapm_routes = mt8516_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt8516_memif_routes); + + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt8516_dai_memif_register, +}; + +static int mt8516_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +static const struct snd_soc_component_driver mt8516_afe_component = { + .name = AFE_PCM_NAME, + .ops = &mtk_afe_pcm_ops, + .pcm_new = mtk_afe_pcm_new, + .pcm_free = mtk_afe_pcm_free, + .probe = mt8516_afe_component_probe, +}; + +static int mt8516_afe_pcm_dev_probe(struct platform_device *pdev) +{ + int ret, i; + unsigned int irq_id; + struct mtk_base_afe *afe; + struct resource *res; + struct device_node *np = pdev->dev.of_node; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->dev = &pdev->dev; + + irq_id = platform_get_irq(pdev, 0); + if (!irq_id) { + dev_err(afe->dev, "np %s no irq\n", np->name); + return -ENXIO; + } + + ret = devm_request_irq(afe->dev, irq_id, mt8516_afe_irq_handler, + 0, "Afe_ISR_Handle", (void *)afe); + if (ret) { + dev_err(afe->dev, "could not request_irq\n"); + return ret; + } + + 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); + + afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, + &mt8516_afe_regmap_config); + if (IS_ERR(afe->regmap)) + return PTR_ERR(afe->regmap); + + afe->reg_back_up_list = &mt8516_afe_backup_list[0]; + afe->reg_back_up_list_num = ARRAY_SIZE(mt8516_afe_backup_list); + + /* 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, + "Failed to register dai register %d, 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, "Failed to combine sub-dais, ret %d\n", ret); + return ret; + } + + afe->mtk_afe_hardware = &mt8516_afe_hardware; + + afe->irqs = mt8516_irqs; + afe->irq_fs = mt8516_afe_irq_fs; + + afe->memif = &mt8516_memif[0]; + afe->memif_size = ARRAY_SIZE(mt8516_memif); + afe->memif_fs = mt8516_afe_i2s_fs; + + ret = devm_snd_soc_register_component(&pdev->dev, + &mt8516_afe_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) + return ret; + + return 0; +} + +static int mt8516_afe_pcm_dev_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id mt8516_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt8516-audio", }, + { } +}; +MODULE_DEVICE_TABLE(of, mt8516_afe_pcm_dt_match); + +static struct platform_driver mt8516_afe_pcm_driver = { + .driver = { + .name = "mtk-afe-pcm", + .of_match_table = mt8516_afe_pcm_dt_match, + }, + .probe = mt8516_afe_pcm_dev_probe, + .remove = mt8516_afe_pcm_dev_remove, +}; + +module_platform_driver(mt8516_afe_pcm_driver); + +MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Fabien Parent fparent@baylibre.com"); diff --git a/sound/soc/mediatek/mt8516/mt8516-afe-regs.h b/sound/soc/mediatek/mt8516/mt8516-afe-regs.h new file mode 100644 index 000000000000..0edb19cfecf4 --- /dev/null +++ b/sound/soc/mediatek/mt8516/mt8516-afe-regs.h @@ -0,0 +1,218 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS + * Copyright (c) 2019 MediaTek, Inc + * Author: Fabien Parent fparent@baylibre.com + */ + +#ifndef _MT8516_AFE_REGS_H_ +#define _MT8516_AFE_REGS_H_ + +#include <linux/bitops.h> + +#define AUDIO_TOP_CON0 0x0000 +#define AUDIO_TOP_CON1 0x0004 +#define AUDIO_TOP_CON3 0x000c +#define AFE_DAC_CON0 0x0010 +#define AFE_DAC_CON1 0x0014 +#define AFE_I2S_CON 0x0018 +#define AFE_I2S_CON1 0x0034 +#define AFE_I2S_CON2 0x0038 +#define AFE_I2S_CON3 0x004c +#define AFE_DAIBT_CON0 0x001c +#define AFE_MRGIF_CON 0x003c +#define AFE_CONN_24BIT 0x006c + +#define AFE_CONN0 0x0020 +#define AFE_CONN1 0x0024 +#define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002C +#define AFE_CONN4 0x0030 +#define AFE_CONN5 0x005C + +/* Memory interface */ +#define AFE_DL1_BASE 0x0040 +#define AFE_DL1_CUR 0x0044 +#define AFE_DL1_END 0x0048 +#define AFE_DL2_BASE 0x0050 +#define AFE_DL2_CUR 0x0054 +#define AFE_DL2_END 0x0058 +#define AFE_AWB_BASE 0x0070 +#define AFE_AWB_END 0x0078 +#define AFE_AWB_CUR 0x007c +#define AFE_VUL_BASE 0x0080 +#define AFE_VUL_CUR 0x008c +#define AFE_VUL_END 0x0088 +#define AFE_DAI_BASE 0x0090 +#define AFE_DAI_END 0x0098 +#define AFE_DAI_CUR 0x009c +#define AFE_MOD_PCM_BASE 0x0330 +#define AFE_MOD_PCM_END 0x0338 +#define AFE_MOD_PCM_CUR 0x033c +#define AFE_HDMI_OUT_BASE 0x0374 +#define AFE_HDMI_OUT_CUR 0x0378 +#define AFE_HDMI_OUT_END 0x037c + +#define AFE_MEMIF_MSB 0x00cc +#define AFE_MEMIF_MON0 0x00d0 +#define AFE_MEMIF_MON1 0x00d4 +#define AFE_MEMIF_MON2 0x00d8 +#define AFE_MEMIF_MON3 0x00dc + +#define AFE_ADDA_DL_SRC2_CON0 0x0108 +#define AFE_ADDA_DL_SRC2_CON1 0x010c +#define AFE_ADDA_UL_SRC_CON0 0x0114 +#define AFE_ADDA_UL_SRC_CON1 0x0118 +#define AFE_ADDA_TOP_CON0 0x0120 +#define AFE_ADDA_UL_DL_CON0 0x0124 +#define AFE_ADDA_NEWIF_CFG0 0x0138 +#define AFE_ADDA_NEWIF_CFG1 0x013c +#define AFE_ADDA_PREDIS_CON0 0x0260 +#define AFE_ADDA_PREDIS_CON1 0x0264 + +#define AFE_HDMI_OUT_CON0 0x0370 + +#define AFE_IRQ_MCU_CON 0x03a0 +#define AFE_IRQ_STATUS 0x03a4 +#define AFE_IRQ_CLR 0x03a8 +#define AFE_IRQ_CNT1 0x03ac +#define AFE_IRQ_CNT2 0x03b0 +#define AFE_IRQ_MCU_EN 0x03b4 +#define AFE_IRQ_CNT5 0x03bc +#define AFE_IRQ_CNT7 0x03dc +#define AFE_IRQ_CNT13 0x0408 +#define AFE_IRQ1_MCU_CNT_MON 0x03c0 +#define AFE_IRQ2_MCU_CNT_MON 0x03c4 +#define AFE_IRQ_MCU_CON2 0x03f8 + +#define AFE_MEMIF_PBUF_SIZE 0x03d8 +#define AFE_MEMIF_PBUF2_SIZE 0x03ec + +#define AFE_ASRC_CON0 0x0500 + +#define AFE_ASRC_CON13 0x0550 +#define AFE_ASRC_CON14 0x0554 +#define AFE_ASRC_CON15 0x0558 +#define AFE_ASRC_CON16 0x055c +#define AFE_ASRC_CON17 0x0560 +#define AFE_ASRC_CON18 0x0564 +#define AFE_ASRC_CON19 0x0568 +#define AFE_ASRC_CON20 0x056c +#define AFE_ASRC_CON21 0x0570 + +#define AFE_TDM_CON1 0x0548 +#define AFE_TDM_CON2 0x054c + +#define AFE_TDM_IN_CON1 0x0588 +#define AFE_TDM_IN_MON2 0x0594 +#define AFE_IRQ_CNT10 0x08dc + +#define AFE_HDMI_IN_2CH_CON0 0x09c0 +#define AFE_HDMI_IN_2CH_BASE 0x09c4 +#define AFE_HDMI_IN_2CH_END 0x09c8 +#define AFE_HDMI_IN_2CH_CUR 0x09cc + +#define AFE_MEMIF_MON15 0x0d7c +#define ABB_AFE_SDM_TEST 0x0f4c + +#define AFE_IRQ_STATUS_BITS 0x13ff + +/* AFE_I2S_CON (0x0018) */ +#define AFE_I2S_CON_PHASE_SHIFT_FIX BIT(31) +#define AFE_I2S_CON_BCK_INV BIT(29) +#define AFE_I2S_CON_FROM_IO_MUX BIT(28) +#define AFE_I2S_CON_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON_LRCK_INV BIT(5) +#define AFE_I2S_CON_FORMAT_I2S BIT(3) +#define AFE_I2S_CON_SRC_SLAVE BIT(2) +#define AFE_I2S_CON_WLEN_32BIT BIT(1) +#define AFE_I2S_CON_EN BIT(0) + +/* AFE_CONN1 (0x0024) */ +#define AFE_CONN1_I03_O03_S BIT(19) + +/* AFE_CONN2 (0x0028) */ +#define AFE_CONN2_I04_O04_S BIT(4) +#define AFE_CONN2_I03_O04_S BIT(3) + +/* AFE_I2S_CON1 (0x0034) */ +#define AFE_I2S_CON1_I2S2_TO_PAD (1 << 18) +#define AFE_I2S_CON1_TDMOUT_TO_PAD (0 << 18) +#define AFE_I2S_CON1_TDMOUT_MUX_MASK GENMASK(18, 18) +#define AFE_I2S_CON1_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON1_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON1_FORMAT_I2S BIT(3) +#define AFE_I2S_CON1_WLEN_32BIT BIT(1) +#define AFE_I2S_CON1_EN BIT(0) + +/* AFE_I2S_CON2 (0x0038) */ +#define AFE_I2S_CON2_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON2_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON2_FORMAT_I2S BIT(3) +#define AFE_I2S_CON2_WLEN_32BIT BIT(1) +#define AFE_I2S_CON2_EN BIT(0) + +/* AFE_I2S_CON3 (0x004C) */ +#define AFE_I2S_CON3_LOW_JITTER_CLK BIT(12) +#define AFE_I2S_CON3_RATE(x) (((x) & 0xf) << 8) +#define AFE_I2S_CON3_FORMAT_I2S BIT(3) +#define AFE_I2S_CON3_WLEN_32BIT BIT(1) +#define AFE_I2S_CON3_EN BIT(0) + +/* AFE_CONN_24BIT (0x006c) */ +#define AFE_CONN_24BIT_O10 BIT(10) +#define AFE_CONN_24BIT_O09 BIT(9) +#define AFE_CONN_24BIT_O06 BIT(6) +#define AFE_CONN_24BIT_O05 BIT(5) +#define AFE_CONN_24BIT_O04 BIT(4) +#define AFE_CONN_24BIT_O03 BIT(3) +#define AFE_CONN_24BIT_O02 BIT(2) +#define AFE_CONN_24BIT_O01 BIT(1) +#define AFE_CONN_24BIT_O00 BIT(0) + +/* AFE_ADDA_UL_SRC_CON0 */ +#define AFE_ADDA_UL_RATE_CH1_SHIFT 17 +#define AFE_ADDA_UL_RATE_CH1_MASK 0x3 +#define AFE_ADDA_UL_RATE_CH2_SHIFT 19 +#define AFE_ADDA_UL_RATE_CH2_MASK 0x3 + +/* AFE_ADDA_DL_SRC2_CON0 (0x0108) */ +#define AFE_ADDA_DL_8X_UPSAMPLE (BIT(25) | BIT(24)) +#define AFE_ADDA_DL_MUTE_OFF (BIT(12) | BIT(11)) +#define AFE_ADDA_DL_VOICE_DATA BIT(5) +#define AFE_ADDA_DL_DEGRADE_GAIN BIT(1) +#define AFE_ADDA_DL_RATE_SHIFT 28 + +/* AFE_ASRC_CON0 (0x0500) */ +#define AFE_ASRC_CON0_ASM_ON BIT(0) +#define AFE_ASRC_CON0_STR_CLR_MASK GENMASK(6, 4) +#define AFE_ASRC_CON0_CLR_TX (0x1 << 4) +#define AFE_ASRC_CON0_CLR_RX (0x2 << 4) +#define AFE_ASRC_CON0_CLR_I2S (0x4 << 4) + +/* AFE_ASRC_CON13 (0x0550) */ +#define AFE_ASRC_CON13_16BIT BIT(19) +#define AFE_ASRC_CON13_MONO BIT(16) + +/* AFE_ASRC_CON16 (0x055c) */ +#define AFE_ASRC_CON16_FC2_CYCLE_MASK GENMASK(31, 16) +#define AFE_ASRC_CON16_FC2_CYCLE(x) (((x) - 1) << 16) +#define AFE_ASRC_CON16_FC2_AUTO_RST BIT(14) +#define AFE_ASRC_CON16_TUNE_FREQ5 BIT(12) +#define AFE_ASRC_CON16_COMP_FREQ_EN BIT(11) +#define AFE_ASRC_CON16_FC2_SEL GENMASK(9, 8) +#define AFE_ASRC_CON16_FC2_I2S_IN (0x1 << 8) +#define AFE_ASRC_CON16_FC2_DGL_BYPASS BIT(7) +#define AFE_ASRC_CON16_FC2_AUTO_RESTART BIT(2) +#define AFE_ASRC_CON16_FC2_FREQ BIT(1) +#define AFE_ASRC_CON16_FC2_EN BIT(0) + +/* AFE_ADDA_NEWIF_CFG0 (0x0138) */ +#define AFE_ADDA_NEWIF_ADC_VOICE_MODE_SHIFT 10 +#define AFE_ADDA_NEWIF_ADC_VOICE_MODE_CLR (0x3 << 10) + +/* AFE_SPDIF_IN */ +#define SPDIFIN_BASE_ADR (0x0994) +#define SPDIFIN_CUR_ADR (0x09B8) + +#endif