Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // MediaTek ALSA SoC Audio DAI I2S Control
0004 //
0005 // Copyright (c) 2018 MediaTek Inc.
0006 // Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
0007 
0008 #include <linux/regmap.h>
0009 #include <sound/pcm_params.h>
0010 #include "mt6797-afe-common.h"
0011 #include "mt6797-interconnection.h"
0012 #include "mt6797-reg.h"
0013 
0014 enum AUD_TX_LCH_RPT {
0015     AUD_TX_LCH_RPT_NO_REPEAT = 0,
0016     AUD_TX_LCH_RPT_REPEAT = 1
0017 };
0018 
0019 enum AUD_VBT_16K_MODE {
0020     AUD_VBT_16K_MODE_DISABLE = 0,
0021     AUD_VBT_16K_MODE_ENABLE = 1
0022 };
0023 
0024 enum AUD_EXT_MODEM {
0025     AUD_EXT_MODEM_SELECT_INTERNAL = 0,
0026     AUD_EXT_MODEM_SELECT_EXTERNAL = 1
0027 };
0028 
0029 enum AUD_PCM_SYNC_TYPE {
0030     /* bck sync length = 1 */
0031     AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
0032     /* bck sync length = PCM_INTF_CON1[9:13] */
0033     AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
0034 };
0035 
0036 enum AUD_BT_MODE {
0037     AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
0038     AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
0039 };
0040 
0041 enum AUD_PCM_AFIFO_SRC {
0042     /* slave mode & external modem uses different crystal */
0043     AUD_PCM_AFIFO_ASRC = 0,
0044     /* slave mode & external modem uses the same crystal */
0045     AUD_PCM_AFIFO_AFIFO = 1
0046 };
0047 
0048 enum AUD_PCM_CLOCK_SOURCE {
0049     AUD_PCM_CLOCK_MASTER_MODE = 0,
0050     AUD_PCM_CLOCK_SLAVE_MODE = 1
0051 };
0052 
0053 enum AUD_PCM_WLEN {
0054     AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
0055     AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
0056 };
0057 
0058 enum AUD_PCM_MODE {
0059     AUD_PCM_MODE_PCM_MODE_8K = 0,
0060     AUD_PCM_MODE_PCM_MODE_16K = 1,
0061     AUD_PCM_MODE_PCM_MODE_32K = 2,
0062     AUD_PCM_MODE_PCM_MODE_48K = 3,
0063 };
0064 
0065 enum AUD_PCM_FMT {
0066     AUD_PCM_FMT_I2S = 0,
0067     AUD_PCM_FMT_EIAJ = 1,
0068     AUD_PCM_FMT_PCM_MODE_A = 2,
0069     AUD_PCM_FMT_PCM_MODE_B = 3
0070 };
0071 
0072 enum AUD_BCLK_OUT_INV {
0073     AUD_BCLK_OUT_INV_NO_INVERSE = 0,
0074     AUD_BCLK_OUT_INV_INVERSE = 1
0075 };
0076 
0077 enum AUD_PCM_EN {
0078     AUD_PCM_EN_DISABLE = 0,
0079     AUD_PCM_EN_ENABLE = 1
0080 };
0081 
0082 /* dai component */
0083 static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
0084     SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
0085                     I_ADDA_UL_CH1, 1, 0),
0086     SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
0087                     I_DL2_CH1, 1, 0),
0088 };
0089 
0090 static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
0091     SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
0092                     I_ADDA_UL_CH2, 1, 0),
0093     SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
0094                     I_DL2_CH2, 1, 0),
0095 };
0096 
0097 static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
0098     SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
0099                     I_DL1_CH1, 1, 0),
0100 };
0101 
0102 static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
0103     SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
0104                     I_ADDA_UL_CH1, 1, 0),
0105     SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
0106                     I_DL2_CH1, 1, 0),
0107 };
0108 
0109 static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
0110     SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
0111                     I_ADDA_UL_CH2, 1, 0),
0112     SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
0113                     I_DL2_CH2, 1, 0),
0114 };
0115 
0116 static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
0117     SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
0118                     I_DL1_CH1, 1, 0),
0119 };
0120 
0121 static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
0122     /* inter-connections */
0123     SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
0124                mtk_pcm_1_playback_ch1_mix,
0125                ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
0126     SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
0127                mtk_pcm_1_playback_ch2_mix,
0128                ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
0129     SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
0130                mtk_pcm_1_playback_ch4_mix,
0131                ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
0132     SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
0133                mtk_pcm_2_playback_ch1_mix,
0134                ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
0135     SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
0136                mtk_pcm_2_playback_ch2_mix,
0137                ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
0138     SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
0139                mtk_pcm_2_playback_ch4_mix,
0140                ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
0141 
0142     SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0,
0143                 NULL, 0),
0144 
0145     SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0,
0146                 NULL, 0),
0147 
0148     SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
0149     SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
0150     SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
0151     SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
0152 };
0153 
0154 static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
0155     {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
0156     {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
0157     {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
0158     {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
0159     {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
0160     {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
0161 
0162     {"PCM 1 Playback", NULL, "PCM_1_EN"},
0163     {"PCM 2 Playback", NULL, "PCM_2_EN"},
0164     {"PCM 1 Capture", NULL, "PCM_1_EN"},
0165     {"PCM 2 Capture", NULL, "PCM_2_EN"},
0166 
0167     {"AFE_TO_MD1", NULL, "PCM 2 Playback"},
0168     {"AFE_TO_MD2", NULL, "PCM 1 Playback"},
0169     {"PCM 2 Capture", NULL, "MD1_TO_AFE"},
0170     {"PCM 1 Capture", NULL, "MD2_TO_AFE"},
0171 
0172     {"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
0173     {"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
0174     {"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
0175     {"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
0176     {"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
0177     {"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
0178 };
0179 
0180 /* dai ops */
0181 static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
0182                  struct snd_pcm_hw_params *params,
0183                  struct snd_soc_dai *dai)
0184 {
0185     struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
0186     unsigned int rate = params_rate(params);
0187     unsigned int rate_reg = mt6797_rate_transform(afe->dev, rate, dai->id);
0188     unsigned int pcm_con = 0;
0189 
0190     dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
0191         __func__,
0192         dai->id,
0193         substream->stream,
0194         rate,
0195         rate_reg,
0196         dai->playback_widget->active,
0197         dai->capture_widget->active);
0198 
0199     if (dai->playback_widget->active || dai->capture_widget->active)
0200         return 0;
0201 
0202     switch (dai->id) {
0203     case MT6797_DAI_PCM_1:
0204         pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
0205         pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
0206         pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
0207         pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
0208         pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
0209         pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
0210         pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
0211         pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
0212         pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
0213         pcm_con |= rate_reg << PCM_MODE_SFT;
0214         pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
0215 
0216         regmap_update_bits(afe->regmap, PCM_INTF_CON1,
0217                    0xfffffffe, pcm_con);
0218         break;
0219     case MT6797_DAI_PCM_2:
0220         pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
0221         pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
0222         pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
0223         pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
0224         pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
0225         pcm_con |= rate_reg << PCM2_MODE_SFT;
0226         pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
0227 
0228         regmap_update_bits(afe->regmap, PCM2_INTF_CON,
0229                    0xfffffffe, pcm_con);
0230         break;
0231     default:
0232         dev_warn(afe->dev, "%s(), id %d not support\n",
0233              __func__, dai->id);
0234         return -EINVAL;
0235     }
0236 
0237     return 0;
0238 }
0239 
0240 static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
0241     .hw_params = mtk_dai_pcm_hw_params,
0242 };
0243 
0244 /* dai driver */
0245 #define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
0246                SNDRV_PCM_RATE_16000 |\
0247                SNDRV_PCM_RATE_32000 |\
0248                SNDRV_PCM_RATE_48000)
0249 
0250 #define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
0251              SNDRV_PCM_FMTBIT_S24_LE |\
0252              SNDRV_PCM_FMTBIT_S32_LE)
0253 
0254 static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
0255     {
0256         .name = "PCM 1",
0257         .id = MT6797_DAI_PCM_1,
0258         .playback = {
0259             .stream_name = "PCM 1 Playback",
0260             .channels_min = 1,
0261             .channels_max = 2,
0262             .rates = MTK_PCM_RATES,
0263             .formats = MTK_PCM_FORMATS,
0264         },
0265         .capture = {
0266             .stream_name = "PCM 1 Capture",
0267             .channels_min = 1,
0268             .channels_max = 2,
0269             .rates = MTK_PCM_RATES,
0270             .formats = MTK_PCM_FORMATS,
0271         },
0272         .ops = &mtk_dai_pcm_ops,
0273         .symmetric_rate = 1,
0274         .symmetric_sample_bits = 1,
0275     },
0276     {
0277         .name = "PCM 2",
0278         .id = MT6797_DAI_PCM_2,
0279         .playback = {
0280             .stream_name = "PCM 2 Playback",
0281             .channels_min = 1,
0282             .channels_max = 2,
0283             .rates = MTK_PCM_RATES,
0284             .formats = MTK_PCM_FORMATS,
0285         },
0286         .capture = {
0287             .stream_name = "PCM 2 Capture",
0288             .channels_min = 1,
0289             .channels_max = 2,
0290             .rates = MTK_PCM_RATES,
0291             .formats = MTK_PCM_FORMATS,
0292         },
0293         .ops = &mtk_dai_pcm_ops,
0294         .symmetric_rate = 1,
0295         .symmetric_sample_bits = 1,
0296     },
0297 };
0298 
0299 int mt6797_dai_pcm_register(struct mtk_base_afe *afe)
0300 {
0301     struct mtk_base_afe_dai *dai;
0302 
0303     dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
0304     if (!dai)
0305         return -ENOMEM;
0306 
0307     list_add(&dai->list, &afe->sub_dais);
0308 
0309     dai->dai_drivers = mtk_dai_pcm_driver;
0310     dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
0311 
0312     dai->dapm_widgets = mtk_dai_pcm_widgets;
0313     dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
0314     dai->dapm_routes = mtk_dai_pcm_routes;
0315     dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
0316     return 0;
0317 }