[alsa-devel] [PATCH 0/7] ASoC: Mediatek: Add support for MT2701 SOC
This patch adds basic support for Mediatek AFE for MT2701 SoC. The patch is based on broonie tree "for-next" branch.
Change since RFC v2: add BT function refine Kconfig and Makefile add prefix 'mt8173' and 'mt2701' for relative drivers.
Garlic Tseng (7): ASoC: mediatek: Refine mt8173 driver and change config option ASoC: mediatek: add documents for mt2701 ASoC: mediatek: add clock and irq control for 2701 platform driver ASoC: mediatek: add mt2701 platform driver implementation. ASoC: bt-sco: extend rate and add a general compatible string ASoC: mediatek: add BT implementation ASoC: mediatek: Add mt2701-cs42448 driver and config option.
Documentation/devicetree/bindings/sound/bt-sco.txt | 2 +- .../devicetree/bindings/sound/mt2701-afe-pcm.txt | 150 ++ .../devicetree/bindings/sound/mt2701-cs42448.txt | 43 + sound/soc/codecs/bt-sco.c | 5 +- sound/soc/mediatek/Kconfig | 35 +- sound/soc/mediatek/Makefile | 9 +- sound/soc/mediatek/mt2701/Makefile | 20 + sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | 344 ++++ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h | 33 + sound/soc/mediatek/mt2701/mt2701-afe-common.h | 228 +++ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 1825 ++++++++++++++++++++ sound/soc/mediatek/mt2701/mt2701-cs42448.c | 412 +++++ sound/soc/mediatek/mt2701/mt2701-irq.c | 74 + sound/soc/mediatek/mt2701/mt2701-irq.h | 26 + sound/soc/mediatek/mt2701/mt2701-reg.h | 195 +++ sound/soc/mediatek/mt8173/Makefile | 7 + sound/soc/mediatek/mt8173/mt8173-afe-common.h | 101 ++ .../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} | 488 +++--- sound/soc/mediatek/{ => mt8173}/mt8173-max98090.c | 2 +- .../mediatek/{ => mt8173}/mt8173-rt5650-rt5514.c | 2 +- .../mediatek/{ => mt8173}/mt8173-rt5650-rt5676.c | 4 +- sound/soc/mediatek/{ => mt8173}/mt8173-rt5650.c | 2 +- sound/soc/mediatek/mtk-afe-common.h | 101 -- 23 files changed, 3740 insertions(+), 368 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt create mode 100644 Documentation/devicetree/bindings/sound/mt2701-cs42448.txt create mode 100644 sound/soc/mediatek/mt2701/Makefile create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-common.h create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c create mode 100644 sound/soc/mediatek/mt2701/mt2701-irq.c create mode 100644 sound/soc/mediatek/mt2701/mt2701-irq.h create mode 100644 sound/soc/mediatek/mt2701/mt2701-reg.h create mode 100644 sound/soc/mediatek/mt8173/Makefile create mode 100644 sound/soc/mediatek/mt8173/mt8173-afe-common.h rename sound/soc/mediatek/{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} (67%) rename sound/soc/mediatek/{ => mt8173}/mt8173-max98090.c (99%) rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650-rt5514.c (99%) rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650-rt5676.c (99%) rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650.c (99%) delete mode 100644 sound/soc/mediatek/mtk-afe-common.h
move mt8173 driver to another folder and add prefix. change config option from SND_SOC_MEDIATEK to SND_SOC_MT8173
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- sound/soc/mediatek/Kconfig | 14 +- sound/soc/mediatek/Makefile | 9 +- sound/soc/mediatek/mt8173/Makefile | 7 + sound/soc/mediatek/mt8173/mt8173-afe-common.h | 101 +++++ .../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} | 488 ++++++++++----------- sound/soc/mediatek/{ => mt8173}/mt8173-max98090.c | 2 +- .../mediatek/{ => mt8173}/mt8173-rt5650-rt5514.c | 2 +- .../mediatek/{ => mt8173}/mt8173-rt5650-rt5676.c | 4 +- sound/soc/mediatek/{ => mt8173}/mt8173-rt5650.c | 2 +- sound/soc/mediatek/mtk-afe-common.h | 101 ----- 10 files changed, 365 insertions(+), 365 deletions(-) create mode 100644 sound/soc/mediatek/mt8173/Makefile create mode 100644 sound/soc/mediatek/mt8173/mt8173-afe-common.h rename sound/soc/mediatek/{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} (67%) rename sound/soc/mediatek/{ => mt8173}/mt8173-max98090.c (99%) rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650-rt5514.c (99%) rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650-rt5676.c (99%) rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650.c (99%) delete mode 100644 sound/soc/mediatek/mtk-afe-common.h
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 3abf51c..ae9f664 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -1,15 +1,15 @@ -config SND_SOC_MEDIATEK - tristate "ASoC support for Mediatek chip" +config SND_SOC_MT8173 + tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK help - This adds ASoC platform driver support for Mediatek chip + This adds ASoC platform driver support for Mediatek MT8173 chip that can be used with other codecs. Select Y if you have such device. Ex: MT8173
config SND_SOC_MT8173_MAX98090 tristate "ASoC Audio driver for MT8173 with MAX98090 codec" - depends on SND_SOC_MEDIATEK && I2C + depends on SND_SOC_MT8173 && I2C select SND_SOC_MAX98090 help This adds ASoC driver for Mediatek MT8173 boards @@ -19,7 +19,7 @@ config SND_SOC_MT8173_MAX98090
config SND_SOC_MT8173_RT5650 tristate "ASoC Audio driver for MT8173 with RT5650 codec" - depends on SND_SOC_MEDIATEK && I2C + depends on SND_SOC_MT8173 && I2C select SND_SOC_RT5645 help This adds ASoC driver for Mediatek MT8173 boards @@ -29,7 +29,7 @@ config SND_SOC_MT8173_RT5650
config SND_SOC_MT8173_RT5650_RT5514 tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs" - depends on SND_SOC_MEDIATEK && I2C + depends on SND_SOC_MT8173 && I2C select SND_SOC_RT5645 select SND_SOC_RT5514 help @@ -40,7 +40,7 @@ config SND_SOC_MT8173_RT5650_RT5514
config SND_SOC_MT8173_RT5650_RT5676 tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" - depends on SND_SOC_MEDIATEK && I2C + depends on SND_SOC_MT8173 && I2C select SND_SOC_RT5645 select SND_SOC_RT5677 select SND_SOC_HDMI_CODEC diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index d486860..240dfc70 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -1,7 +1,2 @@ -# MTK Platform Support -obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o -# Machine support -obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o -obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o -obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o -obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o +# 8173 Machine support +obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ diff --git a/sound/soc/mediatek/mt8173/Makefile b/sound/soc/mediatek/mt8173/Makefile new file mode 100644 index 0000000..8158ef2 --- /dev/null +++ b/sound/soc/mediatek/mt8173/Makefile @@ -0,0 +1,7 @@ +# MTK Platform Support +obj-$(CONFIG_SND_SOC_MEDIATEK) += mt8173-afe-pcm.o +# Machine support +obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o +obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-common.h b/sound/soc/mediatek/mt8173/mt8173-afe-common.h new file mode 100644 index 0000000..8f2936d --- /dev/null +++ b/sound/soc/mediatek/mt8173/mt8173-afe-common.h @@ -0,0 +1,101 @@ +/* + * mt8173_afe_common.h -- Mediatek 8173 audio driver common definitions + * + * Copyright (c) 2015 MediaTek Inc. + * Author: Koro Chen koro.chen@mediatek.com + * Sascha Hauer s.hauer@pengutronix.de + * Hidalgo Huang hidalgo.huang@mediatek.com + * Ir Lian ir.lian@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT8173_AFE_COMMON_H_ +#define _MT8173_AFE_COMMON_H_ + +#include <linux/clk.h> +#include <linux/regmap.h> + +enum { + MT8173_AFE_MEMIF_DL1, + MT8173_AFE_MEMIF_DL2, + MT8173_AFE_MEMIF_VUL, + MT8173_AFE_MEMIF_DAI, + MT8173_AFE_MEMIF_AWB, + MT8173_AFE_MEMIF_MOD_DAI, + MT8173_AFE_MEMIF_HDMI, + MT8173_AFE_MEMIF_NUM, + MT8173_AFE_IO_MOD_PCM1 = MT8173_AFE_MEMIF_NUM, + MT8173_AFE_IO_MOD_PCM2, + MT8173_AFE_IO_PMIC, + MT8173_AFE_IO_I2S, + MT8173_AFE_IO_2ND_I2S, + MT8173_AFE_IO_HW_GAIN1, + MT8173_AFE_IO_HW_GAIN2, + MT8173_AFE_IO_MRG_O, + MT8173_AFE_IO_MRG_I, + MT8173_AFE_IO_DAIBT, + MT8173_AFE_IO_HDMI, +}; + +enum { + MT8173_AFE_IRQ_1, + MT8173_AFE_IRQ_2, + MT8173_AFE_IRQ_3, + MT8173_AFE_IRQ_4, + MT8173_AFE_IRQ_5, + MT8173_AFE_IRQ_6, + MT8173_AFE_IRQ_7, + MT8173_AFE_IRQ_8, + MT8173_AFE_IRQ_NUM, +}; + +enum { + MT8173_CLK_INFRASYS_AUD, + MT8173_CLK_TOP_PDN_AUD, + MT8173_CLK_TOP_PDN_AUD_BUS, + MT8173_CLK_I2S0_M, + MT8173_CLK_I2S1_M, + MT8173_CLK_I2S2_M, + MT8173_CLK_I2S3_M, + MT8173_CLK_I2S3_B, + MT8173_CLK_BCK0, + MT8173_CLK_BCK1, + MT8173_CLK_NUM +}; + +struct mt8173_afe; +struct snd_pcm_substream; + +struct mt8173_afe_memif_data { + int id; + const char *name; + int reg_ofs_base; + int reg_ofs_cur; + int fs_shift; + int mono_shift; + int enable_shift; + int irq_reg_cnt; + int irq_cnt_shift; + int irq_en_shift; + int irq_fs_shift; + int irq_clr_shift; + int msb_shift; +}; + +struct mt8173_afe_memif { + unsigned int phys_buf_addr; + int buffer_size; + struct snd_pcm_substream *substream; + const struct mt8173_afe_memif_data *data; + const struct mt8173_afe_irq_data *irqdata; +}; + +#endif diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c similarity index 67% rename from sound/soc/mediatek/mtk-afe-pcm.c rename to sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 2b5df2e..ba4739c 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1,5 +1,5 @@ /* - * Mediatek ALSA SoC AFE platform driver + * Mediatek 8173 ALSA SoC AFE platform driver * * Copyright (c) 2015 MediaTek Inc. * Author: Koro Chen koro.chen@mediatek.com @@ -24,7 +24,7 @@ #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <sound/soc.h> -#include "mtk-afe-common.h" +#include "mt8173-afe-common.h"
/***************************************************************************** * R E G I S T E R D E F I N I T I O N @@ -135,7 +135,7 @@ enum afe_tdm_ch_start { AFE_TDM_CH_ZERO, };
-static const unsigned int mtk_afe_backup_list[] = { +static const unsigned int mt8173_afe_backup_list[] = { AUDIO_TOP_CON0, AFE_CONN1, AFE_CONN2, @@ -152,18 +152,18 @@ static const unsigned int mtk_afe_backup_list[] = { AFE_DAC_CON0, };
-struct mtk_afe { +struct mt8173_afe { /* address for ioremap audio hardware register */ void __iomem *base_addr; struct device *dev; struct regmap *regmap; - struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; - struct clk *clocks[MTK_CLK_NUM]; - unsigned int backup_regs[ARRAY_SIZE(mtk_afe_backup_list)]; + struct mt8173_afe_memif memif[MT8173_AFE_MEMIF_NUM]; + struct clk *clocks[MT8173_CLK_NUM]; + unsigned int backup_regs[ARRAY_SIZE(mt8173_afe_backup_list)]; bool suspended; };
-static const struct snd_pcm_hardware mtk_afe_hardware = { +static const struct snd_pcm_hardware mt8173_afe_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), .buffer_bytes_max = 256 * 1024, @@ -174,12 +174,12 @@ static const struct snd_pcm_hardware mtk_afe_hardware = { .fifo_size = 0, };
-static snd_pcm_uframes_t mtk_afe_pcm_pointer +static snd_pcm_uframes_t mt8173_afe_pcm_pointer (struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; unsigned int hw_ptr; int ret;
@@ -193,40 +193,40 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer hw_ptr - memif->phys_buf_addr); }
-static const struct snd_pcm_ops mtk_afe_pcm_ops = { +static const struct snd_pcm_ops mt8173_afe_pcm_ops = { .ioctl = snd_pcm_lib_ioctl, - .pointer = mtk_afe_pcm_pointer, + .pointer = mt8173_afe_pcm_pointer, };
-static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) +static int mt8173_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) { size_t size; struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm;
- size = mtk_afe_hardware.buffer_bytes_max; + size = mt8173_afe_hardware.buffer_bytes_max;
return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, card->dev, size, size); }
-static void mtk_afe_pcm_free(struct snd_pcm *pcm) +static void mt8173_afe_pcm_free(struct snd_pcm *pcm) { snd_pcm_lib_preallocate_free_for_all(pcm); }
-static const struct snd_soc_platform_driver mtk_afe_pcm_platform = { - .ops = &mtk_afe_pcm_ops, - .pcm_new = mtk_afe_pcm_new, - .pcm_free = mtk_afe_pcm_free, +static const struct snd_soc_platform_driver mt8173_afe_pcm_platform = { + .ops = &mt8173_afe_pcm_ops, + .pcm_new = mt8173_afe_pcm_new, + .pcm_free = mt8173_afe_pcm_free, };
-struct mtk_afe_rate { +struct mt8173_afe_rate { unsigned int rate; unsigned int regvalue; };
-static const struct mtk_afe_rate mtk_afe_i2s_rates[] = { +static const struct mt8173_afe_rate mt8173_afe_i2s_rates[] = { { .rate = 8000, .regvalue = 0 }, { .rate = 11025, .regvalue = 1 }, { .rate = 12000, .regvalue = 2 }, @@ -242,21 +242,21 @@ static const struct mtk_afe_rate mtk_afe_i2s_rates[] = { { .rate = 192000, .regvalue = 14 }, };
-static int mtk_afe_i2s_fs(unsigned int sample_rate) +static int mt8173_afe_i2s_fs(unsigned int sample_rate) { int i;
- for (i = 0; i < ARRAY_SIZE(mtk_afe_i2s_rates); i++) - if (mtk_afe_i2s_rates[i].rate == sample_rate) - return mtk_afe_i2s_rates[i].regvalue; + for (i = 0; i < ARRAY_SIZE(mt8173_afe_i2s_rates); i++) + if (mt8173_afe_i2s_rates[i].rate == sample_rate) + return mt8173_afe_i2s_rates[i].regvalue;
return -EINVAL; }
-static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) +static int mt8173_afe_set_i2s(struct mt8173_afe *afe, unsigned int rate) { unsigned int val; - int fs = mtk_afe_i2s_fs(rate); + int fs = mt8173_afe_i2s_fs(rate);
if (fs < 0) return -EINVAL; @@ -281,7 +281,7 @@ static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) return 0; }
-static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) +static void mt8173_afe_set_i2s_enable(struct mt8173_afe *afe, bool enable) { unsigned int val;
@@ -296,8 +296,8 @@ static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable); }
-static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, - struct clk *m_ck, struct clk *b_ck) +static int mt8173_afe_dais_enable_clks(struct mt8173_afe *afe, + struct clk *m_ck, struct clk *b_ck) { int ret;
@@ -319,9 +319,9 @@ static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, return 0; }
-static int mtk_afe_dais_set_clks(struct mtk_afe *afe, - struct clk *m_ck, unsigned int mck_rate, - struct clk *b_ck, unsigned int bck_rate) +static int mt8173_afe_dais_set_clks(struct mt8173_afe *afe, + struct clk *m_ck, unsigned int mck_rate, + struct clk *b_ck, unsigned int bck_rate) { int ret;
@@ -343,8 +343,8 @@ static int mtk_afe_dais_set_clks(struct mtk_afe *afe, return 0; }
-static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, - struct clk *m_ck, struct clk *b_ck) +static void mt8173_afe_dais_disable_clks(struct mt8173_afe *afe, + struct clk *m_ck, struct clk *b_ck) { if (m_ck) clk_disable_unprepare(m_ck); @@ -352,102 +352,100 @@ static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, clk_disable_unprepare(b_ck); }
-static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
if (dai->active) return 0;
- mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); - mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); + mt8173_afe_dais_enable_clks(afe, afe->clocks[MT8173_CLK_I2S1_M], NULL); + mt8173_afe_dais_enable_clks(afe, afe->clocks[MT8173_CLK_I2S2_M], NULL); regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); return 0; }
-static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
if (dai->active) return;
- mtk_afe_set_i2s_enable(afe, false); + mt8173_afe_set_i2s_enable(afe, false); regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); - mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); - mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); + mt8173_afe_dais_disable_clks(afe, afe->clocks[MT8173_CLK_I2S1_M], NULL); + mt8173_afe_dais_disable_clks(afe, afe->clocks[MT8173_CLK_I2S2_M], NULL); }
-static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime * const runtime = substream->runtime; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); int ret;
- mtk_afe_dais_set_clks(afe, - afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256, - NULL, 0); - mtk_afe_dais_set_clks(afe, - afe->clocks[MTK_CLK_I2S2_M], runtime->rate * 256, - NULL, 0); + mt8173_afe_dais_set_clks(afe, afe->clocks[MT8173_CLK_I2S1_M], + runtime->rate * 256, NULL, 0); + mt8173_afe_dais_set_clks(afe, afe->clocks[MT8173_CLK_I2S2_M], + runtime->rate * 256, NULL, 0); /* config I2S */ - ret = mtk_afe_set_i2s(afe, substream->runtime->rate); + ret = mt8173_afe_set_i2s(afe, substream->runtime->rate); if (ret) return ret;
- mtk_afe_set_i2s_enable(afe, true); + mt8173_afe_set_i2s_enable(afe, true);
return 0; }
-static int mtk_afe_hdmi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
if (dai->active) return 0;
- mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], - afe->clocks[MTK_CLK_I2S3_B]); + mt8173_afe_dais_enable_clks(afe, afe->clocks[MT8173_CLK_I2S3_M], + afe->clocks[MT8173_CLK_I2S3_B]); return 0; }
-static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
if (dai->active) return;
- mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], - afe->clocks[MTK_CLK_I2S3_B]); + mt8173_afe_dais_disable_clks(afe, afe->clocks[MT8173_CLK_I2S3_M], + afe->clocks[MT8173_CLK_I2S3_B]); }
-static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime * const runtime = substream->runtime; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); unsigned int val;
- mtk_afe_dais_set_clks(afe, - afe->clocks[MTK_CLK_I2S3_M], runtime->rate * 128, - afe->clocks[MTK_CLK_I2S3_B], - runtime->rate * runtime->channels * 32); + mt8173_afe_dais_set_clks(afe, afe->clocks[MT8173_CLK_I2S3_M], + runtime->rate * 128, + afe->clocks[MT8173_CLK_I2S3_B], + runtime->rate * runtime->channels * 32);
val = AFE_TDM_CON1_BCK_INV | AFE_TDM_CON1_LRCK_INV | @@ -498,11 +496,11 @@ static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, return 0; }
-static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
@@ -544,18 +542,18 @@ static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, } }
-static int mtk_afe_dais_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int mt8173_afe_dais_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct snd_pcm_runtime *runtime = substream->runtime; - struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; int ret;
memif->substream = substream;
- snd_soc_set_runtime_hwparams(substream, &mtk_afe_hardware); + snd_soc_set_runtime_hwparams(substream, &mt8173_afe_hardware);
/* * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be @@ -567,7 +565,7 @@ static int mtk_afe_dais_startup(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS, 3, - mtk_afe_hardware.periods_max); + mt8173_afe_hardware.periods_max); if (ret < 0) { dev_err(afe->dev, "hw_constraint_minmax failed\n"); return ret; @@ -580,23 +578,23 @@ static int mtk_afe_dais_startup(struct snd_pcm_substream *substream, return ret; }
-static void mtk_afe_dais_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void mt8173_afe_dais_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
memif->substream = NULL; }
-static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int mt8173_afe_dais_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; int msb_at_bit33 = 0; int ret;
@@ -638,8 +636,8 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, /* set rate */ if (memif->data->fs_shift < 0) return 0; - if (memif->data->id == MTK_AFE_MEMIF_DAI || - memif->data->id == MTK_AFE_MEMIF_MOD_DAI) { + if (memif->data->id == MT8173_AFE_MEMIF_DAI || + memif->data->id == MT8173_AFE_MEMIF_MOD_DAI) { unsigned int val;
switch (params_rate(params)) { @@ -656,7 +654,7 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, return -EINVAL; }
- if (memif->data->id == MTK_AFE_MEMIF_DAI) + if (memif->data->id == MT8173_AFE_MEMIF_DAI) regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x3 << memif->data->fs_shift, val << memif->data->fs_shift); @@ -666,7 +664,7 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, val << memif->data->fs_shift);
} else { - int fs = mtk_afe_i2s_fs(params_rate(params)); + int fs = mt8173_afe_i2s_fs(params_rate(params));
if (fs < 0) return -EINVAL; @@ -679,19 +677,19 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, return 0; }
-static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int mt8173_afe_dais_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { return snd_pcm_lib_free_pages(substream); }
-static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int mt8173_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime * const runtime = substream->runtime; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; unsigned int counter = runtime->period_size;
dev_info(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); @@ -712,7 +710,7 @@ static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
/* set irq fs */ if (memif->data->irq_fs_shift >= 0) { - int fs = mtk_afe_i2s_fs(runtime->rate); + int fs = mt8173_afe_i2s_fs(runtime->rate);
if (fs < 0) return -EINVAL; @@ -747,76 +745,76 @@ static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, }
/* FE DAIs */ -static const struct snd_soc_dai_ops mtk_afe_dai_ops = { - .startup = mtk_afe_dais_startup, - .shutdown = mtk_afe_dais_shutdown, - .hw_params = mtk_afe_dais_hw_params, - .hw_free = mtk_afe_dais_hw_free, - .trigger = mtk_afe_dais_trigger, +static const struct snd_soc_dai_ops mt8173_afe_dai_ops = { + .startup = mt8173_afe_dais_startup, + .shutdown = mt8173_afe_dais_shutdown, + .hw_params = mt8173_afe_dais_hw_params, + .hw_free = mt8173_afe_dais_hw_free, + .trigger = mt8173_afe_dais_trigger, };
/* BE DAIs */ -static const struct snd_soc_dai_ops mtk_afe_i2s_ops = { - .startup = mtk_afe_i2s_startup, - .shutdown = mtk_afe_i2s_shutdown, - .prepare = mtk_afe_i2s_prepare, +static const struct snd_soc_dai_ops mt8173_afe_i2s_ops = { + .startup = mt8173_afe_i2s_startup, + .shutdown = mt8173_afe_i2s_shutdown, + .prepare = mt8173_afe_i2s_prepare, };
-static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = { - .startup = mtk_afe_hdmi_startup, - .shutdown = mtk_afe_hdmi_shutdown, - .prepare = mtk_afe_hdmi_prepare, - .trigger = mtk_afe_hdmi_trigger, +static const struct snd_soc_dai_ops mt8173_afe_hdmi_ops = { + .startup = mt8173_afe_hdmi_startup, + .shutdown = mt8173_afe_hdmi_shutdown, + .prepare = mt8173_afe_hdmi_prepare, + .trigger = mt8173_afe_hdmi_trigger,
};
-static int mtk_afe_runtime_suspend(struct device *dev); -static int mtk_afe_runtime_resume(struct device *dev); +static int mt8173_afe_runtime_suspend(struct device *dev); +static int mt8173_afe_runtime_resume(struct device *dev);
-static int mtk_afe_dai_suspend(struct snd_soc_dai *dai) +static int mt8173_afe_dai_suspend(struct snd_soc_dai *dai) { - struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8173_afe *afe = snd_soc_dai_get_drvdata(dai); int i;
dev_dbg(afe->dev, "%s\n", __func__); if (pm_runtime_status_suspended(afe->dev) || afe->suspended) return 0;
- for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) - regmap_read(afe->regmap, mtk_afe_backup_list[i], + for (i = 0; i < ARRAY_SIZE(mt8173_afe_backup_list); i++) + regmap_read(afe->regmap, mt8173_afe_backup_list[i], &afe->backup_regs[i]);
afe->suspended = true; - mtk_afe_runtime_suspend(afe->dev); + mt8173_afe_runtime_suspend(afe->dev); return 0; }
-static int mtk_afe_dai_resume(struct snd_soc_dai *dai) +static int mt8173_afe_dai_resume(struct snd_soc_dai *dai) { - struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8173_afe *afe = snd_soc_dai_get_drvdata(dai); int i = 0;
dev_dbg(afe->dev, "%s\n", __func__); if (pm_runtime_status_suspended(afe->dev) || !afe->suspended) return 0;
- mtk_afe_runtime_resume(afe->dev); + mt8173_afe_runtime_resume(afe->dev);
- for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) - regmap_write(afe->regmap, mtk_afe_backup_list[i], + for (i = 0; i < ARRAY_SIZE(mt8173_afe_backup_list); i++) + regmap_write(afe->regmap, mt8173_afe_backup_list[i], afe->backup_regs[i]);
afe->suspended = false; return 0; }
-static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { +static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = { /* FE DAIs: memory intefaces to CPU */ { .name = "DL1", /* downlink 1 */ - .id = MTK_AFE_MEMIF_DL1, - .suspend = mtk_afe_dai_suspend, - .resume = mtk_afe_dai_resume, + .id = MT8173_AFE_MEMIF_DL1, + .suspend = mt8173_afe_dai_suspend, + .resume = mt8173_afe_dai_resume, .playback = { .stream_name = "DL1", .channels_min = 1, @@ -824,12 +822,12 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &mtk_afe_dai_ops, + .ops = &mt8173_afe_dai_ops, }, { .name = "VUL", /* voice uplink */ - .id = MTK_AFE_MEMIF_VUL, - .suspend = mtk_afe_dai_suspend, - .resume = mtk_afe_dai_resume, + .id = MT8173_AFE_MEMIF_VUL, + .suspend = mt8173_afe_dai_suspend, + .resume = mt8173_afe_dai_resume, .capture = { .stream_name = "VUL", .channels_min = 1, @@ -837,11 +835,11 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &mtk_afe_dai_ops, + .ops = &mt8173_afe_dai_ops, }, { /* BE DAIs */ .name = "I2S", - .id = MTK_AFE_IO_I2S, + .id = MT8173_AFE_IO_I2S, .playback = { .stream_name = "I2S Playback", .channels_min = 1, @@ -856,18 +854,18 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &mtk_afe_i2s_ops, + .ops = &mt8173_afe_i2s_ops, .symmetric_rates = 1, }, };
-static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { +static struct snd_soc_dai_driver mt8173_afe_hdmi_dais[] = { /* FE DAIs */ { .name = "HDMI", - .id = MTK_AFE_MEMIF_HDMI, - .suspend = mtk_afe_dai_suspend, - .resume = mtk_afe_dai_resume, + .id = MT8173_AFE_MEMIF_HDMI, + .suspend = mt8173_afe_dai_suspend, + .resume = mt8173_afe_dai_resume, .playback = { .stream_name = "HDMI", .channels_min = 2, @@ -878,11 +876,11 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &mtk_afe_dai_ops, + .ops = &mt8173_afe_dai_ops, }, { /* BE DAIs */ .name = "HDMIO", - .id = MTK_AFE_IO_HDMI, + .id = MT8173_AFE_IO_HDMI, .playback = { .stream_name = "HDMIO Playback", .channels_min = 2, @@ -893,29 +891,29 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &mtk_afe_hdmi_ops, + .ops = &mt8173_afe_hdmi_ops, }, };
-static const struct snd_kcontrol_new mtk_afe_o03_mix[] = { +static const struct snd_kcontrol_new mt8173_afe_o03_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0), };
-static const struct snd_kcontrol_new mtk_afe_o04_mix[] = { +static const struct snd_kcontrol_new mt8173_afe_o04_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0), };
-static const struct snd_kcontrol_new mtk_afe_o09_mix[] = { +static const struct snd_kcontrol_new mt8173_afe_o09_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0), };
-static const struct snd_kcontrol_new mtk_afe_o10_mix[] = { +static const struct snd_kcontrol_new mt8173_afe_o10_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0), };
-static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { +static const struct snd_soc_dapm_widget mt8173_afe_pcm_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), @@ -925,16 +923,16 @@ static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, - mtk_afe_o03_mix, ARRAY_SIZE(mtk_afe_o03_mix)), + mt8173_afe_o03_mix, ARRAY_SIZE(mt8173_afe_o03_mix)), SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, - mtk_afe_o04_mix, ARRAY_SIZE(mtk_afe_o04_mix)), + mt8173_afe_o04_mix, ARRAY_SIZE(mt8173_afe_o04_mix)), SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, - mtk_afe_o09_mix, ARRAY_SIZE(mtk_afe_o09_mix)), + mt8173_afe_o09_mix, ARRAY_SIZE(mt8173_afe_o09_mix)), SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, - mtk_afe_o10_mix, ARRAY_SIZE(mtk_afe_o10_mix)), + mt8173_afe_o10_mix, ARRAY_SIZE(mt8173_afe_o10_mix)), };
-static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { +static const struct snd_soc_dapm_route mt8173_afe_pcm_routes[] = { {"I05", NULL, "DL1"}, {"I06", NULL, "DL1"}, {"I2S Playback", NULL, "O03"}, @@ -953,41 +951,41 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { { "O10", "I04 Switch", "I04" }, };
-static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = { +static const struct snd_soc_dapm_route mt8173_afe_hdmi_routes[] = { {"HDMIO Playback", NULL, "HDMI"}, };
-static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = { - .name = "mtk-afe-pcm-dai", - .dapm_widgets = mtk_afe_pcm_widgets, - .num_dapm_widgets = ARRAY_SIZE(mtk_afe_pcm_widgets), - .dapm_routes = mtk_afe_pcm_routes, - .num_dapm_routes = ARRAY_SIZE(mtk_afe_pcm_routes), +static const struct snd_soc_component_driver mt8173_afe_pcm_dai_component = { + .name = "mt8173-afe-pcm-dai", + .dapm_widgets = mt8173_afe_pcm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt8173_afe_pcm_widgets), + .dapm_routes = mt8173_afe_pcm_routes, + .num_dapm_routes = ARRAY_SIZE(mt8173_afe_pcm_routes), };
-static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = { - .name = "mtk-afe-hdmi-dai", - .dapm_routes = mtk_afe_hdmi_routes, - .num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes), +static const struct snd_soc_component_driver mt8173_afe_hdmi_dai_component = { + .name = "mt8173-afe-hdmi-dai", + .dapm_routes = mt8173_afe_hdmi_routes, + .num_dapm_routes = ARRAY_SIZE(mt8173_afe_hdmi_routes), };
-static const char *aud_clks[MTK_CLK_NUM] = { - [MTK_CLK_INFRASYS_AUD] = "infra_sys_audio_clk", - [MTK_CLK_TOP_PDN_AUD] = "top_pdn_audio", - [MTK_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus", - [MTK_CLK_I2S0_M] = "i2s0_m", - [MTK_CLK_I2S1_M] = "i2s1_m", - [MTK_CLK_I2S2_M] = "i2s2_m", - [MTK_CLK_I2S3_M] = "i2s3_m", - [MTK_CLK_I2S3_B] = "i2s3_b", - [MTK_CLK_BCK0] = "bck0", - [MTK_CLK_BCK1] = "bck1", +static const char *aud_clks[MT8173_CLK_NUM] = { + [MT8173_CLK_INFRASYS_AUD] = "infra_sys_audio_clk", + [MT8173_CLK_TOP_PDN_AUD] = "top_pdn_audio", + [MT8173_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus", + [MT8173_CLK_I2S0_M] = "i2s0_m", + [MT8173_CLK_I2S1_M] = "i2s1_m", + [MT8173_CLK_I2S2_M] = "i2s2_m", + [MT8173_CLK_I2S3_M] = "i2s3_m", + [MT8173_CLK_I2S3_B] = "i2s3_b", + [MT8173_CLK_BCK0] = "bck0", + [MT8173_CLK_BCK1] = "bck1", };
-static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { +static const struct mt8173_afe_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = { { .name = "DL1", - .id = MTK_AFE_MEMIF_DL1, + .id = MT8173_AFE_MEMIF_DL1, .reg_ofs_base = AFE_DL1_BASE, .reg_ofs_cur = AFE_DL1_CUR, .fs_shift = 0, @@ -1001,7 +999,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .msb_shift = 0, }, { .name = "DL2", - .id = MTK_AFE_MEMIF_DL2, + .id = MT8173_AFE_MEMIF_DL2, .reg_ofs_base = AFE_DL2_BASE, .reg_ofs_cur = AFE_DL2_CUR, .fs_shift = 4, @@ -1015,7 +1013,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .msb_shift = 1, }, { .name = "VUL", - .id = MTK_AFE_MEMIF_VUL, + .id = MT8173_AFE_MEMIF_VUL, .reg_ofs_base = AFE_VUL_BASE, .reg_ofs_cur = AFE_VUL_CUR, .fs_shift = 16, @@ -1029,7 +1027,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .msb_shift = 6, }, { .name = "DAI", - .id = MTK_AFE_MEMIF_DAI, + .id = MT8173_AFE_MEMIF_DAI, .reg_ofs_base = AFE_DAI_BASE, .reg_ofs_cur = AFE_DAI_CUR, .fs_shift = 24, @@ -1043,7 +1041,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .msb_shift = 5, }, { .name = "AWB", - .id = MTK_AFE_MEMIF_AWB, + .id = MT8173_AFE_MEMIF_AWB, .reg_ofs_base = AFE_AWB_BASE, .reg_ofs_cur = AFE_AWB_CUR, .fs_shift = 12, @@ -1057,7 +1055,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .msb_shift = 3, }, { .name = "MOD_DAI", - .id = MTK_AFE_MEMIF_MOD_DAI, + .id = MT8173_AFE_MEMIF_MOD_DAI, .reg_ofs_base = AFE_MOD_PCM_BASE, .reg_ofs_cur = AFE_MOD_PCM_CUR, .fs_shift = 30, @@ -1071,7 +1069,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { .msb_shift = 4, }, { .name = "HDMI", - .id = MTK_AFE_MEMIF_HDMI, + .id = MT8173_AFE_MEMIF_HDMI, .reg_ofs_base = AFE_HDMI_OUT_BASE, .reg_ofs_cur = AFE_HDMI_OUT_CUR, .fs_shift = -1, @@ -1086,7 +1084,7 @@ static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { }, };
-static const struct regmap_config mtk_afe_regmap_config = { +static const struct regmap_config mt8173_afe_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1094,9 +1092,9 @@ static const struct regmap_config mtk_afe_regmap_config = { .cache_type = REGCACHE_NONE, };
-static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) +static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id) { - struct mtk_afe *afe = dev_id; + struct mt8173_afe *afe = dev_id; unsigned int reg_value; int i, ret;
@@ -1107,8 +1105,8 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) goto err_irq; }
- for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) { - struct mtk_afe_memif *memif = &afe->memif[i]; + for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++) { + struct mt8173_afe_memif *memif = &afe->memif[i];
if (!(reg_value & (1 << memif->data->irq_clr_shift))) continue; @@ -1123,9 +1121,9 @@ err_irq: return IRQ_HANDLED; }
-static int mtk_afe_runtime_suspend(struct device *dev) +static int mt8173_afe_runtime_suspend(struct device *dev) { - struct mtk_afe *afe = dev_get_drvdata(dev); + struct mt8173_afe *afe = dev_get_drvdata(dev);
/* disable AFE */ regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); @@ -1134,36 +1132,36 @@ static int mtk_afe_runtime_suspend(struct device *dev) regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
- clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]); - clk_disable_unprepare(afe->clocks[MTK_CLK_BCK1]); - clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]); - clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); - clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_BCK0]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_BCK1]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_INFRASYS_AUD]); return 0; }
-static int mtk_afe_runtime_resume(struct device *dev) +static int mt8173_afe_runtime_resume(struct device *dev) { - struct mtk_afe *afe = dev_get_drvdata(dev); + struct mt8173_afe *afe = dev_get_drvdata(dev); int ret;
- ret = clk_prepare_enable(afe->clocks[MTK_CLK_INFRASYS_AUD]); + ret = clk_prepare_enable(afe->clocks[MT8173_CLK_INFRASYS_AUD]); if (ret) return ret;
- ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); + ret = clk_prepare_enable(afe->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]); if (ret) goto err_infra;
- ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD]); + ret = clk_prepare_enable(afe->clocks[MT8173_CLK_TOP_PDN_AUD]); if (ret) goto err_top_aud_bus;
- ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK0]); + ret = clk_prepare_enable(afe->clocks[MT8173_CLK_BCK0]); if (ret) goto err_top_aud;
- ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK1]); + ret = clk_prepare_enable(afe->clocks[MT8173_CLK_BCK1]); if (ret) goto err_bck0;
@@ -1182,17 +1180,17 @@ static int mtk_afe_runtime_resume(struct device *dev) return 0;
err_bck0: - clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_BCK0]); err_top_aud: - clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD]); err_top_aud_bus: - clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]); err_infra: - clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]); + clk_disable_unprepare(afe->clocks[MT8173_CLK_INFRASYS_AUD]); return ret; }
-static int mtk_afe_init_audio_clk(struct mtk_afe *afe) +static int mt8173_afe_init_audio_clk(struct mt8173_afe *afe) { size_t i;
@@ -1204,16 +1202,16 @@ static int mtk_afe_init_audio_clk(struct mtk_afe *afe) return PTR_ERR(afe->clocks[i]); } } - clk_set_rate(afe->clocks[MTK_CLK_BCK0], 22579200); /* 22M */ - clk_set_rate(afe->clocks[MTK_CLK_BCK1], 24576000); /* 24M */ + clk_set_rate(afe->clocks[MT8173_CLK_BCK0], 22579200); /* 22M */ + clk_set_rate(afe->clocks[MT8173_CLK_BCK1], 24576000); /* 24M */ return 0; }
-static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) +static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) { int ret, i; unsigned int irq_id; - struct mtk_afe *afe; + struct mt8173_afe *afe; struct resource *res;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); @@ -1231,7 +1229,7 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name); return -ENXIO; } - ret = devm_request_irq(afe->dev, irq_id, mtk_afe_irq_handler, + ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, 0, "Afe_ISR_Handle", (void *)afe); if (ret) { dev_err(afe->dev, "could not request_irq\n"); @@ -1244,48 +1242,48 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) return PTR_ERR(afe->base_addr);
afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, - &mtk_afe_regmap_config); + &mt8173_afe_regmap_config); if (IS_ERR(afe->regmap)) return PTR_ERR(afe->regmap);
/* initial audio related clock */ - ret = mtk_afe_init_audio_clk(afe); + ret = mt8173_afe_init_audio_clk(afe); if (ret) { - dev_err(afe->dev, "mtk_afe_init_audio_clk fail\n"); + dev_err(afe->dev, "mt8173_afe_init_audio_clk fail\n"); return ret; }
- for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) + for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++) afe->memif[i].data = &memif_data[i];
platform_set_drvdata(pdev, afe);
pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { - ret = mtk_afe_runtime_resume(&pdev->dev); + ret = mt8173_afe_runtime_resume(&pdev->dev); if (ret) goto err_pm_disable; }
- ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform); + ret = snd_soc_register_platform(&pdev->dev, &mt8173_afe_pcm_platform); if (ret) goto err_pm_disable;
ret = snd_soc_register_component(&pdev->dev, - &mtk_afe_pcm_dai_component, - mtk_afe_pcm_dais, - ARRAY_SIZE(mtk_afe_pcm_dais)); + &mt8173_afe_pcm_dai_component, + mt8173_afe_pcm_dais, + ARRAY_SIZE(mt8173_afe_pcm_dais)); if (ret) goto err_platform;
ret = snd_soc_register_component(&pdev->dev, - &mtk_afe_hdmi_dai_component, - mtk_afe_hdmi_dais, - ARRAY_SIZE(mtk_afe_hdmi_dais)); + &mt8173_afe_hdmi_dai_component, + mt8173_afe_hdmi_dais, + ARRAY_SIZE(mt8173_afe_hdmi_dais)); if (ret) goto err_comp;
- dev_info(&pdev->dev, "MTK AFE driver initialized.\n"); + dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n"); return 0;
err_comp: @@ -1297,38 +1295,38 @@ err_pm_disable: return ret; }
-static int mtk_afe_pcm_dev_remove(struct platform_device *pdev) +static int mt8173_afe_pcm_dev_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) - mtk_afe_runtime_suspend(&pdev->dev); + mt8173_afe_runtime_suspend(&pdev->dev); snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); return 0; }
-static const struct of_device_id mtk_afe_pcm_dt_match[] = { +static const struct of_device_id mt8173_afe_pcm_dt_match[] = { { .compatible = "mediatek,mt8173-afe-pcm", }, { } }; -MODULE_DEVICE_TABLE(of, mtk_afe_pcm_dt_match); +MODULE_DEVICE_TABLE(of, mt8173_afe_pcm_dt_match);
-static const struct dev_pm_ops mtk_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mtk_afe_runtime_suspend, mtk_afe_runtime_resume, - NULL) +static const struct dev_pm_ops mt8173_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt8173_afe_runtime_suspend, + mt8173_afe_runtime_resume, NULL) };
-static struct platform_driver mtk_afe_pcm_driver = { +static struct platform_driver mt8173_afe_pcm_driver = { .driver = { - .name = "mtk-afe-pcm", - .of_match_table = mtk_afe_pcm_dt_match, - .pm = &mtk_afe_pm_ops, + .name = "mt8173-afe-pcm", + .of_match_table = mt8173_afe_pcm_dt_match, + .pm = &mt8173_afe_pm_ops, }, - .probe = mtk_afe_pcm_dev_probe, - .remove = mtk_afe_pcm_dev_remove, + .probe = mt8173_afe_pcm_dev_probe, + .remove = mt8173_afe_pcm_dev_remove, };
-module_platform_driver(mtk_afe_pcm_driver); +module_platform_driver(mt8173_afe_pcm_driver);
MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver"); MODULE_AUTHOR("Koro Chen koro.chen@mediatek.com"); diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c similarity index 99% rename from sound/soc/mediatek/mt8173-max98090.c rename to sound/soc/mediatek/mt8173/mt8173-max98090.c index 71a1a35..5524a2c 100644 --- a/sound/soc/mediatek/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -18,7 +18,7 @@ #include <sound/soc.h> #include <sound/jack.h> #include <linux/gpio.h> -#include "../codecs/max98090.h" +#include "../../codecs/max98090.h"
static struct snd_soc_jack mt8173_max98090_jack;
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c similarity index 99% rename from sound/soc/mediatek/mt8173-rt5650-rt5514.c rename to sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 58e0836..467f704 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -19,7 +19,7 @@ #include <linux/of_gpio.h> #include <sound/soc.h> #include <sound/jack.h> -#include "../codecs/rt5645.h" +#include "../../codecs/rt5645.h"
#define MCLK_FOR_CODECS 12288000
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c similarity index 99% rename from sound/soc/mediatek/mt8173-rt5650-rt5676.c rename to sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index bb59392..1b8b2a7 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -19,8 +19,8 @@ #include <linux/of_gpio.h> #include <sound/soc.h> #include <sound/jack.h> -#include "../codecs/rt5645.h" -#include "../codecs/rt5677.h" +#include "../../codecs/rt5645.h" +#include "../../codecs/rt5677.h"
#define MCLK_FOR_CODECS 12288000
diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c similarity index 99% rename from sound/soc/mediatek/mt8173-rt5650.c rename to sound/soc/mediatek/mt8173/mt8173-rt5650.c index a27a667..400dabf 100644 --- a/sound/soc/mediatek/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -19,7 +19,7 @@ #include <linux/of_gpio.h> #include <sound/soc.h> #include <sound/jack.h> -#include "../codecs/rt5645.h" +#include "../../codecs/rt5645.h"
#define MCLK_FOR_CODECS 12288000
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h deleted file mode 100644 index f341f62..0000000 --- a/sound/soc/mediatek/mtk-afe-common.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * mtk_afe_common.h -- Mediatek audio driver common definitions - * - * Copyright (c) 2015 MediaTek Inc. - * Author: Koro Chen koro.chen@mediatek.com - * Sascha Hauer s.hauer@pengutronix.de - * Hidalgo Huang hidalgo.huang@mediatek.com - * Ir Lian ir.lian@mediatek.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MTK_AFE_COMMON_H_ -#define _MTK_AFE_COMMON_H_ - -#include <linux/clk.h> -#include <linux/regmap.h> - -enum { - MTK_AFE_MEMIF_DL1, - MTK_AFE_MEMIF_DL2, - MTK_AFE_MEMIF_VUL, - MTK_AFE_MEMIF_DAI, - MTK_AFE_MEMIF_AWB, - MTK_AFE_MEMIF_MOD_DAI, - MTK_AFE_MEMIF_HDMI, - MTK_AFE_MEMIF_NUM, - MTK_AFE_IO_MOD_PCM1 = MTK_AFE_MEMIF_NUM, - MTK_AFE_IO_MOD_PCM2, - MTK_AFE_IO_PMIC, - MTK_AFE_IO_I2S, - MTK_AFE_IO_2ND_I2S, - MTK_AFE_IO_HW_GAIN1, - MTK_AFE_IO_HW_GAIN2, - MTK_AFE_IO_MRG_O, - MTK_AFE_IO_MRG_I, - MTK_AFE_IO_DAIBT, - MTK_AFE_IO_HDMI, -}; - -enum { - MTK_AFE_IRQ_1, - MTK_AFE_IRQ_2, - MTK_AFE_IRQ_3, - MTK_AFE_IRQ_4, - MTK_AFE_IRQ_5, - MTK_AFE_IRQ_6, - MTK_AFE_IRQ_7, - MTK_AFE_IRQ_8, - MTK_AFE_IRQ_NUM, -}; - -enum { - MTK_CLK_INFRASYS_AUD, - MTK_CLK_TOP_PDN_AUD, - MTK_CLK_TOP_PDN_AUD_BUS, - MTK_CLK_I2S0_M, - MTK_CLK_I2S1_M, - MTK_CLK_I2S2_M, - MTK_CLK_I2S3_M, - MTK_CLK_I2S3_B, - MTK_CLK_BCK0, - MTK_CLK_BCK1, - MTK_CLK_NUM -}; - -struct mtk_afe; -struct snd_pcm_substream; - -struct mtk_afe_memif_data { - int id; - const char *name; - int reg_ofs_base; - int reg_ofs_cur; - int fs_shift; - int mono_shift; - int enable_shift; - int irq_reg_cnt; - int irq_cnt_shift; - int irq_en_shift; - int irq_fs_shift; - int irq_clr_shift; - int msb_shift; -}; - -struct mtk_afe_memif { - unsigned int phys_buf_addr; - int buffer_size; - struct snd_pcm_substream *substream; - const struct mtk_afe_memif_data *data; - const struct mtk_afe_irq_data *irqdata; -}; - -#endif
On Fri, Apr 29, 2016 at 09:00:42PM +0800, Garlic Tseng wrote:
.../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} | 488 ++++++++++-----------
So there's going to be no code sharing at all between this and any other Mediatek chips? That seems very surprising, it'd suggest that the hardware designers were creating a new design completely from scratch each time which doesn't seem all that likely. This is an unusual way of organizing things and we need a much clearer explanation of what's going on here.
On Wed, 2016-05-04 at 17:43 +0100, Mark Brown wrote:
On Fri, Apr 29, 2016 at 09:00:42PM +0800, Garlic Tseng wrote:
.../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} | 488 ++++++++++-----------
So there's going to be no code sharing at all between this and any other Mediatek chips? That seems very surprising, it'd suggest that the hardware designers were creating a new design completely from scratch each time which doesn't seem all that likely. This is an unusual way of organizing things and we need a much clearer explanation of what's going on here.
MT8173 and MT2701 are from different product lines so the register control sequences are very different. If another driver for 8173-like (or 2701-like) chip go upstream it shall share some common code with the relatively driver indeed. However I think MT8173 and MT2701 can't share the platform driver or a lot of "if MT8173 else MT2701" will mess up the code.
However, several (maybe 2 or 3) tiny functions for the two driver code are very similar indeed. For example, pointer callback functions of platform driver are very similar. It reads the cursor and return. But I'm not sure if it is better to share the function. It is too trivial for me.
On 05/05/16 04:45, Garlic Tseng wrote:
On Wed, 2016-05-04 at 17:43 +0100, Mark Brown wrote:
On Fri, Apr 29, 2016 at 09:00:42PM +0800, Garlic Tseng wrote:
.../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} | 488 ++++++++++-----------
So there's going to be no code sharing at all between this and any other Mediatek chips? That seems very surprising, it'd suggest that the hardware designers were creating a new design completely from scratch each time which doesn't seem all that likely. This is an unusual way of organizing things and we need a much clearer explanation of what's going on here.
MT8173 and MT2701 are from different product lines so the register control sequences are very different. If another driver for 8173-like (or 2701-like) chip go upstream it shall share some common code with the relatively driver indeed. However I think MT8173 and MT2701 can't share the platform driver or a lot of "if MT8173 else MT2701" will mess up the code.
What about the other SoCs we have some minimal support for: mt6589, mt8135, mt6592, mt6580, mt7323, mt8127?
A quick glance at the datasheets showed me, that mt6589 and at least mt8127 have quite similar register offsets. So I suppose there is some common code actually.
Regards, Matthias
On Thu, 2016-05-05 at 10:32 +0200, Matthias Brugger wrote:
On 05/05/16 04:45, Garlic Tseng wrote:
On Wed, 2016-05-04 at 17:43 +0100, Mark Brown wrote:
On Fri, Apr 29, 2016 at 09:00:42PM +0800, Garlic Tseng wrote:
.../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} | 488 ++++++++++-----------
So there's going to be no code sharing at all between this and any other Mediatek chips? That seems very surprising, it'd suggest that the hardware designers were creating a new design completely from scratch each time which doesn't seem all that likely. This is an unusual way of organizing things and we need a much clearer explanation of what's going on here.
MT8173 and MT2701 are from different product lines so the register control sequences are very different. If another driver for 8173-like (or 2701-like) chip go upstream it shall share some common code with the relatively driver indeed. However I think MT8173 and MT2701 can't share the platform driver or a lot of "if MT8173 else MT2701" will mess up the code.
What about the other SoCs we have some minimal support for: mt6589, mt8135, mt6592, mt6580, mt7323, mt8127?
A quick glance at the datasheets showed me, that mt6589 and at least mt8127 have quite similar register offsets. So I suppose there is some common code actually.
Well, the last ASoC driver only support mt8173, and we try to add the support for mt2701. As I mentioned, the ASoCs of the two chips have very different control sequence, so make the platform driver common will mess up the code. If there are some chips we want to support in the future and the ASoC part is similar with mt8173 (or mt2701), then it shall share some common code with the relative driver.
The ASoC hardwares has lots of differences between mt8173 and mt2701.
Mt8173 only support 2ch memory interface, whereas mt2701 has different hardware to support four memory interface, which can group together as a 8-ch memory interface, separate as four 2-ch memory interfaces, or function as one 4-ch memory interface and two 2-ch memory interfaces. That makes the control sequence different and the FE dais can't share.
Mt8173 only support 2ch i2s playback/capture separately, but mt2701 has different i2s hardware so that four i2s can sync together to preform 8ch playback/capture. Same as the memory interface, the i2s can separate as 2ch i2s and works simultaneously. The i2s hardware has a limitation that when i2s-in enable, i2s-out must be enable to function well. The i2s hardware is so different that we can't share BE-dai code.
The connection between FE and BE also differ between the two chips. Mt2701 has much more port then mt8173. However mt2701 can still fit in DAPM structure (just control a register bit to connect/disconnect two ports).
The irq and the clock are also different. Mt2701 support higher rate irq than mt8173; mt2701 has too many memory interface so it needs to dynamically request irq when needed; the clock structure also different between them.
As mentioned above, the difference of the ASoCs between the two chips are too large that we have a hard time sharing the driver code.
Regards, Matthias
On Thu, May 05, 2016 at 06:39:32PM +0800, Garlic Tseng wrote:
As mentioned above, the difference of the ASoCs between the two chips are too large that we have a hard time sharing the driver code.
The things you're describing all sound like scaling differences rather than fundamental changes. I'd expect to see at least some shared code here, we don't want to be just duplicating the entire driver every time there's a new hardware revision.
On Fri, 2016-05-06 at 13:20 +0100, Mark Brown wrote:
On Thu, May 05, 2016 at 06:39:32PM +0800, Garlic Tseng wrote:
As mentioned above, the difference of the ASoCs between the two chips are too large that we have a hard time sharing the driver code.
The things you're describing all sound like scaling differences rather than fundamental changes. I'd expect to see at least some shared code here, we don't want to be just duplicating the entire driver every time there's a new hardware revision.
Oh ok, I'll do it in the next version. Thanks for comment.
add mt2701-afe-pcm.txt and mt2701-cs42448.txt for mt2701
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- .../devicetree/bindings/sound/mt2701-afe-pcm.txt | 150 +++++++++++++++++++++ .../devicetree/bindings/sound/mt2701-cs42448.txt | 43 ++++++ 2 files changed, 193 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt create mode 100644 Documentation/devicetree/bindings/sound/mt2701-cs42448.txt
diff --git a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt new file mode 100644 index 0000000..3e623a7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt @@ -0,0 +1,150 @@ +Mediatek AFE PCM controller for mt2701 + +Required properties: +- compatible = "mediatek,mt2701-audio"; +- reg: register location and size +- interrupts: Should contain AFE interrupt +- clock-names: should have these clock names: + "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_mux1_div", + "top_audio_mux2_div", + "top_audio_48k_timing", + "top_audio_44k_timing", + "top_audpll_mux_sel", + "top_apll_sel", + "top_aud1_pll_98M", + "top_aud2_pll_90M", + "top_hadds2_pll_98M", + "top_hadds2_pll_294M", + "top_audpll", + "top_audpll_d4", + "top_audpll_d8", + "top_audpll_d16", + "top_audpll_d24", + "top_audintbus_sel", + "clk_26m", + "top_syspll1_d4", + "top_aud_k1_src_sel", + "top_aud_k2_src_sel", + "top_aud_k3_src_sel", + "top_aud_k4_src_sel", + "top_aud_k5_src_sel", + "top_aud_k6_src_sel", + "top_aud_k1_src_div", + "top_aud_k2_src_div", + "top_aud_k3_src_div", + "top_aud_k4_src_div", + "top_aud_k5_src_div", + "top_aud_k6_src_div", + "top_aud_i2s1_mclk", + "top_aud_i2s2_mclk", + "top_aud_i2s3_mclk", + "top_aud_i2s4_mclk", + "top_aud_i2s5_mclk", + "top_aud_i2s6_mclk", + "top_asm_m_sel", + "top_asm_h_sel", + "top_univpll2_d4", + "top_univpll2_d2", + "top_syspll_d5"; + +Example: + + afe: mt2701-afe-pcm@11220000 { + compatible = "mediatek,mt2701-audio"; + reg = <0 0x11220000 0 0x2000>, + <0 0x112A0000 0 0x20000>; + interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>, + <GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>; + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>, + <&topckgen CLK_TOP_AUD_48K_TIMING>, + <&topckgen CLK_TOP_AUD_44K_TIMING>, + <&topckgen CLK_TOP_AUDPLL_MUX_SEL>, + <&topckgen CLK_TOP_APLL_SEL>, + <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>, + <&topckgen CLK_TOP_HADDS2PLL_98M>, + <&topckgen CLK_TOP_HADDS2PLL_294M>, + <&topckgen CLK_TOP_AUDPLL>, + <&topckgen CLK_TOP_AUDPLL_D4>, + <&topckgen CLK_TOP_AUDPLL_D8>, + <&topckgen CLK_TOP_AUDPLL_D16>, + <&topckgen CLK_TOP_AUDPLL_D24>, + <&topckgen CLK_TOP_AUDINTBUS_SEL>, + <&clk26m>, + <&topckgen CLK_TOP_SYSPLL1_D4>, + <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K5_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K6_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K5_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K6_SRC_DIV>, + <&topckgen CLK_TOP_AUD_I2S1_MCLK>, + <&topckgen CLK_TOP_AUD_I2S2_MCLK>, + <&topckgen CLK_TOP_AUD_I2S3_MCLK>, + <&topckgen CLK_TOP_AUD_I2S4_MCLK>, + <&topckgen CLK_TOP_AUD_I2S5_MCLK>, + <&topckgen CLK_TOP_AUD_I2S6_MCLK>, + <&topckgen CLK_TOP_ASM_M_SEL>, + <&topckgen CLK_TOP_ASM_H_SEL>, + <&topckgen CLK_TOP_UNIVPLL2_D4>, + <&topckgen CLK_TOP_UNIVPLL2_D2>, + <&topckgen CLK_TOP_SYSPLL_D5>; + + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_mux1_div", + "top_audio_mux2_div", + "top_audio_48k_timing", + "top_audio_44k_timing", + "top_audpll_mux_sel", + "top_apll_sel", + "top_aud1_pll_98M", + "top_aud2_pll_90M", + "top_hadds2_pll_98M", + "top_hadds2_pll_294M", + "top_audpll", + "top_audpll_d4", + "top_audpll_d8", + "top_audpll_d16", + "top_audpll_d24", + "top_audintbus_sel", + "clk_26m", + "top_syspll1_d4", + "top_aud_k1_src_sel", + "top_aud_k2_src_sel", + "top_aud_k3_src_sel", + "top_aud_k4_src_sel", + "top_aud_k5_src_sel", + "top_aud_k6_src_sel", + "top_aud_k1_src_div", + "top_aud_k2_src_div", + "top_aud_k3_src_div", + "top_aud_k4_src_div", + "top_aud_k5_src_div", + "top_aud_k6_src_div", + "top_aud_i2s1_mclk", + "top_aud_i2s2_mclk", + "top_aud_i2s3_mclk", + "top_aud_i2s4_mclk", + "top_aud_i2s5_mclk", + "top_aud_i2s6_mclk", + "top_asm_m_sel", + "top_asm_h_sel", + "top_univpll2_d4", + "top_univpll2_d2", + "top_syspll_d5"; + }; diff --git a/Documentation/devicetree/bindings/sound/mt2701-cs42448.txt b/Documentation/devicetree/bindings/sound/mt2701-cs42448.txt new file mode 100644 index 0000000..5718169 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt2701-cs42448.txt @@ -0,0 +1,43 @@ +MT2701 with CS42448 CODEC + +Required properties: +- compatible: "mediatek,mt2701-cs42448-machin" +- mediatek,platform: the phandle of MT2701 ASoC platform +- audio-routing: a list of the connections between audio +- mediatek,audio-codec: the phandles of cs42448 codec +- mediatek,audio-codec-bt-mrg the phandles of bt-sco dummy codec +- pinctrl-names: Should contain only one value - "default" +- pinctrl-0: Should specify pin control groups used for this controller. +- i2s1-in-sel-gpio1, i2s1-in-sel-gpio2: Should specify two gpio pins to + control I2S1-in mux. + +Example: + + sound:sound { + compatible = "mediatek,mt2701-cs42448-machine"; + mediatek,platform = <&afe>; + /* CS42448 Machine name */ + audio-routing = + "Line Out Jack", "AOUT1L", + "Line Out Jack", "AOUT1R", + "Line Out Jack", "AOUT2L", + "Line Out Jack", "AOUT2R", + "Line Out Jack", "AOUT3L", + "Line Out Jack", "AOUT3R", + "Line Out Jack", "AOUT4L", + "Line Out Jack", "AOUT4R", + "AIN1L", "AMIC", + "AIN1R", "AMIC", + "AIN2L", "Tuner In", + "AIN2R", "Tuner In", + "AIN3L", "Satellite Tuner In", + "AIN3R", "Satellite Tuner In", + "AIN3L", "AUX In", + "AIN3R", "AUX In"; + mediatek,audio-codec = <&cs42448>; + mediatek,audio-codec-bt-mrg = <&bt_sco_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&aud_pins_default>; + i2s1-in-sel-gpio1 = <&pio 53 0>; + i2s1-in-sel-gpio2 = <&pio 54 0>; + };
Clock and irq controls for 2701 platform driver. To save irq resource, dynamic-allocated irq mechanism is implemented.
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | 344 ++++++++++++++++++++++ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h | 33 +++ sound/soc/mediatek/mt2701/mt2701-afe-common.h | 228 ++++++++++++++ sound/soc/mediatek/mt2701/mt2701-irq.c | 74 +++++ sound/soc/mediatek/mt2701/mt2701-irq.h | 26 ++ sound/soc/mediatek/mt2701/mt2701-reg.h | 195 ++++++++++++ 6 files changed, 900 insertions(+) create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-common.h create mode 100644 sound/soc/mediatek/mt2701/mt2701-irq.c create mode 100644 sound/soc/mediatek/mt2701/mt2701-irq.h create mode 100644 sound/soc/mediatek/mt2701/mt2701-reg.h
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c new file mode 100644 index 0000000..0fe29cd --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c @@ -0,0 +1,344 @@ +/* + * mt2701-afe-clock-ctrl.c -- Mediatek 2701 afe clock ctrl + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <sound/soc.h> +#include <linux/regmap.h> +#include <linux/pm_runtime.h> + +#include "mt2701-afe-common.h" +#include "mt2701-afe-clock-ctrl.h" + +static const char *aud_clks[MT2701_CLOCK_NUM] = { + [MT2701_AUD_INFRA_SYS_AUDIO] = "infra_sys_audio_clk", + [MT2701_AUD_TOP_AUD_MUX1_SEL] = "top_audio_mux1_sel", + [MT2701_AUD_TOP_AUD_MUX2_SEL] = "top_audio_mux2_sel", + [MT2701_AUD_TOP_AUD_MUX1_DIV] = "top_audio_mux1_div", + [MT2701_AUD_TOP_AUD_MUX2_DIV] = "top_audio_mux2_div", + [MT2701_AUD_TOP_AUD_48K_TIMING] = "top_audio_48k_timing", + [MT2701_AUD_TOP_AUD_44K_TIMING] = "top_audio_44k_timing", + [MT2701_AUD_TOP_AUDPLL_MUX_SEL] = "top_audpll_mux_sel", + [MT2701_AUD_TOP_APLL_SEL] = "top_apll_sel", + [MT2701_AUD_TOP_AUD1PLL_98M] = "top_aud1_pll_98M", + [MT2701_AUD_TOP_AUD2PLL_90M] = "top_aud2_pll_90M", + [MT2701_AUD_TOP_HADDS2PLL_98M] = "top_hadds2_pll_98M", + [MT2701_AUD_TOP_HADDS2PLL_294M] = "top_hadds2_pll_294M", + [MT2701_AUD_TOP_AUDPLL] = "top_audpll", + [MT2701_AUD_TOP_AUDPLL_D4] = "top_audpll_d4", + [MT2701_AUD_TOP_AUDPLL_D8] = "top_audpll_d8", + [MT2701_AUD_TOP_AUDPLL_D16] = "top_audpll_d16", + [MT2701_AUD_TOP_AUDPLL_D24] = "top_audpll_d24", + [MT2701_AUD_TOP_AUDINTBUS] = "top_audintbus_sel", + [MT2701_AUD_CLK_26M] = "clk_26m", + [MT2701_AUD_TOP_SYSPLL1_D4] = "top_syspll1_d4", + [MT2701_AUD_TOP_AUD_K1_SRC_SEL] = "top_aud_k1_src_sel", + [MT2701_AUD_TOP_AUD_K2_SRC_SEL] = "top_aud_k2_src_sel", + [MT2701_AUD_TOP_AUD_K3_SRC_SEL] = "top_aud_k3_src_sel", + [MT2701_AUD_TOP_AUD_K4_SRC_SEL] = "top_aud_k4_src_sel", + [MT2701_AUD_TOP_AUD_K5_SRC_SEL] = "top_aud_k5_src_sel", + [MT2701_AUD_TOP_AUD_K6_SRC_SEL] = "top_aud_k6_src_sel", + [MT2701_AUD_TOP_AUD_K1_SRC_DIV] = "top_aud_k1_src_div", + [MT2701_AUD_TOP_AUD_K2_SRC_DIV] = "top_aud_k2_src_div", + [MT2701_AUD_TOP_AUD_K3_SRC_DIV] = "top_aud_k3_src_div", + [MT2701_AUD_TOP_AUD_K4_SRC_DIV] = "top_aud_k4_src_div", + [MT2701_AUD_TOP_AUD_K5_SRC_DIV] = "top_aud_k5_src_div", + [MT2701_AUD_TOP_AUD_K6_SRC_DIV] = "top_aud_k6_src_div", + [MT2701_AUD_TOP_AUD_I2S1_MCLK] = "top_aud_i2s1_mclk", + [MT2701_AUD_TOP_AUD_I2S2_MCLK] = "top_aud_i2s2_mclk", + [MT2701_AUD_TOP_AUD_I2S3_MCLK] = "top_aud_i2s3_mclk", + [MT2701_AUD_TOP_AUD_I2S4_MCLK] = "top_aud_i2s4_mclk", + [MT2701_AUD_TOP_AUD_I2S5_MCLK] = "top_aud_i2s5_mclk", + [MT2701_AUD_TOP_AUD_I2S6_MCLK] = "top_aud_i2s6_mclk", + [MT2701_AUD_TOP_ASM_M_SEL] = "top_asm_m_sel", + [MT2701_AUD_TOP_ASM_H_SEL] = "top_asm_h_sel", + [MT2701_AUD_TOP_UNIVPLL2_D4] = "top_univpll2_d4", + [MT2701_AUD_TOP_UNIVPLL2_D2] = "top_univpll2_d2", + [MT2701_AUD_TOP_SYSPLL_D5] = "top_syspll_d5", +}; + +void mt2701_init_clock(struct mt2701_afe *afe) +{ + int i = 0; + + for (i = 0; i < MT2701_CLOCK_NUM; i++) { + afe->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(aud_clks[i])) + dev_warn(afe->dev, "%s devm_clk_get %s fail\n", + __func__, aud_clks[i]); + } +} + +void mt2701_afe_enable_clock(struct mt2701_afe *afe, int en) +{ + if (en) { + mt2701_turn_on_a1sys_clock(afe); + mt2701_turn_on_a2sys_clock(afe); + mt2701_turn_on_afe_clock(afe); + regmap_update_bits(afe->regmap, ASYS_TOP_CON, + AUDIO_TOP_CON0_A1SYS_A2SYS_ON, + AUDIO_TOP_CON0_A1SYS_A2SYS_ON); + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + AFE_DAC_CON0_AFE_ON, AFE_DAC_CON0_AFE_ON); + regmap_write(afe->regmap, PWR2_TOP_CON, PWR2_TOP_CON_INIT_VAL); + regmap_write(afe->regmap, PWR1_ASM_CON1, + PWR1_ASM_CON1_INIT_VAL); + regmap_write(afe->regmap, PWR2_ASM_CON1, + PWR2_ASM_CON1_INIT_VAL); + } else { + mt2701_turn_off_afe_clock(afe); + mt2701_turn_off_a1sys_clock(afe); + mt2701_turn_off_a2sys_clock(afe); + regmap_update_bits(afe->regmap, ASYS_TOP_CON, + AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0); + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + AFE_DAC_CON0_AFE_ON, 0); + } +} + +void mt2701_turn_on_a1sys_clock(struct mt2701_afe *afe) +{ + int ret = 0; + + /* Set Mux */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUD_MUX1_SEL]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[MT2701_AUD_TOP_AUD_MUX1_SEL], ret); + + ret = clk_set_parent(afe->clocks[MT2701_AUD_TOP_AUD_MUX1_SEL], + afe->clocks[MT2701_AUD_TOP_AUD1PLL_98M]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX1_SEL], + aud_clks[MT2701_AUD_TOP_AUD1PLL_98M], ret); + + /* Set Divider */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUD_MUX1_DIV]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX1_DIV], + ret); + ret = clk_set_rate(afe->clocks[MT2701_AUD_TOP_AUD_MUX1_DIV], + MT2701_AUD_TOP_AUD_MUX1_DIV_RATE); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX1_DIV], + MT2701_AUD_TOP_AUD_MUX1_DIV_RATE, ret); + + /* Enable clock gate */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUD_48K_TIMING]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[MT2701_AUD_TOP_AUD_48K_TIMING], ret); + /* Enable infra audio */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); +} + +void mt2701_turn_off_a1sys_clock(struct mt2701_afe *afe) +{ + clk_disable_unprepare(afe->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUD_48K_TIMING]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUD_MUX1_DIV]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUD_MUX1_SEL]); +} + +void mt2701_turn_on_a2sys_clock(struct mt2701_afe *afe) +{ + int ret = 0; + + /* Set Mux */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUD_MUX2_SEL]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX2_SEL], + ret); + ret = clk_set_parent(afe->clocks[MT2701_AUD_TOP_AUD_MUX2_SEL], + afe->clocks[MT2701_AUD_TOP_AUD2PLL_90M]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX2_SEL], + aud_clks[MT2701_AUD_TOP_AUD2PLL_90M], ret); + /* Set Divider */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUD_MUX2_DIV]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX2_DIV], + ret); + ret = clk_set_rate(afe->clocks[MT2701_AUD_TOP_AUD_MUX2_DIV], + MT2701_AUD_TOP_AUD_MUX2_DIV_RATE); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_AUD_MUX2_DIV], + MT2701_AUD_TOP_AUD_MUX2_DIV_RATE, ret); + + /* Enable clock gate */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUD_44K_TIMING]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[MT2701_AUD_TOP_AUD_44K_TIMING], ret); + /* Enable infra audio */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); +} + +void mt2701_turn_off_a2sys_clock(struct mt2701_afe *afe) +{ + clk_disable_unprepare(afe->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUD_44K_TIMING]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUD_MUX2_DIV]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUD_MUX2_SEL]); +} + +void mt2701_turn_on_afe_clock(struct mt2701_afe *afe) +{ + int ret; + + /*MT_CG_INFRA_AUDIO, INFRA_PDN_STA[5]*/ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); + + /* Set MT2701_AUD_TOP_AUDINTBUS to MT2701_AUD_TOP_SYSPLL1_D4 */ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_AUDINTBUS]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, + aud_clks[MT2701_AUD_TOP_AUDINTBUS], ret); + + ret = clk_set_parent(afe->clocks[MT2701_AUD_TOP_AUDINTBUS], + afe->clocks[MT2701_AUD_TOP_SYSPLL1_D4]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_AUDINTBUS], + aud_clks[MT2701_AUD_TOP_SYSPLL1_D4], ret); + + /* Set MT2701_AUD_TOP_ASM_H_SEL to MT2701_AUD_TOP_UNIVPLL2_D2*/ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_ASM_H_SEL]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, + aud_clks[MT2701_AUD_TOP_ASM_H_SEL], ret); + + ret = clk_set_parent(afe->clocks[MT2701_AUD_TOP_ASM_H_SEL], + afe->clocks[MT2701_AUD_TOP_UNIVPLL2_D2]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_ASM_H_SEL], + aud_clks[MT2701_AUD_TOP_UNIVPLL2_D2], ret); + + /* Set MT2701_AUD_TOP_ASM_M_SEL to MT2701_AUD_TOP_UNIVPLL2_D4*/ + ret = clk_prepare_enable(afe->clocks[MT2701_AUD_TOP_ASM_M_SEL]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, + aud_clks[MT2701_AUD_TOP_ASM_M_SEL], ret); + + ret = clk_set_parent(afe->clocks[MT2701_AUD_TOP_ASM_M_SEL], + afe->clocks[MT2701_AUD_TOP_UNIVPLL2_D4]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, + aud_clks[MT2701_AUD_TOP_ASM_M_SEL], + aud_clks[MT2701_AUD_TOP_UNIVPLL2_D4], ret); + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUDIO_TOP_CON0_PDN_AFE, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUDIO_TOP_CON0_PDN_APLL_CK, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_A1SYS, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_A2SYS, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_AFE_CONN, 0); +} + +void mt2701_turn_off_afe_clock(struct mt2701_afe *afe) +{ + /*MT_CG_INFRA_AUDIO,*/ + clk_disable_unprepare(afe->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); + + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_AUDINTBUS]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_ASM_H_SEL]); + clk_disable_unprepare(afe->clocks[MT2701_AUD_TOP_ASM_M_SEL]); + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUDIO_TOP_CON0_PDN_AFE, AUDIO_TOP_CON0_PDN_AFE); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUDIO_TOP_CON0_PDN_APLL_CK, + AUDIO_TOP_CON0_PDN_APLL_CK); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_A1SYS, AUDIO_TOP_CON4_PDN_A1SYS); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_A2SYS, AUDIO_TOP_CON4_PDN_A2SYS); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_AFE_CONN, + AUDIO_TOP_CON4_PDN_AFE_CONN); +} + +void mt2701_mclk_configuration(struct mt2701_afe *afe, int id, int domain, + int mclk) +{ + int ret; + int aud_src_div_id = MT2701_AUD_TOP_AUD_K1_SRC_DIV + id; + int aud_src_clk_id = MT2701_AUD_TOP_AUD_K1_SRC_SEL + id; + + /* Set MCLK Kx_SRC_SEL(domain) */ + ret = clk_prepare_enable(afe->clocks[aud_src_clk_id]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[aud_src_clk_id], ret); + + if (domain == 0) { + ret = clk_set_parent(afe->clocks[aud_src_clk_id], + afe->clocks[MT2701_AUD_TOP_AUD_MUX1_SEL]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[aud_src_clk_id], + aud_clks[MT2701_AUD_TOP_AUD_MUX1_SEL], ret); + } else { + ret = clk_set_parent(afe->clocks[aud_src_clk_id], + afe->clocks[MT2701_AUD_TOP_AUD_MUX2_SEL]); + if (ret) + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[aud_src_clk_id], + aud_clks[MT2701_AUD_TOP_AUD_MUX2_SEL], ret); + } + clk_disable_unprepare(afe->clocks[aud_src_clk_id]); + + /* Set MCLK Kx_SRC_DIV(divider) */ + ret = clk_prepare_enable(afe->clocks[aud_src_div_id]); + if (ret) + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[aud_src_div_id], ret); + + ret = clk_set_rate(afe->clocks[aud_src_div_id], mclk); + if (ret) + dev_err(afe->dev, "%s clk_set_rate %s-%d fail %d\n", __func__, + aud_clks[aud_src_div_id], mclk, ret); + clk_disable_unprepare(afe->clocks[aud_src_div_id]); +} + +MODULE_DESCRIPTION("MT2701 afe clock control"); +MODULE_AUTHOR("Garlic Tseng garlic.tseng@mediatek.com"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h new file mode 100644 index 0000000..4b02da2 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h @@ -0,0 +1,33 @@ +/* + * mt2701-afe-clock-ctrl.h -- Mediatek 2701 afe clock ctrl definition + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT2701_AFE_CLOCK_CTRL_H_ +#define _MT2701_AFE_CLOCK_CTRL_H_ + +struct mt2701_afe; + +void mt2701_init_clock(struct mt2701_afe *afe); +void mt2701_afe_enable_clock(struct mt2701_afe *afe, int en); +void mt2701_turn_on_a1sys_clock(struct mt2701_afe *afe); +void mt2701_turn_off_a1sys_clock(struct mt2701_afe *afe); +void mt2701_turn_on_a2sys_clock(struct mt2701_afe *afe); +void mt2701_turn_off_a2sys_clock(struct mt2701_afe *afe); +void mt2701_turn_on_afe_clock(struct mt2701_afe *afe); +void mt2701_turn_off_afe_clock(struct mt2701_afe *afe); +void mt2701_mclk_configuration(struct mt2701_afe *afe, int id, int domain, + int mclk); + +#endif diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h new file mode 100644 index 0000000..d801bce --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h @@ -0,0 +1,228 @@ +/* + * mt2701-afe-common.h -- Mediatek 2701 audio driver definitions + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * Koro Chen koro.chen@mediatek.com + * Sascha Hauer s.hauer@pengutronix.de + * Hidalgo Huang hidalgo.huang@mediatek.com + * Ir Lian ir.lian@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT_2701_AFE_COMMON_H_ +#define _MT_2701_AFE_COMMON_H_ +#include <sound/soc.h> +#include <linux/clk.h> +#include <linux/regmap.h> +#include "mt2701-reg.h" + +#define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1) +#define MT2701_PLL_DOMAIN_0_RATE 98304000 +#define MT2701_PLL_DOMAIN_1_RATE 90316800 +#define MT2701_AUD_TOP_AUD_MUX1_DIV_RATE (MT2701_PLL_DOMAIN_0_RATE / 2) +#define MT2701_AUD_TOP_AUD_MUX2_DIV_RATE (MT2701_PLL_DOMAIN_1_RATE / 2) + +enum { + MT2701_I2S_1, + MT2701_I2S_2, + MT2701_I2S_3, + MT2701_I2S_4, + MT2701_I2S_NUM, +}; + +enum { + MT2701_MEMIF_1, + MT2701_MEMIF_2, + MT2701_MEMIF_3, + MT2701_MEMIF_4, + MT2701_MEMIF_5, + MT2701_MEMIF_SINGLE_NUM, + MT2701_MEMIF_M = MT2701_MEMIF_SINGLE_NUM, + MT2701_MEMIF_BT, + MT2701_MEMIF_NUM, + MT2701_IO_I2S = MT2701_MEMIF_NUM, + MT2701_IO_2ND_I2S, + MT2701_IO_3RD_I2S, + MT2701_IO_4TH_I2S, + MT2701_IO_5TH_I2S, + MT2701_IO_6TH_I2S, + MT2701_IO_MRG, +}; + +enum { + MT2701_IRQ_ASYS_START, + MT2701_IRQ_ASYS_IRQ1 = MT2701_IRQ_ASYS_START, + MT2701_IRQ_ASYS_IRQ2, + MT2701_IRQ_ASYS_IRQ3, + MT2701_IRQ_ASYS_END, +}; + +enum { + DIV_ID_MCLK_TO_BCK, + DIV_ID_BCK_TO_LRCK, +}; + +/*2701 clock def*/ +enum audio_system_clock_type { + MT2701_AUD_INFRA_SYS_AUDIO, + MT2701_AUD_TOP_AUD_MUX1_SEL, + MT2701_AUD_TOP_AUD_MUX2_SEL, + MT2701_AUD_TOP_AUD_MUX1_DIV, + MT2701_AUD_TOP_AUD_MUX2_DIV, + MT2701_AUD_TOP_AUD_48K_TIMING, + MT2701_AUD_TOP_AUD_44K_TIMING, + MT2701_AUD_TOP_AUDPLL_MUX_SEL, + MT2701_AUD_TOP_APLL_SEL, + MT2701_AUD_TOP_AUD1PLL_98M, + MT2701_AUD_TOP_AUD2PLL_90M, + MT2701_AUD_TOP_HADDS2PLL_98M, + MT2701_AUD_TOP_HADDS2PLL_294M, + MT2701_AUD_TOP_AUDPLL, + MT2701_AUD_TOP_AUDPLL_D4, + MT2701_AUD_TOP_AUDPLL_D8, + MT2701_AUD_TOP_AUDPLL_D16, + MT2701_AUD_TOP_AUDPLL_D24, + MT2701_AUD_TOP_AUDINTBUS, + MT2701_AUD_CLK_26M, + MT2701_AUD_TOP_SYSPLL1_D4, + MT2701_AUD_TOP_AUD_K1_SRC_SEL, + MT2701_AUD_TOP_AUD_K2_SRC_SEL, + MT2701_AUD_TOP_AUD_K3_SRC_SEL, + MT2701_AUD_TOP_AUD_K4_SRC_SEL, + MT2701_AUD_TOP_AUD_K5_SRC_SEL, + MT2701_AUD_TOP_AUD_K6_SRC_SEL, + MT2701_AUD_TOP_AUD_K1_SRC_DIV, + MT2701_AUD_TOP_AUD_K2_SRC_DIV, + MT2701_AUD_TOP_AUD_K3_SRC_DIV, + MT2701_AUD_TOP_AUD_K4_SRC_DIV, + MT2701_AUD_TOP_AUD_K5_SRC_DIV, + MT2701_AUD_TOP_AUD_K6_SRC_DIV, + MT2701_AUD_TOP_AUD_I2S1_MCLK, + MT2701_AUD_TOP_AUD_I2S2_MCLK, + MT2701_AUD_TOP_AUD_I2S3_MCLK, + MT2701_AUD_TOP_AUD_I2S4_MCLK, + MT2701_AUD_TOP_AUD_I2S5_MCLK, + MT2701_AUD_TOP_AUD_I2S6_MCLK, + MT2701_AUD_TOP_ASM_M_SEL, + MT2701_AUD_TOP_ASM_H_SEL, + MT2701_AUD_TOP_UNIVPLL2_D4, + MT2701_AUD_TOP_UNIVPLL2_D2, + MT2701_AUD_TOP_SYSPLL_D5, + MT2701_CLOCK_NUM +}; + +static const unsigned int mt2701_afe_backup_list[] = { + AUDIO_TOP_CON0, + AUDIO_TOP_CON4, + AUDIO_TOP_CON5, + ASYS_TOP_CON, + AFE_CONN0, + AFE_CONN1, + AFE_CONN2, + AFE_CONN3, + AFE_CONN15, + AFE_CONN16, + AFE_CONN17, + AFE_CONN18, + AFE_CONN19, + AFE_CONN20, + AFE_CONN21, + AFE_CONN22, + AFE_DAC_CON0, + AFE_MEMIF_PBUF_SIZE, +}; + +struct mt2701_afe; +struct snd_pcm_substream; + +struct mt2701_afe_memif_data { + int id; + const char *name; + int reg_ofs_base; + int reg_ofs_cur; + int fs_reg; + int fs_shift; + int mono_reg; + int mono_shift; + int enable_shift; + int hd_reg; + int hd_shift; + int agent_disable_shift; +}; + +struct mt2701_afe_irq_data { + int irq_id; + int irq_cnt_reg; + int irq_cnt_shift; + int irq_cnt_maskbit; + int irq_fs_reg; + int irq_fs_shift; + int irq_fs_maskbit; + int irq_en_reg; + int irq_en_shift; + int irq_occupy; +}; + +struct mt2701_afe_irq { + const struct mt2701_afe_irq_data *irq_data; + int irq_occupyed; + struct mt2701_afe_memif *memif; + void (*isr)(struct mt2701_afe *afe, struct mt2701_afe_memif *memif); +}; + +struct mt2701_afe_memif { + unsigned int phys_buf_addr; + int buffer_size; + struct snd_pcm_substream *substream; + const struct mt2701_afe_memif_data *data; + struct mt2701_afe_irq *irq; +}; + +struct mt2701_i2s_data { + int i2s_ctrl_reg; + int i2s_pwn_shift; + int i2s_asrc_fs_shift; + int i2s_asrc_fs_mask; +}; + +enum mt2701_i2s_dir { + I2S_OUT, + I2S_IN, + I2S_DIR_NUM, +}; + +struct mt2701_i2s_path { + int dai_id; + int mclk_rate; + int div_mclk_to_bck; + int div_bck_to_lrck; + int format; + snd_pcm_format_t stream_fmt; + int on[I2S_DIR_NUM]; + int occupied[I2S_DIR_NUM]; + const struct mt2701_i2s_data *i2s_data[2]; +}; + +struct mt2701_afe { + void __iomem *base_addr; + struct device *dev; + struct regmap *regmap; + struct mt2701_afe_memif memif[MT2701_MEMIF_NUM][MT2701_STREAM_DIR_NUM]; + struct clk *clocks[MT2701_CLOCK_NUM]; + struct mt2701_afe_irq irqs[MT2701_IRQ_ASYS_END]; + struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM]; + bool mrg_enable[MT2701_STREAM_DIR_NUM]; + unsigned int backup_regs[ARRAY_SIZE(mt2701_afe_backup_list)]; + bool suspended; +}; + +#endif diff --git a/sound/soc/mediatek/mt2701/mt2701-irq.c b/sound/soc/mediatek/mt2701/mt2701-irq.c new file mode 100644 index 0000000..302766a --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-irq.c @@ -0,0 +1,74 @@ +/* + * mt2701-irq.c -- Mediatek 2701 audio driver irq function + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include "mt2701-afe-common.h" +#include "mt2701-irq.h" + +u32 mt2701_asys_irq_status(struct mt2701_afe *afe) +{ + u32 status = 0; + + regmap_read(afe->regmap, ASYS_IRQ_STATUS, &status); + return status; +} + +void mt2701_asys_irq_clear(struct mt2701_afe *afe, u32 status) +{ + regmap_write(afe->regmap, ASYS_IRQ_CLR, status); +} + +void mt2701_memif_isr(struct mt2701_afe *afe, struct mt2701_afe_memif *memif) +{ + if (memif) + snd_pcm_period_elapsed(memif->substream); +} + +static DEFINE_MUTEX(asys_irqs_lock); +int mt2701_asys_irq_acquire(struct mt2701_afe *afe) +{ + int i; + + mutex_lock(&asys_irqs_lock); + for (i = MT2701_IRQ_ASYS_START; i < MT2701_IRQ_ASYS_END; ++i) { + if (afe->irqs[i].irq_occupyed == 0) { + afe->irqs[i].irq_occupyed = 1; + mutex_unlock(&asys_irqs_lock); + return i; + } + } + mutex_unlock(&asys_irqs_lock); + return MT2701_IRQ_ASYS_END; +} + +int mt2701_asys_irq_release(struct mt2701_afe *afe, int irq_id) +{ + mutex_lock(&asys_irqs_lock); + if (irq_id >= MT2701_IRQ_ASYS_START && irq_id < MT2701_IRQ_ASYS_END) { + afe->irqs[irq_id].irq_occupyed = 0; + mutex_unlock(&asys_irqs_lock); + return 0; + } + mutex_unlock(&asys_irqs_lock); + return -EINVAL; +} + +MODULE_DESCRIPTION("MT2701 irq control"); +MODULE_AUTHOR("Garlic Tseng garlic.tseng@mediatek.com"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt2701/mt2701-irq.h b/sound/soc/mediatek/mt2701/mt2701-irq.h new file mode 100644 index 0000000..3c31037 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-irq.h @@ -0,0 +1,26 @@ +/* + * mt2701-irq.h -- Mediatek 2701 audio driver irq function definition + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT_2701_IRQ_H_ +#define _MT_2701_IRQ_H_ + +u32 mt2701_asys_irq_status(struct mt2701_afe *afe); +void mt2701_asys_irq_clear(struct mt2701_afe *afe, u32 status); +void mt2701_memif_isr(struct mt2701_afe *afe, struct mt2701_afe_memif *memif); +int mt2701_asys_irq_acquire(struct mt2701_afe *afe); +int mt2701_asys_irq_release(struct mt2701_afe *afe, int irq_id); + +#endif diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h new file mode 100644 index 0000000..c9c52a8 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-reg.h @@ -0,0 +1,195 @@ +/* + * mt2701-reg.h -- Mediatek 2701 audio driver reg definition + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT2701_REG_H_ +#define _MT2701_REG_H_ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> +#include "mt2701-afe-common.h" + +/***************************************************************************** + * R E G I S T E R D E F I N I T I O N + *****************************************************************************/ +#define AUDIO_TOP_CON0 0x0000 +#define AUDIO_TOP_CON4 0x0010 +#define AUDIO_TOP_CON5 0x0014 +#define AFE_DAIBT_CON0 0x001c +#define AFE_MRGIF_CON 0x003c +#define ASMI_TIMING_CON1 0x0100 +#define ASMO_TIMING_CON1 0x0104 +#define PWR1_ASM_CON1 0x0108 +#define AFE_BT_SECURITY0 0x0320 +#define AFE_BT_SECURITY1 0x0324 +#define ASYS_TOP_CON 0x0600 +#define ASYS_I2SIN1_CON 0x0604 +#define ASYS_I2SIN2_CON 0x0608 +#define ASYS_I2SIN3_CON 0x060c +#define ASYS_I2SIN4_CON 0x0610 +#define ASYS_I2SIN5_CON 0x0614 +#define ASYS_I2SO1_CON 0x061C +#define ASYS_I2SO2_CON 0x0620 +#define ASYS_I2SO3_CON 0x0624 +#define ASYS_I2SO4_CON 0x0628 +#define ASYS_I2SO5_CON 0x062c +#define PWR2_TOP_CON 0x0634 +#define AFE_CONN0 0x06c0 +#define AFE_CONN1 0x06c4 +#define AFE_CONN2 0x06c8 +#define AFE_CONN3 0x06cc +#define AFE_CONN14 0x06f8 +#define AFE_CONN15 0x06fc +#define AFE_CONN16 0x0700 +#define AFE_CONN17 0x0704 +#define AFE_CONN18 0x0708 +#define AFE_CONN19 0x070c +#define AFE_CONN20 0x0710 +#define AFE_CONN21 0x0714 +#define AFE_CONN22 0x0718 +#define AFE_CONN23 0x071c +#define AFE_CONN24 0x0720 +#define AFE_CONN41 0x0764 +#define ASYS_IRQ1_CON 0x0780 +#define ASYS_IRQ2_CON 0x0784 +#define ASYS_IRQ3_CON 0x0788 +#define ASYS_IRQ_CLR 0x07c0 +#define ASYS_IRQ_STATUS 0x07c4 +#define PWR2_ASM_CON1 0x1070 +#define AFE_DAC_CON0 0x1200 +#define AFE_DAC_CON1 0x1204 +#define AFE_DAC_CON2 0x1208 +#define AFE_DAC_CON3 0x120c +#define AFE_DAC_CON4 0x1210 +#define AFE_MEMIF_HD_CON1 0x121c +#define AFE_MEMIF_PBUF_SIZE 0x1238 +#define AFE_MEMIF_HD_CON0 0x123c +#define AFE_DL1_BASE 0x1240 +#define AFE_DL1_CUR 0x1244 +#define AFE_DL2_BASE 0x1250 +#define AFE_DL2_CUR 0x1254 +#define AFE_DL3_BASE 0x1260 +#define AFE_DL3_CUR 0x1264 +#define AFE_DL4_BASE 0x1270 +#define AFE_DL4_CUR 0x1274 +#define AFE_DL5_BASE 0x1280 +#define AFE_DL5_CUR 0x1284 +#define AFE_DLMCH_BASE 0x12a0 +#define AFE_DLMCH_CUR 0x12a4 +#define AFE_ARB1_BASE 0x12b0 +#define AFE_ARB1_CUR 0x12b4 +#define AFE_VUL_BASE 0x1300 +#define AFE_VUL_CUR 0x130c +#define AFE_UL2_BASE 0x1310 +#define AFE_UL2_END 0x1318 +#define AFE_UL2_CUR 0x131c +#define AFE_UL3_BASE 0x1320 +#define AFE_UL3_END 0x1328 +#define AFE_UL3_CUR 0x132c +#define AFE_UL4_BASE 0x1330 +#define AFE_UL4_END 0x1338 +#define AFE_UL4_CUR 0x133c +#define AFE_UL5_BASE 0x1340 +#define AFE_UL5_END 0x1348 +#define AFE_UL5_CUR 0x134c +#define AFE_DAI_BASE 0x1370 +#define AFE_DAI_CUR 0x137c + +/*AUDIO_TOP_CON0 (0x0000)*/ +#define AUDIO_TOP_CON0_A1SYS_A2SYS_ON (0x3 << 0) +#define AUDIO_TOP_CON0_PDN_AFE (0x1 << 2) +#define AUDIO_TOP_CON0_PDN_APLL_CK (0x1 << 23) + +/*AUDIO_TOP_CON4 (0x0010)*/ +#define AUDIO_TOP_CON4_I2SO1_PWN (0x1 << 6) +#define AUDIO_TOP_CON4_PDN_A1SYS (0x1 << 21) +#define AUDIO_TOP_CON4_PDN_A2SYS (0x1 << 22) +#define AUDIO_TOP_CON4_PDN_AFE_CONN (0x1 << 23) +#define AUDIO_TOP_CON4_PDN_MRGIF (0x1 << 25) + +/*AFE_DAIBT_CON0 (0x001c)*/ +#define AFE_DAIBT_CON0_DAIBT_EN (0x1 << 0) +#define AFE_DAIBT_CON0_BT_FUNC_EN (0x1 << 1) +#define AFE_DAIBT_CON0_BT_FUNC_RDY (0x1 << 3) +#define AFE_DAIBT_CON0_BT_WIDE_MODE_EN (0x1 << 9) +#define AFE_DAIBT_CON0_MRG_USE (0x1 << 12) + +/*PWR1_ASM_CON1 (0x0108)*/ +#define PWR1_ASM_CON1_INIT_VAL (0x492) + +/*AFE_MRGIF_CON (0x003c)*/ +#define AFE_MRGIF_CON_MRG_EN (0x1 << 0) +#define AFE_MRGIF_CON_MRG_I2S_EN (0x1 << 16) +#define AFE_MRGIF_CON_I2S_MODE_MASK (0xf << 20) +#define AFE_MRGIF_CON_I2S_MODE_32K (0x4 << 20) + +/*AFE_BT_SECURITY0 (0x0320)*/ +#define AFE_BT_SECURITY0_INIT_VAL (0x235000) + +/*AFE_BT_SECURITY1 (0x0324)*/ +#define AFE_BT_SECURITY1_INIT_VAL (0x5) + +/* ASYS_I2SO1_CON (0x061c)*/ +#define ASYS_I2SO1_CON_FS (0x1f << 8) +#define ASYS_I2SO1_CON_FS_SET(x) ((x) << 8) +#define ASYS_I2SO1_CON_MULTI_CH (0x1 << 16) +#define ASYS_I2SO1_CON_SIDEGEN (0x1 << 30) +#define ASYS_I2SO1_CON_I2S_EN (0x1 << 0) +/*0:EIAJ 1:I2S*/ +#define ASYS_I2SO1_CON_I2S_MODE (0x1 << 3) +#define ASYS_I2SO1_CON_WIDE_MODE (0x1 << 1) +#define ASYS_I2SO1_CON_WIDE_MODE_SET(x) ((x) << 1) + +/*PWR2_TOP_CON (0x0634)*/ +#define PWR2_TOP_CON_INIT_VAL (0xffe1ffff) + +/*ASYS_IRQ_CLR (0x07c0)*/ +#define ASYS_IRQ_CLR_ALL (0xffffffff) + +/*PWR2_ASM_CON1 (0x1070)*/ +#define PWR2_ASM_CON1_INIT_VAL (0x492492) + +/*AFE_DAC_CON0 (0x1200)*/ +#define AFE_DAC_CON0_AFE_ON (0x1 << 0) + +/* AFE_MEMIF_PBUF_SIZE (0x1238)*/ +#define AFE_MEMIF_PBUF_SIZE_DLM_MASK (0x1 << 29) +#define AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE (0x0 << 29) +#define AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE (0x1 << 29) +#define DLMCH_BIT_WIDTH_MASK (0x1 << 28) +#define AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK (0xf << 24) +#define AFE_MEMIF_PBUF_SIZE_DLM_CH(x) ((x) << 24) +#define AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK (0x3 << 12) +#define AFE_MEMIF_PBUF_SIZE_DLM_32BYTES (0x1 << 12) + +/*I2S in/out register bit control*/ +#define ASYS_I2S_CON_FS (0x1f << 8) +#define ASYS_I2S_CON_FS_SET(x) ((x) << 8) +#define ASYS_I2S_CON_MULTI_CH (0x1 << 16) +#define ASYS_I2S_CON_RESET (0x1 << 30) +#define ASYS_I2S_CON_I2S_EN (0x1 << 0) +#define ASYS_I2S_CON_I2S_COUPLE_MODE (0x1 << 17) +/*0:EIAJ 1:I2S*/ +#define ASYS_I2S_CON_I2S_MODE (0x1 << 3) +#define ASYS_I2S_CON_WIDE_MODE (0x1 << 1) +#define ASYS_I2S_CON_WIDE_MODE_SET(x) ((x) << 1) +#define ASYS_I2S_IN_PHASE_FIX (0x1 << 31) + +#define AFE_END_ADDR 0x15e0 +#endif
Add mt2701 platform driver implementation for playback and capture. The implement follow DAPM structure (memory interface as FE and I2S as BE). Because of the hardware design, i2s out required to be enabled when we need to enable i2s in. This patch includes the implementation.
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 1689 ++++++++++++++++++++++++++++ 1 file changed, 1689 insertions(+) create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c new file mode 100644 index 0000000..6cdc25e --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -0,0 +1,1689 @@ +/* + * Mediatek ALSA SoC AFE platform driver for 2701 + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Garlic Tseng garlic.tseng@mediatek.com + * Koro Chen koro.chen@mediatek.com + * Hidalgo Huang hidalgo.huang@mediatek.com + * Ir Lian ir.lian@mediatek.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/pm_runtime.h> +#include <sound/soc.h> + +#include "mt2701-afe-common.h" + +#include "mt2701-afe-clock-ctrl.h" +#include "mt2701-irq.h" + +#define AFE_BASE_END_OFFSET 8 +#define AFE_IRQ_STATUS_BITS 0xff + +static const struct snd_pcm_hardware mt2701_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED + | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE + | SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 1024, + .period_bytes_max = 1024 * 256, + .periods_min = 4, + .periods_max = 1024, + .buffer_bytes_max = 1024 * 1024 * 16, + .fifo_size = 0, +}; + +static snd_pcm_uframes_t mt2701_afe_pcm_pointer + (struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int stream_dir = substream->stream; + int cpu_dai_id = rtd->cpu_dai->id; + struct mt2701_afe_memif *memif = &afe->memif[cpu_dai_id][stream_dir]; + unsigned int hw_ptr; + int ret; + + ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr); + if (ret || hw_ptr == 0) { + dev_err(afe->dev, "%s hw_ptr err\n", __func__); + hw_ptr = memif->phys_buf_addr; + } + + return bytes_to_frames(substream->runtime, + hw_ptr - memif->phys_buf_addr); +} + +static const struct snd_pcm_ops mt2701_afe_pcm_ops = { + .ioctl = snd_pcm_lib_ioctl, + .pointer = mt2701_afe_pcm_pointer, +}; + +static int mt2701_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + size_t size; + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + + size = mt2701_afe_hardware.buffer_bytes_max; + return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + card->dev, size, size); +} + +static void mt2701_afe_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static const struct snd_soc_platform_driver mt2701_afe_pcm_platform = { + .ops = &mt2701_afe_pcm_ops, + .pcm_new = mt2701_afe_pcm_new, + .pcm_free = mt2701_afe_pcm_free, +}; + +struct mt2701_afe_rate { + unsigned int rate; + unsigned int regvalue; +}; + +static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = { + { .rate = 8000, .regvalue = 0 }, + { .rate = 12000, .regvalue = 1 }, + { .rate = 16000, .regvalue = 2 }, + { .rate = 24000, .regvalue = 3 }, + { .rate = 32000, .regvalue = 4 }, + { .rate = 48000, .regvalue = 5 }, + { .rate = 96000, .regvalue = 6 }, + { .rate = 192000, .regvalue = 7 }, + { .rate = 384000, .regvalue = 8 }, + { .rate = 7350, .regvalue = 16 }, + { .rate = 11025, .regvalue = 17 }, + { .rate = 14700, .regvalue = 18 }, + { .rate = 22050, .regvalue = 19 }, + { .rate = 29400, .regvalue = 20 }, + { .rate = 44100, .regvalue = 21 }, + { .rate = 88200, .regvalue = 22 }, + { .rate = 176400, .regvalue = 23 }, + { .rate = 352800, .regvalue = 24 }, +}; + +int mt2701_dai_num_to_i2s(struct mt2701_afe *afe, int num) +{ + int val = num - MT2701_IO_I2S; + + if (val < 0 || val > MT2701_I2S_NUM) { + dev_err(afe->dev, "%s, num not available, num %d, val %d\n", + __func__, num, val); + return -1; + } + return val; +} + +static int mt2701_afe_i2s_fs(unsigned int sample_rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt2701_afe_i2s_rates); i++) + if (mt2701_afe_i2s_rates[i].rate == sample_rate) + return mt2701_afe_i2s_rates[i].regvalue; + + return -EINVAL; +} + +static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + int clk_num = MT2701_AUD_TOP_AUD_I2S1_MCLK + i2s_num; + int ret = 0; + + /*enable mclk*/ + ret = clk_prepare_enable(afe->clocks[clk_num]); + if (ret) + dev_err(afe->dev, "Failed to enable mclk for I2S: %d\n", + i2s_num); + + return ret; +} + +static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, + int dir_invert) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + struct mt2701_i2s_path *i2s_path = &afe->i2s_path[i2s_num]; + const struct mt2701_i2s_data *i2s_data; + int stream_dir = substream->stream; + + if (dir_invert) { + if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) + stream_dir = SNDRV_PCM_STREAM_CAPTURE; + else + stream_dir = SNDRV_PCM_STREAM_PLAYBACK; + } + i2s_data = i2s_path->i2s_data[stream_dir]; + + i2s_path->on[stream_dir]--; + if (i2s_path->on[stream_dir] < 0) { + dev_warn(afe->dev, "i2s_path->on: %d, dir: %d\n", + i2s_path->on[stream_dir], stream_dir); + i2s_path->on[stream_dir] = 0; + } + if (i2s_path->on[stream_dir]) + return 0; + + /*disable i2s*/ + regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, + ASYS_I2S_CON_I2S_EN, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + 1 << i2s_data->i2s_pwn_shift, + 1 << i2s_data->i2s_pwn_shift); + return 0; +} + +static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + struct mt2701_i2s_path *i2s_path = &afe->i2s_path[i2s_num]; + int clk_num = MT2701_AUD_TOP_AUD_I2S1_MCLK + i2s_num; + + if (i2s_path->occupied[substream->stream]) + i2s_path->occupied[substream->stream] = 0; + else + goto I2S_UNSTART; + + mt2701_afe_i2s_path_shutdown(substream, dai, 0); + + /*need to disable i2s-out path when disable i2s-in*/ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + mt2701_afe_i2s_path_shutdown(substream, dai, 1); + +I2S_UNSTART: + /*disable mclk*/ + clk_disable_unprepare(afe->clocks[clk_num]); +} + +static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, + int dir_invert) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + struct mt2701_i2s_path *i2s_path = &afe->i2s_path[i2s_num]; + const struct mt2701_i2s_data *i2s_data; + struct snd_pcm_runtime * const runtime = substream->runtime; + int reg, fs, w_len = 1; + int stream_dir = substream->stream; + unsigned int mask = 0, val = 0; + + if (dir_invert) { + if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) + stream_dir = SNDRV_PCM_STREAM_CAPTURE; + else + stream_dir = SNDRV_PCM_STREAM_PLAYBACK; + } + i2s_data = i2s_path->i2s_data[stream_dir]; + + /*no need to enable if already done*/ + i2s_path->on[stream_dir]++; + + if (i2s_path->on[stream_dir] != 1) + return 0; + + fs = mt2701_afe_i2s_fs(runtime->rate); + + if (i2s_path->div_bck_to_lrck == 32) + w_len = 0; + else if (i2s_path->div_bck_to_lrck == 64) + w_len = 1; + else + dev_warn(dai->dev, "%s() bad bit count %d\n", __func__, + afe->i2s_path[i2s_num].div_bck_to_lrck); + + mask = ASYS_I2S_CON_FS | + ASYS_I2S_CON_MULTI_CH | /*0*/ + ASYS_I2S_CON_I2S_COUPLE_MODE | /*0*/ + ASYS_I2S_CON_I2S_MODE | + ASYS_I2S_CON_WIDE_MODE; + + val = ASYS_I2S_CON_FS_SET(fs) | + ASYS_I2S_CON_I2S_MODE | + ASYS_I2S_CON_WIDE_MODE_SET(w_len); + + if (stream_dir == SNDRV_PCM_STREAM_CAPTURE) { + mask |= ASYS_I2S_IN_PHASE_FIX; + val |= ASYS_I2S_IN_PHASE_FIX; + } + + regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, mask, val); + + if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) + reg = ASMO_TIMING_CON1; + else + reg = ASMI_TIMING_CON1; + + regmap_update_bits(afe->regmap, reg, + i2s_data->i2s_asrc_fs_mask << i2s_data->i2s_asrc_fs_shift, + fs << i2s_data->i2s_asrc_fs_shift); + + /*enable i2s*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + 1 << i2s_data->i2s_pwn_shift, + 0 << i2s_data->i2s_pwn_shift); + + /*reset irq hw status before enable*/ + regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, + ASYS_I2S_CON_RESET, ASYS_I2S_CON_RESET); + udelay(1); + regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, + ASYS_I2S_CON_RESET, 0); + udelay(1); + regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, + ASYS_I2S_CON_I2S_EN, ASYS_I2S_CON_I2S_EN); + return 0; +} + +static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int clk_domain; + + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + struct mt2701_i2s_path *i2s_path = &afe->i2s_path[i2s_num]; + const int mclk_rate = i2s_path->mclk_rate; + + if (i2s_path->occupied[substream->stream]) + return -EBUSY; + i2s_path->occupied[substream->stream] = 1; + + if (MT2701_PLL_DOMAIN_0_RATE % mclk_rate == 0) { + clk_domain = 0; + } else if (MT2701_PLL_DOMAIN_1_RATE % mclk_rate == 0) { + clk_domain = 1; + } else { + dev_err(dai->dev, "%s() bad mclk rate %d\n", + __func__, mclk_rate); + return -EINVAL; + } + mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mt2701_i2s_path_prepare_enable(substream, dai, 0); + } else { + /*need to enable i2s-out path when enable i2s-in*/ + /*prepare for another direction "out"*/ + mt2701_i2s_path_prepare_enable(substream, dai, 1); + /*prepare for "in"*/ + mt2701_i2s_path_prepare_enable(substream, dai, 0); + } + + return 0; +} + +static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct mt2701_afe *afe = dev_get_drvdata(dai->dev); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + /* mclk */ + if (dir == SND_SOC_CLOCK_IN) { + dev_warn(dai->dev, + "%s() warning: mt2701 doesn't support mclk input\n", + __func__); + return -EINVAL; + } + afe->i2s_path[i2s_num].mclk_rate = freq; + return 0; +} + +static int mt2701_afe_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, + int div) +{ + struct mt2701_afe *afe = dev_get_drvdata(dai->dev); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + + switch (div_id) { + case DIV_ID_MCLK_TO_BCK: + afe->i2s_path[i2s_num].div_mclk_to_bck = div; + break; + case DIV_ID_BCK_TO_LRCK: + afe->i2s_path[i2s_num].div_bck_to_lrck = div; + break; + default: + return -EINVAL; + } + return 0; +} + +static int mt2701_afe_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct mt2701_afe *afe = dev_get_drvdata(dai->dev); + int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); + + afe = dev_get_drvdata(dai->dev); + afe->i2s_path[i2s_num].format = fmt; + return 0; +} + +static int mt2701_playback_mem_avail(struct mt2701_afe *afe, int memif_num) +{ + struct mt2701_afe_memif *memif_tmp; + + if (memif_num >= MT2701_MEMIF_1 && + memif_num < MT2701_MEMIF_SINGLE_NUM) { + memif_tmp = + &afe->memif[MT2701_MEMIF_M][SNDRV_PCM_STREAM_PLAYBACK]; + if (memif_tmp->substream) + return 0; + } else if (memif_num == MT2701_MEMIF_M) { + int i; + + for (i = MT2701_MEMIF_1; i < MT2701_MEMIF_SINGLE_NUM; ++i) { + memif_tmp = &afe->memif[i][SNDRV_PCM_STREAM_PLAYBACK]; + if (memif_tmp->substream) + return 0; + } + } + return 1; +} + +static int mt2701_afe_dais_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + struct snd_pcm_runtime *runtime = substream->runtime; + int stream_dir = substream->stream; + int memif_num = rtd->cpu_dai->id; + struct mt2701_afe_memif *memif = &afe->memif[memif_num][stream_dir]; + int is_dlm = 0; + int ret, i; + struct mt2701_afe_memif *memif_tmp; + + if (memif->substream) { + dev_warn(afe->dev, "%s memif is occupied, stream_dir %d, memif_num = %d\n", + __func__, stream_dir, memif_num); + return -EBUSY; + } + + if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK && + !mt2701_playback_mem_avail(afe, memif_num)) { + dev_warn(afe->dev, "%s memif is not available, stream_dir %d, memif_num %d\n", + __func__, stream_dir, memif_num); + return -EBUSY; + } + + if (memif_num == MT2701_MEMIF_M && + stream_dir == SNDRV_PCM_STREAM_PLAYBACK) + is_dlm = 1; + + memif->substream = substream; + + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); + /*enable agent*/ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON5, + 1 << memif->data->agent_disable_shift, + 0 << memif->data->agent_disable_shift); + if (is_dlm) { + for (i = MT2701_MEMIF_1; i < MT2701_MEMIF_SINGLE_NUM; ++i) { + memif_tmp = &afe->memif[i][SNDRV_PCM_STREAM_PLAYBACK]; + regmap_update_bits(afe->regmap, AUDIO_TOP_CON5, + 1 << memif_tmp->data->agent_disable_shift, + 0 << memif_tmp->data->agent_disable_shift); + } + } + + snd_soc_set_runtime_hwparams(substream, &mt2701_afe_hardware); + + /* + * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be + * smaller than period_size due to AFE's internal buffer. + * This easily leads to overrun when avail_min is period_size. + * One more period can hold the possible unread buffer. + */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + ret = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_PERIODS, + 3, + mt2701_afe_hardware.periods_max); + if (ret < 0) { + dev_err(afe->dev, "hw_constraint_minmax failed\n"); + return ret; + } + } + + 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"); + + /*require irq resource*/ + if (!memif->irq) { + int irq_id = mt2701_asys_irq_acquire(afe); + + if (irq_id != MT2701_IRQ_ASYS_END) { + /* link */ + memif->irq = &afe->irqs[irq_id]; + afe->irqs[irq_id].memif = memif; + afe->irqs[irq_id].isr = mt2701_memif_isr; + } else { + dev_err(afe->dev, "%s() error: no more asys irq\n", + __func__); + ret = -EBUSY; + } + } + return ret; +} + +static void mt2701_afe_dais_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int stream_dir = substream->stream; + struct mt2701_afe_memif *memif = + &afe->memif[rtd->cpu_dai->id][stream_dir]; + int irq_id, i; + int is_dlm = 0; + struct mt2701_afe_memif *memif_tmp; + + irq_id = memif->irq->irq_data->irq_id; + if (rtd->cpu_dai->id == MT2701_MEMIF_M && + stream_dir == SNDRV_PCM_STREAM_PLAYBACK) + is_dlm = 1; + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON5, + 1 << memif->data->agent_disable_shift, + 1 << memif->data->agent_disable_shift); + if (is_dlm) { + for (i = MT2701_MEMIF_1; i < MT2701_MEMIF_SINGLE_NUM; ++i) { + memif_tmp = &afe->memif[i][SNDRV_PCM_STREAM_PLAYBACK]; + regmap_update_bits(afe->regmap, AUDIO_TOP_CON5, + 1 << memif_tmp->data->agent_disable_shift, + 1 << memif_tmp->data->agent_disable_shift); + } + } + mt2701_asys_irq_release(afe, irq_id); + memif->irq = NULL; + afe->irqs[irq_id].memif = NULL; + afe->irqs[irq_id].isr = NULL; + memif->substream = NULL; +} + +static int mt2701_afe_dais_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int stream_dir = substream->stream; + struct mt2701_afe_memif *memif = + &afe->memif[rtd->cpu_dai->id][stream_dir]; + int ret, fs, is_dlm = 0; + + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) + return ret; + + memif->phys_buf_addr = substream->runtime->dma_addr; + memif->buffer_size = substream->runtime->dma_bytes; + + /* set rate */ + if (memif->data->fs_shift < 0) + return 0; + + fs = mt2701_afe_i2s_fs(params_rate(params)); + if (fs < 0) + return -EINVAL; + + regmap_update_bits(afe->regmap, memif->data->fs_reg, + 0x1f << memif->data->fs_shift, + fs << memif->data->fs_shift); + /* set channel */ + if (memif->data->mono_shift >= 0) { + unsigned int mono = (params_channels(params) == 1) ? 1 : 0; + + regmap_update_bits(afe->regmap, memif->data->mono_reg, + 1 << memif->data->mono_shift, + mono << memif->data->mono_shift); + } + /* start */ + regmap_write(afe->regmap, + memif->data->reg_ofs_base, memif->phys_buf_addr); + /* end */ + regmap_write(afe->regmap, + memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, + memif->phys_buf_addr + memif->buffer_size - 1); + + if (rtd->cpu_dai->id == MT2701_MEMIF_M && + stream_dir == SNDRV_PCM_STREAM_PLAYBACK) + is_dlm = 1; + + if (is_dlm) { /*setting for multi-ch playback*/ + int channels = params_channels(params); + + regmap_update_bits(afe->regmap, + AFE_MEMIF_PBUF_SIZE, + AFE_MEMIF_PBUF_SIZE_DLM_MASK, + AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE); + regmap_update_bits(afe->regmap, + AFE_MEMIF_PBUF_SIZE, + AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK, + AFE_MEMIF_PBUF_SIZE_DLM_32BYTES); + regmap_update_bits(afe->regmap, + AFE_MEMIF_PBUF_SIZE, + AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK, + AFE_MEMIF_PBUF_SIZE_DLM_CH(channels)); + } else if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(afe->regmap, + AFE_MEMIF_PBUF_SIZE, + AFE_MEMIF_PBUF_SIZE_DLM_MASK, + AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE); + } + + return 0; +} + +static int mt2701_afe_dais_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int mt2701_afe_dais_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int stream_dir = substream->stream; + struct mt2701_afe_memif *memif = + &afe->memif[rtd->cpu_dai->id][stream_dir]; + int hd_audio = 0; + + /*set hd mode*/ + switch (substream->runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + hd_audio = 0; + break; + case SNDRV_PCM_FORMAT_S32_LE: + hd_audio = 1; + break; + case SNDRV_PCM_FORMAT_S24_LE: + hd_audio = 1; + break; + default: + dev_err(afe->dev, "%s() error: unsupported format %d\n", + __func__, substream->runtime->format); + break; + } + + regmap_update_bits(afe->regmap, memif->data->hd_reg, + 1 << memif->data->hd_shift, + hd_audio << memif->data->hd_shift); + + return 0; +} + +static int mt2701_afe_dais_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int stream_dir = substream->stream; + struct mt2701_afe_memif *memif = + &afe->memif[rtd->cpu_dai->id][stream_dir]; + struct mt2701_afe_memif *memif_tmp; + struct snd_pcm_runtime * const runtime = substream->runtime; + unsigned int counter = runtime->period_size; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /*memory interface enable*/ + if (memif->data->enable_shift >= 0) + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + 1 << memif->data->enable_shift, + 1 << memif->data->enable_shift); + + /* set irq counter */ + regmap_update_bits(afe->regmap, + memif->irq->irq_data->irq_cnt_reg, + memif->irq->irq_data->irq_cnt_maskbit + << memif->irq->irq_data->irq_cnt_shift, + counter << (memif->irq->irq_data->irq_cnt_shift)); + /* set irq fs */ + if (memif->irq->irq_data->irq_fs_shift >= 0) { + int fs; + + fs = mt2701_afe_i2s_fs(runtime->rate); + if (fs < 0) + return -EINVAL; + + regmap_update_bits(afe->regmap, + memif->irq->irq_data->irq_fs_reg, + memif->irq->irq_data->irq_fs_maskbit + << memif->irq->irq_data->irq_fs_shift, + fs << memif->irq->irq_data->irq_fs_shift); + } + + if (rtd->cpu_dai->id == MT2701_MEMIF_M && + stream_dir == SNDRV_PCM_STREAM_PLAYBACK) { + memif_tmp = &afe->memif[MT2701_MEMIF_1][stream_dir]; + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + 1 << memif_tmp->data->enable_shift, + 1 << memif_tmp->data->enable_shift); + } + /* enable interrupt */ + regmap_update_bits(afe->regmap, + memif->irq->irq_data->irq_en_reg, + 1 << memif->irq->irq_data->irq_en_shift, + 1 << memif->irq->irq_data->irq_en_shift); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* disable interrupt */ + regmap_update_bits(afe->regmap, + memif->irq->irq_data->irq_en_reg, + 1 << memif->irq->irq_data->irq_en_shift, + 0 << memif->irq->irq_data->irq_en_shift); + /*memory interface disable*/ + if (memif->data->enable_shift >= 0) + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + 1 << memif->data->enable_shift, 0); + if (rtd->cpu_dai->id == MT2701_MEMIF_M && + stream_dir == SNDRV_PCM_STREAM_PLAYBACK) { + memif_tmp = &afe->memif[MT2701_MEMIF_1][stream_dir]; + regmap_update_bits(afe->regmap, AFE_DAC_CON0, + 1 << memif_tmp->data->enable_shift, + 0); + } + return 0; + default: + return -EINVAL; + } +} + +/* FE DAIs */ +static const struct snd_soc_dai_ops mt2701_afe_dai_ops = { + .startup = mt2701_afe_dais_startup, + .shutdown = mt2701_afe_dais_shutdown, + .hw_params = mt2701_afe_dais_hw_params, + .hw_free = mt2701_afe_dais_hw_free, + .prepare = mt2701_afe_dais_prepare, + .trigger = mt2701_afe_dais_trigger, +}; + +/* I2S BE DAIs */ +static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = { + .startup = mt2701_afe_i2s_startup, + .shutdown = mt2701_afe_i2s_shutdown, + .prepare = mt2701_afe_i2s_prepare, + .set_sysclk = mt2701_afe_i2s_set_sysclk, + .set_clkdiv = mt2701_afe_i2s_set_clkdiv, + .set_fmt = mt2701_afe_i2s_set_fmt, +}; + +static int mt2701_afe_runtime_suspend(struct device *dev); +static int mt2701_afe_runtime_resume(struct device *dev); + +static int mt2701_afe_dai_suspend(struct snd_soc_dai *dai) +{ + struct mt2701_afe *afe = snd_soc_dai_get_drvdata(dai); + int i; + + dev_dbg(afe->dev, "%s\n", __func__); + if (pm_runtime_status_suspended(afe->dev) || afe->suspended) + return 0; + + for (i = 0; i < ARRAY_SIZE(mt2701_afe_backup_list); i++) + regmap_read(afe->regmap, mt2701_afe_backup_list[i], + &afe->backup_regs[i]); + + afe->suspended = true; + mt2701_afe_runtime_suspend(afe->dev); + return 0; +} + +static int mt2701_afe_dai_resume(struct snd_soc_dai *dai) +{ + struct mt2701_afe *afe = snd_soc_dai_get_drvdata(dai); + int i = 0; + + dev_dbg(afe->dev, "%s\n", __func__); + if (pm_runtime_status_suspended(afe->dev) || !afe->suspended) + return 0; + + mt2701_afe_runtime_resume(afe->dev); + + for (i = 0; i < ARRAY_SIZE(mt2701_afe_backup_list); i++) + regmap_write(afe->regmap, mt2701_afe_backup_list[i], + afe->backup_regs[i]); + + afe->suspended = false; + return 0; +} + +static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "PCM0", + .id = MT2701_MEMIF_1, + .suspend = mt2701_afe_dai_suspend, + .resume = mt2701_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) + }, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &mt2701_afe_dai_ops, + }, + { + .name = "PCM_multi", + .id = MT2701_MEMIF_M, + .suspend = mt2701_afe_dai_suspend, + .resume = mt2701_afe_dai_resume, + .playback = { + .stream_name = "DLM", + .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 = &mt2701_afe_dai_ops, + }, + { + .name = "PCM1", + .id = MT2701_MEMIF_2, + .suspend = mt2701_afe_dai_suspend, + .resume = mt2701_afe_dai_resume, + .capture = { + .stream_name = "UL2", + .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 = &mt2701_afe_dai_ops, + }, + /* BE DAIs */ + { + .name = "I2S0", + .id = MT2701_IO_I2S, + .playback = { + .stream_name = "I2S0 Playback", + .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 = "I2S0 Capture", + .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 = &mt2701_afe_i2s_ops, + .symmetric_rates = 1, + }, + { + .name = "I2S1", + .id = MT2701_IO_2ND_I2S, + .playback = { + .stream_name = "I2S1 Playback", + .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 = "I2S1 Capture", + .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 = &mt2701_afe_i2s_ops, + .symmetric_rates = 1, + }, + { + .name = "I2S2", + .id = MT2701_IO_3RD_I2S, + .playback = { + .stream_name = "I2S2 Playback", + .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 = "I2S2 Capture", + .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 = &mt2701_afe_i2s_ops, + .symmetric_rates = 1, + }, + { + .name = "I2S3", + .id = MT2701_IO_4TH_I2S, + .playback = { + .stream_name = "I2S3 Playback", + .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 = "I2S3 Capture", + .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 = &mt2701_afe_i2s_ops, + .symmetric_rates = 1, + }, +}; + +static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN0, 0, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o01_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN1, 1, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o02_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I02 Switch", AFE_CONN2, 2, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o03_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 3, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o14_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN14, 26, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o15_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I12 Switch", AFE_CONN15, 12, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o16_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I13 Switch", AFE_CONN16, 13, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o17_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o18_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o19_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o20_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o21_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o23_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o24_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_i02_mix[] = { + SOC_DAPM_SINGLE("I2S0 Switch", SND_SOC_NOPM, 0, 1, 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s0[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch Out I2s0", ASYS_I2SO1_CON, 26, 1, + 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s1[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch Out I2s1", ASYS_I2SO2_CON, 26, 1, + 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s2[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch Out I2s2", PWR2_TOP_CON, 17, 1, + 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch Out I2s3", PWR2_TOP_CON, 18, 1, + 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch Out I2s4", PWR2_TOP_CON, 19, 1, + 0), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc0[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch asrc out0", AUDIO_TOP_CON4, 14, 1, + 1), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc1[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch asrc out1", AUDIO_TOP_CON4, 15, 1, + 1), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc2[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch asrc out2", PWR2_TOP_CON, 6, 1, + 1), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc3[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch asrc out3", PWR2_TOP_CON, 7, 1, + 1), +}; + +static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc4[] = { + SOC_DAPM_SINGLE_AUTODISABLE("Multi ch asrc out4", PWR2_TOP_CON, 8, 1, + 1), +}; + +static const struct snd_soc_dapm_widget mt2701_afe_pcm_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("I02", SND_SOC_NOPM, 0, 0, mt2701_afe_i02_mix, + ARRAY_SIZE(mt2701_afe_i02_mix)), + SND_SOC_DAPM_MIXER("I03", 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("I26", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I35", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, mt2701_afe_o00_mix, + ARRAY_SIZE(mt2701_afe_o00_mix)), + SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, mt2701_afe_o01_mix, + ARRAY_SIZE(mt2701_afe_o01_mix)), + SND_SOC_DAPM_MIXER("O02", SND_SOC_NOPM, 0, 0, mt2701_afe_o02_mix, + ARRAY_SIZE(mt2701_afe_o02_mix)), + SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, mt2701_afe_o03_mix, + ARRAY_SIZE(mt2701_afe_o03_mix)), + SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, mt2701_afe_o14_mix, + ARRAY_SIZE(mt2701_afe_o14_mix)), + SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, mt2701_afe_o15_mix, + ARRAY_SIZE(mt2701_afe_o15_mix)), + SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, mt2701_afe_o16_mix, + ARRAY_SIZE(mt2701_afe_o16_mix)), + SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, mt2701_afe_o17_mix, + ARRAY_SIZE(mt2701_afe_o17_mix)), + SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, mt2701_afe_o18_mix, + ARRAY_SIZE(mt2701_afe_o18_mix)), + SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, mt2701_afe_o19_mix, + ARRAY_SIZE(mt2701_afe_o19_mix)), + SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, mt2701_afe_o20_mix, + ARRAY_SIZE(mt2701_afe_o20_mix)), + SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, mt2701_afe_o21_mix, + ARRAY_SIZE(mt2701_afe_o21_mix)), + SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, mt2701_afe_o22_mix, + ARRAY_SIZE(mt2701_afe_o22_mix)), + SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, mt2701_afe_o31_mix, + ARRAY_SIZE(mt2701_afe_o31_mix)), + + SND_SOC_DAPM_MIXER("I12I13", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_i2s0, + ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s0)), + SND_SOC_DAPM_MIXER("I14I15", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_i2s1, + ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s1)), + SND_SOC_DAPM_MIXER("I16I17", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_i2s2, + ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s2)), + SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_i2s3, + ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)), + + SND_SOC_DAPM_MIXER("ASRC_O0", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_asrc0, + ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc0)), + SND_SOC_DAPM_MIXER("ASRC_O1", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_asrc1, + ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc1)), + SND_SOC_DAPM_MIXER("ASRC_O2", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_asrc2, + ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc2)), + SND_SOC_DAPM_MIXER("ASRC_O3", SND_SOC_NOPM, 0, 0, + mt2701_afe_multi_ch_out_asrc3, + ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc3)), +}; + +static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { + {"I12", NULL, "DL1"}, + {"I13", NULL, "DL1"}, + {"I35", NULL, "DLBT"}, + + {"I2S0 Playback", NULL, "O15"}, + {"I2S0 Playback", NULL, "O16"}, + + {"I2S1 Playback", NULL, "O17"}, + {"I2S1 Playback", NULL, "O18"}, + {"I2S2 Playback", NULL, "O19"}, + {"I2S2 Playback", NULL, "O20"}, + {"I2S3 Playback", NULL, "O21"}, + {"I2S3 Playback", NULL, "O22"}, + {"BT Playback", NULL, "O31"}, + + {"UL1", NULL, "O00"}, + {"UL1", NULL, "O01"}, + {"UL2", NULL, "O02"}, + {"UL2", NULL, "O03"}, + {"ULBT", NULL, "O14"}, + + {"I00", NULL, "I2S0 Capture"}, + {"I01", NULL, "I2S0 Capture"}, + + {"I02", NULL, "I2S1 Capture"}, + {"I03", NULL, "I2S1 Capture"}, + /*I02,03 link to UL2, also need to open I2S0*/ + {"I02", "I2S0 Switch", "I2S0 Capture"}, + + {"I26", NULL, "BT Capture"}, + + {"ASRC_O0", "Multi ch asrc out0", "DLM"}, + {"ASRC_O1", "Multi ch asrc out1", "DLM"}, + {"ASRC_O2", "Multi ch asrc out2", "DLM"}, + {"ASRC_O3", "Multi ch asrc out3", "DLM"}, + + {"I12I13", "Multi ch Out I2s0", "ASRC_O0"}, + {"I14I15", "Multi ch Out I2s1", "ASRC_O1"}, + {"I16I17", "Multi ch Out I2s2", "ASRC_O2"}, + {"I18I19", "Multi ch Out I2s3", "ASRC_O3"}, + + { "I12", NULL, "I12I13" }, + { "I13", NULL, "I12I13" }, + { "I14", NULL, "I14I15" }, + { "I15", NULL, "I14I15" }, + { "I16", NULL, "I16I17" }, + { "I17", NULL, "I16I17" }, + { "I18", NULL, "I18I19" }, + { "I19", NULL, "I18I19" }, + + { "O00", "I00 Switch", "I00" }, + { "O01", "I01 Switch", "I01" }, + { "O02", "I02 Switch", "I02" }, + { "O03", "I03 Switch", "I03" }, + { "O14", "I26 Switch", "I26" }, + { "O15", "I12 Switch", "I12" }, + { "O16", "I13 Switch", "I13" }, + { "O17", "I14 Switch", "I14" }, + { "O18", "I15 Switch", "I15" }, + { "O19", "I16 Switch", "I16" }, + { "O20", "I17 Switch", "I17" }, + { "O21", "I18 Switch", "I18" }, + { "O22", "I19 Switch", "I19" }, + { "O31", "I35 Switch", "I35" }, + +}; + +static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = { + .name = "mt2701-afe-pcm-dai", + .dapm_widgets = mt2701_afe_pcm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt2701_afe_pcm_widgets), + .dapm_routes = mt2701_afe_pcm_routes, + .num_dapm_routes = ARRAY_SIZE(mt2701_afe_pcm_routes), +}; + +static const struct mt2701_afe_memif_data + memif_data[MT2701_MEMIF_NUM][MT2701_STREAM_DIR_NUM] = { + { + { + .name = "DL1", + .id = MT2701_MEMIF_1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 0, + .mono_reg = AFE_DAC_CON3, + .mono_shift = 16, + .enable_shift = 1, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 0, + .agent_disable_shift = 6, + }, + { + .name = "UL1", + .id = MT2701_MEMIF_1, + .reg_ofs_base = AFE_VUL_BASE, + .reg_ofs_cur = AFE_VUL_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = 0, + .mono_reg = AFE_DAC_CON4, + .mono_shift = 0, + .enable_shift = 10, + .hd_reg = AFE_MEMIF_HD_CON1, + .hd_shift = 0, + .agent_disable_shift = 0, + } + }, + { + { + .name = "DL2", + .id = MT2701_MEMIF_2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 5, + .mono_reg = AFE_DAC_CON3, + .mono_shift = 17, + .enable_shift = 2, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 2, + .agent_disable_shift = 7, + }, + { + .name = "UL2", + .id = MT2701_MEMIF_2, + .reg_ofs_base = AFE_UL2_BASE, + .reg_ofs_cur = AFE_UL2_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = 5, + .mono_reg = AFE_DAC_CON4, + .mono_shift = 2, + .enable_shift = 11, + .hd_reg = AFE_MEMIF_HD_CON1, + .hd_shift = 2, + .agent_disable_shift = 1, + } + }, + { + { + .name = "DL3", + .id = MT2701_MEMIF_3, + .reg_ofs_base = AFE_DL3_BASE, + .reg_ofs_cur = AFE_DL3_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 10, + .mono_reg = AFE_DAC_CON3, + .mono_shift = 18, + .enable_shift = 3, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 4, + .agent_disable_shift = 8, + }, + { + .name = "UL3", + .id = MT2701_MEMIF_3, + .reg_ofs_base = AFE_UL3_BASE, + .reg_ofs_cur = AFE_UL3_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = 10, + .mono_reg = AFE_DAC_CON4, + .mono_shift = 4, + .enable_shift = 12, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 0, + .agent_disable_shift = 2, + } + }, + { + { + .name = "DL4", + .id = MT2701_MEMIF_4, + .reg_ofs_base = AFE_DL4_BASE, + .reg_ofs_cur = AFE_DL4_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 15, + .mono_reg = AFE_DAC_CON3, + .mono_shift = 19, + .enable_shift = 4, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 6, + .agent_disable_shift = 9, + }, + { + .name = "UL4", + .id = MT2701_MEMIF_4, + .reg_ofs_base = AFE_UL4_BASE, + .reg_ofs_cur = AFE_UL4_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = 15, + .mono_reg = AFE_DAC_CON4, + .mono_shift = 6, + .enable_shift = 13, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 6, + .agent_disable_shift = 3, + } + }, + { + { + .name = "DL5", + .id = MT2701_MEMIF_5, + .reg_ofs_base = AFE_DL5_BASE, + .reg_ofs_cur = AFE_DL5_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 20, + .mono_reg = AFE_DAC_CON3, + .mono_shift = 20, + .enable_shift = 5, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 8, + .agent_disable_shift = 10, + }, + { + .name = "UL5", + .id = MT2701_MEMIF_5, + .reg_ofs_base = AFE_UL5_BASE, + .reg_ofs_cur = AFE_UL5_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = 20, + .mono_reg = AFE_DAC_CON4, + .mono_shift = 8, + .enable_shift = 14, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 8, + .agent_disable_shift = 4, + } + }, + { + { + .name = "DLM", + .id = MT2701_MEMIF_M, + .reg_ofs_base = AFE_DLMCH_BASE, + .reg_ofs_cur = AFE_DLMCH_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = 0, + .mono_reg = -1, + .mono_shift = -1, + .enable_shift = 7, + .hd_reg = AFE_MEMIF_PBUF_SIZE, + .hd_shift = 28, + .agent_disable_shift = 12, + }, + { + /*no UL multi channel support*/ + } + }, + { + { + .name = "DLBT", + .id = MT2701_MEMIF_BT, + .reg_ofs_base = AFE_ARB1_BASE, + .reg_ofs_cur = AFE_ARB1_CUR, + .fs_reg = AFE_DAC_CON3, + .fs_shift = 10, + .mono_reg = AFE_DAC_CON3, + .mono_shift = 22, + .enable_shift = 8, + .hd_reg = AFE_MEMIF_HD_CON0, + .hd_shift = 14, + .agent_disable_shift = 13, + }, + { + .name = "ULBT", + .id = MT2701_MEMIF_BT, + .reg_ofs_base = AFE_DAI_BASE, + .reg_ofs_cur = AFE_DAI_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = 30, + .mono_reg = -1, + .mono_shift = -1, + .enable_shift = 17, + .hd_reg = AFE_MEMIF_HD_CON1, + .hd_shift = 20, + .agent_disable_shift = 16, + } + } +}; + +static const struct mt2701_afe_irq_data irq_data[MT2701_IRQ_ASYS_END] = { + { + .irq_id = MT2701_IRQ_ASYS_IRQ1, + .irq_cnt_reg = ASYS_IRQ1_CON, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0xffffff, + .irq_fs_reg = ASYS_IRQ1_CON, + .irq_fs_shift = 24, + .irq_fs_maskbit = 0x1f, + .irq_en_reg = ASYS_IRQ1_CON, + .irq_en_shift = 31, + }, + { + .irq_id = MT2701_IRQ_ASYS_IRQ2, + .irq_cnt_reg = ASYS_IRQ2_CON, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0xffffff, + .irq_fs_reg = ASYS_IRQ2_CON, + .irq_fs_shift = 24, + .irq_fs_maskbit = 0x1f, + .irq_en_reg = ASYS_IRQ2_CON, + .irq_en_shift = 31, + }, + { + .irq_id = MT2701_IRQ_ASYS_IRQ3, + .irq_cnt_reg = ASYS_IRQ3_CON, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0xffffff, + .irq_fs_reg = ASYS_IRQ3_CON, + .irq_fs_shift = 24, + .irq_fs_maskbit = 0x1f, + .irq_en_reg = ASYS_IRQ3_CON, + .irq_en_shift = 31, + } +}; + +static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { + { + { + .i2s_ctrl_reg = ASYS_I2SO1_CON, + .i2s_pwn_shift = 6, + .i2s_asrc_fs_shift = 0, + .i2s_asrc_fs_mask = 0x1f, + + }, + { + .i2s_ctrl_reg = ASYS_I2SIN1_CON, + .i2s_pwn_shift = 0, + .i2s_asrc_fs_shift = 0, + .i2s_asrc_fs_mask = 0x1f, + + }, + }, + { + { + .i2s_ctrl_reg = ASYS_I2SO2_CON, + .i2s_pwn_shift = 7, + .i2s_asrc_fs_shift = 5, + .i2s_asrc_fs_mask = 0x1f, + + }, + { + .i2s_ctrl_reg = ASYS_I2SIN2_CON, + .i2s_pwn_shift = 1, + .i2s_asrc_fs_shift = 5, + .i2s_asrc_fs_mask = 0x1f, + + }, + }, + { + { + .i2s_ctrl_reg = ASYS_I2SO3_CON, + .i2s_pwn_shift = 8, + .i2s_asrc_fs_shift = 10, + .i2s_asrc_fs_mask = 0x1f, + + }, + { + .i2s_ctrl_reg = ASYS_I2SIN3_CON, + .i2s_pwn_shift = 2, + .i2s_asrc_fs_shift = 10, + .i2s_asrc_fs_mask = 0x1f, + + }, + }, + { + { + .i2s_ctrl_reg = ASYS_I2SO4_CON, + .i2s_pwn_shift = 9, + .i2s_asrc_fs_shift = 15, + .i2s_asrc_fs_mask = 0x1f, + + }, + { + .i2s_ctrl_reg = ASYS_I2SIN4_CON, + .i2s_pwn_shift = 3, + .i2s_asrc_fs_shift = 15, + .i2s_asrc_fs_mask = 0x1f, + + }, + }, +}; + +static const struct regmap_config mt2701_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = AFE_END_ADDR, + .cache_type = REGCACHE_NONE, +}; + +static irqreturn_t mt2701_asys_isr(int irq_id, void *dev) +{ + int id; + struct mt2701_afe *afe = dev; + struct mt2701_afe_irq *irq; + u32 status; + + status = mt2701_asys_irq_status(afe); + mt2701_asys_irq_clear(afe, status); + + for (id = MT2701_IRQ_ASYS_START; id < MT2701_IRQ_ASYS_END; ++id) { + irq = &afe->irqs[id]; + if (status & (0x1 << (id - MT2701_IRQ_ASYS_START)) && irq->isr) + irq->isr(afe, irq->memif); + } + return IRQ_HANDLED; +} + +static int mt2701_afe_runtime_suspend(struct device *dev) +{ + struct mt2701_afe *afe = dev_get_drvdata(dev); + + mt2701_afe_enable_clock(afe, 0); + return 0; +} + +static int mt2701_afe_runtime_resume(struct device *dev) +{ + struct mt2701_afe *afe = dev_get_drvdata(dev); + + pr_warn("%s\n", __func__); + mt2701_afe_enable_clock(afe, 1); + return 0; +} + +static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) +{ + int ret, i, j; + unsigned int irq_id; + struct mt2701_afe *afe; + struct resource *res; + + ret = 0; + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + + afe->dev = &pdev->dev; + + irq_id = platform_get_irq(pdev, 0); + if (!irq_id) { + dev_err(afe->dev, "%s no irq found\n", + afe->dev->of_node->name); + return -ENXIO; + } + ret = devm_request_irq(afe->dev, irq_id, mt2701_asys_isr, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) { + dev_err(afe->dev, "could not request_irq for asys-isr\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, + &mt2701_afe_regmap_config); + if (IS_ERR(afe->regmap)) + return PTR_ERR(afe->regmap); + + for (i = 0; i < MT2701_MEMIF_NUM; i++) + for (j = 0; j < MT2701_STREAM_DIR_NUM; ++j) + afe->memif[i][j].data = &memif_data[i][j]; + for (i = 0; i < MT2701_IRQ_ASYS_END; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + for (i = 0; i < MT2701_I2S_NUM; i++) { + afe->i2s_path[i].i2s_data[I2S_OUT] + = &mt2701_i2s_data[i][I2S_OUT]; + afe->i2s_path[i].i2s_data[I2S_IN] + = &mt2701_i2s_data[i][I2S_IN]; + } + + /* initial audio related clock */ + mt2701_init_clock(afe); + + platform_set_drvdata(pdev, afe); + + ret = snd_soc_register_platform(&pdev->dev, &mt2701_afe_pcm_platform); + if (ret) { + dev_warn(afe->dev, "err_platform\n"); + goto err_platform; + } + + ret = snd_soc_register_component(&pdev->dev, + &mt2701_afe_pcm_dai_component, + mt2701_afe_pcm_dais, + ARRAY_SIZE(mt2701_afe_pcm_dais)); + if (ret) { + dev_warn(afe->dev, "err_dai_component\n"); + goto err_dai_component; + } + /*enable afe clock*/ + mt2701_afe_enable_clock(afe, 1); + + return 0; +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_dai_component: + snd_soc_unregister_component(&pdev->dev); + return ret; +} + +static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev) +{ + struct mt2701_afe *afe = platform_get_drvdata(pdev); + + if (!pm_runtime_status_suspended(&pdev->dev)) + mt2701_afe_runtime_suspend(&pdev->dev); + + snd_soc_unregister_component(&pdev->dev); + snd_soc_unregister_platform(&pdev->dev); + /*disable afe clock*/ + mt2701_afe_enable_clock(afe, 0); + return 0; +} + +static const struct of_device_id mt2701_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt2701-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match); + +static const struct dev_pm_ops mt2701_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend, + mt2701_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt2701_afe_pcm_driver = { + .driver = { + .name = "mt2701-audio", + .of_match_table = mt2701_afe_pcm_dt_match, +#ifdef CONFIG_PM + .pm = &mt2701_afe_pm_ops, +#endif + }, + .probe = mt2701_afe_pcm_dev_probe, + .remove = mt2701_afe_pcm_dev_remove, +}; + +module_platform_driver(mt2701_afe_pcm_driver); + +MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701"); +MODULE_AUTHOR("Garlic Tseng garlic.tseng@mediatek.com"); +MODULE_LICENSE("GPL v2");
Add supports for 16k (wideband BT) and add a general compatible string "linux,bt-sco"
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- Documentation/devicetree/bindings/sound/bt-sco.txt | 2 +- sound/soc/codecs/bt-sco.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt index 29b8e5d..641edf7 100644 --- a/Documentation/devicetree/bindings/sound/bt-sco.txt +++ b/Documentation/devicetree/bindings/sound/bt-sco.txt @@ -4,7 +4,7 @@ This device support generic Bluetooth SCO link.
Required properties:
- - compatible : "delta,dfbmcs320" + - compatible : "delta,dfbmcs320" or "linux,bt-sco"
Example:
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index b084ad1..101b384 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c @@ -31,14 +31,14 @@ static struct snd_soc_dai_driver bt_sco_dai = { .stream_name = "Playback", .channels_min = 1, .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }; @@ -77,6 +77,7 @@ MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); #if defined(CONFIG_OF) static const struct of_device_id bt_sco_codec_of_match[] = { { .compatible = "delta,dfbmcs320", }, + { .compatible = "linux,bt-sco", }, {}, }; MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match);
Add BT implementation for mt2701 platform driver.
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 138 ++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-)
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 6cdc25e..88a6c1b 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -387,6 +387,86 @@ static int mt2701_afe_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; }
+static int mt2701_btmrg_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_MRGIF, 0); + + afe->mrg_enable[substream->stream] = 1; + return 0; +} + +static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + int stream_fs; + u32 val, msk; + + pr_debug("%s() cpu_dai id %d\n", __func__, dai->id); + stream_fs = params_rate(params); + + if ((stream_fs != 8000) && (stream_fs != 16000)) { + pr_err("%s() btmgr not supprt this stream_fs %d\n", + __func__, stream_fs); + return -EINVAL; + } + + regmap_update_bits(afe->regmap, + AFE_MRGIF_CON, + AFE_MRGIF_CON_I2S_MODE_MASK, + AFE_MRGIF_CON_I2S_MODE_32K); + + val = AFE_DAIBT_CON0_BT_FUNC_EN | AFE_DAIBT_CON0_BT_FUNC_RDY + | AFE_DAIBT_CON0_MRG_USE; + msk = val; + + if (stream_fs == 16000) + val |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN; + + msk |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN; + + regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, msk, val); + + regmap_write(afe->regmap, AFE_BT_SECURITY0, AFE_BT_SECURITY0_INIT_VAL); + regmap_write(afe->regmap, AFE_BT_SECURITY1, AFE_BT_SECURITY1_INIT_VAL); + regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, AFE_DAIBT_CON0_DAIBT_EN, + AFE_DAIBT_CON0_DAIBT_EN); + regmap_update_bits(afe->regmap, AFE_MRGIF_CON, AFE_MRGIF_CON_MRG_I2S_EN, + AFE_MRGIF_CON_MRG_I2S_EN); + regmap_update_bits(afe->regmap, AFE_MRGIF_CON, AFE_MRGIF_CON_MRG_EN, + AFE_MRGIF_CON_MRG_EN); + return 0; +} + +static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct mt2701_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); + + pr_debug("%s() cpu_dai id %d\n", __func__, dai->id); + /* if the other direction stream is not occupied */ + if (!afe->mrg_enable[!substream->stream]) { + regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, + AFE_DAIBT_CON0_DAIBT_EN, 0); + regmap_update_bits(afe->regmap, AFE_MRGIF_CON, + AFE_MRGIF_CON_MRG_EN, 0); + regmap_update_bits(afe->regmap, AFE_MRGIF_CON, + AFE_MRGIF_CON_MRG_I2S_EN, 0); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, + AUDIO_TOP_CON4_PDN_MRGIF, + AUDIO_TOP_CON4_PDN_MRGIF); + } + afe->mrg_enable[substream->stream] = 0; +} + static int mt2701_playback_mem_avail(struct mt2701_afe *afe, int memif_num) { struct mt2701_afe_memif *memif_tmp; @@ -554,8 +634,12 @@ static int mt2701_afe_dais_hw_params(struct snd_pcm_substream *substream, /* set rate */ if (memif->data->fs_shift < 0) return 0; + if (rtd->cpu_dai->id != MT2701_MEMIF_BT || + stream_dir != SNDRV_PCM_STREAM_CAPTURE) + fs = mt2701_afe_i2s_fs(params_rate(params)); + else + fs = (params_rate(params) == 16000) ? 1 : 0;
- fs = mt2701_afe_i2s_fs(params_rate(params)); if (fs < 0) return -EINVAL;
@@ -746,6 +830,13 @@ static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = { .set_fmt = mt2701_afe_i2s_set_fmt, };
+/* MRG BE DAIs*/ +static struct snd_soc_dai_ops mt2701_btmrg_ops = { + .startup = mt2701_btmrg_startup, + .shutdown = mt2701_btmrg_shutdown, + .hw_params = mt2701_btmrg_hw_params, +}; + static int mt2701_afe_runtime_suspend(struct device *dev); static int mt2701_afe_runtime_resume(struct device *dev);
@@ -845,6 +936,29 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = { }, .ops = &mt2701_afe_dai_ops, }, + { + .name = "PCM_BT", + .id = MT2701_MEMIF_BT, + .suspend = mt2701_afe_dai_suspend, + .resume = mt2701_afe_dai_resume, + .playback = { + .stream_name = "DLBT", + .channels_min = 1, + .channels_max = 1, + .rates = (SNDRV_PCM_RATE_8000 + | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "ULBT", + .channels_min = 1, + .channels_max = 1, + .rates = (SNDRV_PCM_RATE_8000 + | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &mt2701_afe_dai_ops, + }, /* BE DAIs */ { .name = "I2S0", @@ -944,6 +1058,28 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = { .ops = &mt2701_afe_i2s_ops, .symmetric_rates = 1, }, + { + .name = "MRG BT", + .id = MT2701_IO_MRG, + .playback = { + .stream_name = "BT Playback", + .channels_min = 1, + .channels_max = 1, + .rates = (SNDRV_PCM_RATE_8000 + | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "BT Capture", + .channels_min = 1, + .channels_max = 1, + .rates = (SNDRV_PCM_RATE_8000 + | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &mt2701_btmrg_ops, + .symmetric_rates = 1, + } };
static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
Add machine driver and config option for MT2701.
Signed-off-by: Garlic Tseng garlic.tseng@mediatek.com --- sound/soc/mediatek/Kconfig | 21 ++ sound/soc/mediatek/Makefile | 2 +- sound/soc/mediatek/mt2701/Makefile | 20 ++ sound/soc/mediatek/mt2701/mt2701-cs42448.c | 412 +++++++++++++++++++++++++++++ 4 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 sound/soc/mediatek/mt2701/Makefile create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index ae9f664..774972b 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -1,3 +1,23 @@ +config SND_SOC_MT2701 + bool "SND_SOC_MT2701" + depends on ARCH_MEDIATEK + help + This adds ASoC driver for Mediatek MT2701 boards + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". + +config SND_SOC_MT2701_CS42448 + bool "SND_SOC_MT2701_CS42448" + depends on SND_SOC_MT2701 + select SND_SOC_CS42XX8_I2C + select SND_SOC_BT_SCO + help + This adds ASoC driver for Mediatek MT2701 boards + with the CS42448 codecs. + Select Y if you have such device. + If unsure select "N". + config SND_SOC_MT8173 tristate "ASoC support for Mediatek MT8173 chip" depends on ARCH_MEDIATEK @@ -49,3 +69,4 @@ config SND_SOC_MT8173_RT5650_RT5676 with the RT5650 and RT5676 codecs. Select Y if you have such device. If unsure select "N". + diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 240dfc70..b78341c 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -1,2 +1,2 @@ -# 8173 Machine support +obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile new file mode 100644 index 0000000..5f21fd3 --- /dev/null +++ b/sound/soc/mediatek/mt2701/Makefile @@ -0,0 +1,20 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# platform driver +obj-$(CONFIG_SND_SOC_MT2701) += mt2701-afe-pcm.o +obj-$(CONFIG_SND_SOC_MT2701) += mt2701-irq.o +obj-$(CONFIG_SND_SOC_MT2701) += mt2701-afe-clock-ctrl.o + +# machine driver +obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c new file mode 100644 index 0000000..6f61cc3 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -0,0 +1,412 @@ +/* + * mt2701-cs42448.c -- MT2701 CS42448 ALSA SoC machine driver + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Ir Lian ir.lian@mediatek.com + * Garlic Tseng garlic.tseng@mediatek.com + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <sound/soc.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/pinctrl/consumer.h> +#include <linux/of_gpio.h> + +#include "mt2701-afe-common.h" + +struct mt2701_cs42448_private { + int i2s1_in_mux; + int i2s1_in_mux_gpio_sel_1; + int i2s1_in_mux_gpio_sel_2; +}; + +static const char * const i2sin_mux_switch_text[] = { + "ADC_SDOUT2", + "ADC_SDOUT3", + "I2S_IN_1", + "I2S_IN_2", +}; + +static const struct soc_enum i2sin_mux_enum = + SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text); + +static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card); + + ucontrol->value.integer.value[0] = priv->i2s1_in_mux; + return 0; +} + +static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); + struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card); + + if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux) + return 0; + + switch (ucontrol->value.integer.value[0]) { + case 0: + gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0); + gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0); + break; + case 1: + gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1); + gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0); + break; + case 2: + gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0); + gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1); + break; + case 3: + gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1); + gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1); + break; + default: + dev_warn(card->dev, "%s invalid setting\n", __func__); + } + + priv->i2s1_in_mux = ucontrol->value.integer.value[0]; + return 0; +} + +static const struct snd_soc_dapm_widget + mt2701_cs42448_asoc_card_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Line Out Jack", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), + SND_SOC_DAPM_LINE("Tuner In", NULL), + SND_SOC_DAPM_LINE("Satellite Tuner In", NULL), + SND_SOC_DAPM_LINE("AUX In", NULL), +}; + +static const struct snd_kcontrol_new mt2701_cs42448_controls[] = { + SOC_DAPM_PIN_SWITCH("Line Out Jack"), + SOC_DAPM_PIN_SWITCH("AMIC"), + SOC_DAPM_PIN_SWITCH("Tuner In"), + SOC_DAPM_PIN_SWITCH("Satellite Tuner In"), + SOC_DAPM_PIN_SWITCH("AUX In"), + SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum, + mt2701_cs42448_i2sin1_mux_get, + mt2701_cs42448_i2sin1_mux_set), +}; + +static const unsigned int mt2701_cs42448_sampling_rates[] = {48000}; + +static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = { + .count = ARRAY_SIZE(mt2701_cs42448_sampling_rates), + .list = mt2701_cs42448_sampling_rates, + .mask = 0, +}; + +static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream) +{ + int err; + + err = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &mt2701_cs42448_constraints_rates); + if (err < 0) { + dev_err(substream->pcm->card->dev, /*better way to get device?*/ + "%s snd_pcm_hw_constraint_list failed: 0x%x\n", + __func__, err); + return err; + } + return 0; +} + +static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = { + .startup = mt2701_cs42448_fe_ops_startup, +}; + +static int mt2701_cs42448_be_ops_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + /* codec slave, mt2701 master */ + unsigned int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_CONT; + unsigned int mclk_rate; + unsigned int rate = params_rate(params); + unsigned int div_mclk_to_bck = rate > 192000 ? 2 : 4; + unsigned int div_bck_to_lrck = 64; + + mclk_rate = rate * div_bck_to_lrck * div_mclk_to_bck; + + /* mt2701 mclk */ + snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT); + /* mt2701 bck */ + snd_soc_dai_set_clkdiv(cpu_dai, DIV_ID_MCLK_TO_BCK, div_mclk_to_bck); + /* mt2701 lrck */ + snd_soc_dai_set_clkdiv(cpu_dai, DIV_ID_BCK_TO_LRCK, div_bck_to_lrck); + /* mt2701 master */ + snd_soc_dai_set_fmt(cpu_dai, fmt); + + /* codec mclk */ + snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN); + /* codec slave */ + snd_soc_dai_set_fmt(codec_dai, fmt); + return 0; +} + +static struct snd_soc_ops mt2701_cs42448_be_ops = { + .hw_params = mt2701_cs42448_be_ops_hw_params +}; + +enum { + DAI_LINK_FE_PCM0, + DAI_LINK_FE_MULTI_CH_OUT, + DAI_LINK_FE_PCM1_IN, + DAI_LINK_FE_BT, + DAI_LINK_BE_I2S0, + DAI_LINK_BE_I2S1, + DAI_LINK_BE_I2S2, + DAI_LINK_BE_I2S3, + DAI_LINK_BE_MRG_BT, +}; + +static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { + /*FE*/ + [DAI_LINK_FE_PCM0] = { + .name = "mt2701-cs42448-pcm0", + .stream_name = "mt2701-cs42448-pcm0", + .cpu_dai_name = "PCM0", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &mt2701_cs42448_48k_fe_ops, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + [DAI_LINK_FE_MULTI_CH_OUT] = { + .name = "mt2701-cs42448-multi-ch-out", + .stream_name = "mt2701-cs42448-multi-ch-out", + .cpu_dai_name = "PCM_multi", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &mt2701_cs42448_48k_fe_ops, + .dynamic = 1, + .dpcm_playback = 1, + }, + [DAI_LINK_FE_PCM1_IN] = { + .name = "mt2701-cs42448-pcm1-data-UL", + .stream_name = "mt2701-cs42448-pcm1-data-UL", + .cpu_dai_name = "PCM1", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ops = &mt2701_cs42448_48k_fe_ops, + .dynamic = 1, + .dpcm_capture = 1, + }, + [DAI_LINK_FE_BT] = { + .name = "mt2701-cs42448-pcm-BT", + .stream_name = "mt2701-cs42448-pcm-BT", + .cpu_dai_name = "PCM_BT", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + /*BE*/ + [DAI_LINK_BE_I2S0] = { + .name = "mt2701-cs42448-I2S0", + .cpu_dai_name = "I2S0", + .no_pcm = 1, + .codec_dai_name = "cs42448", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt2701_cs42448_be_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + [DAI_LINK_BE_I2S1] = { + .name = "mt2701-cs42448-I2S1", + .cpu_dai_name = "I2S1", + .no_pcm = 1, + .codec_dai_name = "cs42448", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt2701_cs42448_be_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + [DAI_LINK_BE_I2S2] = { + .name = "mt2701-cs42448-I2S2", + .cpu_dai_name = "I2S2", + .no_pcm = 1, + .codec_dai_name = "cs42448", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt2701_cs42448_be_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + [DAI_LINK_BE_I2S3] = { + .name = "mt2701-cs42448-I2S3", + .cpu_dai_name = "I2S3", + .no_pcm = 1, + .codec_dai_name = "cs42448", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + | SND_SOC_DAIFMT_GATED, + .ops = &mt2701_cs42448_be_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + [DAI_LINK_BE_MRG_BT] = { + .name = "mt2701-cs42448-MRG-BT", + .cpu_dai_name = "MRG BT", + .no_pcm = 1, + .codec_dai_name = "bt-sco-pcm", + .dpcm_playback = 1, + .dpcm_capture = 1, + }, +}; + +static struct snd_soc_card mt2701_cs42448_soc_card = { + .name = "mt2701-cs42448", + .owner = THIS_MODULE, + .dai_link = mt2701_cs42448_dai_links, + .num_links = ARRAY_SIZE(mt2701_cs42448_dai_links), + .controls = mt2701_cs42448_controls, + .num_controls = ARRAY_SIZE(mt2701_cs42448_controls), + .dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets), +}; + +static int mt2701_cs42448_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mt2701_cs42448_soc_card; + int ret; + int i; + struct device_node *platform_node, *codec_node, *codec_node_bt_mrg; + struct mt2701_cs42448_private *priv = + devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private), + GFP_KERNEL); + struct device *dev = &pdev->dev; + + if (!priv) + return -ENOMEM; + + platform_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,platform", 0); + if (!platform_node) { + dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); + return -EINVAL; + } + for (i = 0; i < card->num_links; i++) { + if (mt2701_cs42448_dai_links[i].platform_name) + continue; + mt2701_cs42448_dai_links[i].platform_of_node = platform_node; + } + + card->dev = dev; + + codec_node = of_parse_phandle(pdev->dev.of_node, + "mediatek,audio-codec", 0); + if (!codec_node) { + dev_err(&pdev->dev, + "Property 'audio-codec' missing or invalid\n"); + return -EINVAL; + } + for (i = 0; i < card->num_links; i++) { + if (mt2701_cs42448_dai_links[i].codec_name) + continue; + mt2701_cs42448_dai_links[i].codec_of_node = codec_node; + } + + codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, + "mediatek,audio-codec-bt-mrg", 0); + if (!codec_node_bt_mrg) { + dev_err(&pdev->dev, + "Property 'audio-codec-bt-mrg' missing or invalid\n"); + return -EINVAL; + } + mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codec_of_node + = codec_node_bt_mrg; + + ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + return ret; + } + + priv->i2s1_in_mux_gpio_sel_1 = + of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0); + if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) { + ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1, + "i2s1_in_mux_gpio_sel_1"); + if (ret) + dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n", + __func__, ret); + gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0); + } + + priv->i2s1_in_mux_gpio_sel_2 = + of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0); + if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) { + ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2, + "i2s1_in_mux_gpio_sel_2"); + if (ret) + dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n", + __func__, ret); + gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0); + } + snd_soc_card_set_drvdata(card, priv); + + ret = devm_snd_soc_register_card(&pdev->dev, card); + + if (ret) + dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", + __func__, ret); + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id mt2701_cs42448_machine_dt_match[] = { + {.compatible = "mediatek,mt2701-cs42448-machine",}, + {} +}; +#endif + +static struct platform_driver mt2701_cs42448_machine = { + .driver = { + .name = "mt2701-cs42448", + #ifdef CONFIG_OF + .of_match_table = mt2701_cs42448_machine_dt_match, + #endif + }, + .probe = mt2701_cs42448_machine_probe, +}; + +module_platform_driver(mt2701_cs42448_machine); + +/* Module information */ +MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver"); +MODULE_AUTHOR("Ir Lian ir.lian@mediatek.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("mt2701 cs42448 soc card");
participants (3)
-
Garlic Tseng
-
Mark Brown
-
Matthias Brugger