Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // MediaTek ALSA SoC Audio DAI HW Gain Control
0004 //
0005 // Copyright (c) 2022 MediaTek Inc.
0006 // Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
0007 
0008 #include <linux/regmap.h>
0009 #include "mt8186-afe-common.h"
0010 #include "mt8186-interconnection.h"
0011 
0012 #define HW_GAIN_1_EN_W_NAME "HW GAIN 1 Enable"
0013 #define HW_GAIN_2_EN_W_NAME "HW GAIN 2 Enable"
0014 
0015 /* dai component */
0016 static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
0017     SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13_1,
0018                     I_CONNSYS_I2S_CH1, 1, 0),
0019 };
0020 
0021 static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
0022     SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14_1,
0023                     I_CONNSYS_I2S_CH2, 1, 0),
0024 };
0025 
0026 static const struct snd_kcontrol_new mtk_hw_gain2_in_ch1_mix[] = {
0027     SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN15,
0028                     I_ADDA_UL_CH1, 1, 0),
0029 };
0030 
0031 static const struct snd_kcontrol_new mtk_hw_gain2_in_ch2_mix[] = {
0032     SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN16,
0033                     I_ADDA_UL_CH2, 1, 0),
0034 };
0035 
0036 static int mtk_hw_gain_event(struct snd_soc_dapm_widget *w,
0037                  struct snd_kcontrol *kcontrol,
0038                  int event)
0039 {
0040     struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
0041     struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
0042     unsigned int gain_cur;
0043     unsigned int gain_con1;
0044 
0045     dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
0046         __func__, w->name, event);
0047 
0048     switch (event) {
0049     case SND_SOC_DAPM_PRE_PMU:
0050         if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) {
0051             gain_cur = AFE_GAIN1_CUR;
0052             gain_con1 = AFE_GAIN1_CON1;
0053         } else {
0054             gain_cur = AFE_GAIN2_CUR;
0055             gain_con1 = AFE_GAIN2_CON1;
0056         }
0057 
0058         /* let hw gain ramp up, set cur gain to 0 */
0059         regmap_update_bits(afe->regmap, gain_cur, AFE_GAIN1_CUR_MASK_SFT, 0);
0060 
0061         /* set target gain to 0 */
0062         regmap_update_bits(afe->regmap, gain_con1, GAIN1_TARGET_MASK_SFT, 0);
0063         break;
0064     default:
0065         break;
0066     }
0067 
0068     return 0;
0069 }
0070 
0071 static const struct snd_soc_dapm_widget mtk_dai_hw_gain_widgets[] = {
0072     /* inter-connections */
0073     SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0,
0074                mtk_hw_gain1_in_ch1_mix,
0075                ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)),
0076     SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0,
0077                mtk_hw_gain1_in_ch2_mix,
0078                ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)),
0079     SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH1", SND_SOC_NOPM, 0, 0,
0080                mtk_hw_gain2_in_ch1_mix,
0081                ARRAY_SIZE(mtk_hw_gain2_in_ch1_mix)),
0082     SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH2", SND_SOC_NOPM, 0, 0,
0083                mtk_hw_gain2_in_ch2_mix,
0084                ARRAY_SIZE(mtk_hw_gain2_in_ch2_mix)),
0085 
0086     SND_SOC_DAPM_SUPPLY(HW_GAIN_1_EN_W_NAME,
0087                 AFE_GAIN1_CON0, GAIN1_ON_SFT, 0,
0088                 mtk_hw_gain_event,
0089                 SND_SOC_DAPM_PRE_PMU),
0090 
0091     SND_SOC_DAPM_SUPPLY(HW_GAIN_2_EN_W_NAME,
0092                 AFE_GAIN2_CON0, GAIN2_ON_SFT, 0,
0093                 mtk_hw_gain_event,
0094                 SND_SOC_DAPM_PRE_PMU),
0095 
0096     SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
0097     SND_SOC_DAPM_INPUT("HW Gain 2 Out Endpoint"),
0098     SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
0099 };
0100 
0101 static const struct snd_soc_dapm_route mtk_dai_hw_gain_routes[] = {
0102     {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
0103     {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
0104     {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH1"},
0105     {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH2"},
0106 
0107     {"HW Gain 1 In", NULL, HW_GAIN_1_EN_W_NAME},
0108     {"HW Gain 1 Out", NULL, HW_GAIN_1_EN_W_NAME},
0109     {"HW Gain 2 In", NULL, HW_GAIN_2_EN_W_NAME},
0110     {"HW Gain 2 Out", NULL, HW_GAIN_2_EN_W_NAME},
0111 
0112     {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
0113     {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
0114     {"HW Gain 2 Out", NULL, "HW Gain 2 Out Endpoint"},
0115 };
0116 
0117 static const struct snd_kcontrol_new mtk_hw_gain_controls[] = {
0118     SOC_SINGLE("HW Gain 1 Volume", AFE_GAIN1_CON1,
0119            GAIN1_TARGET_SFT, GAIN1_TARGET_MASK, 0),
0120     SOC_SINGLE("HW Gain 2 Volume", AFE_GAIN2_CON1,
0121            GAIN2_TARGET_SFT, GAIN2_TARGET_MASK, 0),
0122 };
0123 
0124 /* dai ops */
0125 static int mtk_dai_gain_hw_params(struct snd_pcm_substream *substream,
0126                   struct snd_pcm_hw_params *params,
0127                   struct snd_soc_dai *dai)
0128 {
0129     struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
0130     unsigned int rate = params_rate(params);
0131     unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
0132 
0133     dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
0134         __func__, dai->id, substream->stream, rate);
0135 
0136     /* rate */
0137     regmap_update_bits(afe->regmap,
0138                dai->id == MT8186_DAI_HW_GAIN_1 ?
0139                AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
0140                GAIN1_MODE_MASK_SFT,
0141                rate_reg << GAIN1_MODE_SFT);
0142 
0143     /* sample per step */
0144     regmap_update_bits(afe->regmap,
0145                dai->id == MT8186_DAI_HW_GAIN_1 ?
0146                AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
0147                GAIN1_SAMPLE_PER_STEP_MASK_SFT,
0148                (dai->id == MT8186_DAI_HW_GAIN_1 ? 0x40 : 0x0) <<
0149                GAIN1_SAMPLE_PER_STEP_SFT);
0150 
0151     return 0;
0152 }
0153 
0154 static const struct snd_soc_dai_ops mtk_dai_gain_ops = {
0155     .hw_params = mtk_dai_gain_hw_params,
0156 };
0157 
0158 /* dai driver */
0159 #define MTK_HW_GAIN_RATES (SNDRV_PCM_RATE_8000_48000 |\
0160                SNDRV_PCM_RATE_88200 |\
0161                SNDRV_PCM_RATE_96000 |\
0162                SNDRV_PCM_RATE_176400 |\
0163                SNDRV_PCM_RATE_192000)
0164 
0165 #define MTK_HW_GAIN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
0166                  SNDRV_PCM_FMTBIT_S24_LE |\
0167                  SNDRV_PCM_FMTBIT_S32_LE)
0168 
0169 static struct snd_soc_dai_driver mtk_dai_gain_driver[] = {
0170     {
0171         .name = "HW Gain 1",
0172         .id = MT8186_DAI_HW_GAIN_1,
0173         .playback = {
0174             .stream_name = "HW Gain 1 In",
0175             .channels_min = 1,
0176             .channels_max = 2,
0177             .rates = MTK_HW_GAIN_RATES,
0178             .formats = MTK_HW_GAIN_FORMATS,
0179         },
0180         .capture = {
0181             .stream_name = "HW Gain 1 Out",
0182             .channels_min = 1,
0183             .channels_max = 2,
0184             .rates = MTK_HW_GAIN_RATES,
0185             .formats = MTK_HW_GAIN_FORMATS,
0186         },
0187         .ops = &mtk_dai_gain_ops,
0188         .symmetric_rate = 1,
0189         .symmetric_channels = 1,
0190         .symmetric_sample_bits = 1,
0191     },
0192     {
0193         .name = "HW Gain 2",
0194         .id = MT8186_DAI_HW_GAIN_2,
0195         .playback = {
0196             .stream_name = "HW Gain 2 In",
0197             .channels_min = 1,
0198             .channels_max = 2,
0199             .rates = MTK_HW_GAIN_RATES,
0200             .formats = MTK_HW_GAIN_FORMATS,
0201         },
0202         .capture = {
0203             .stream_name = "HW Gain 2 Out",
0204             .channels_min = 1,
0205             .channels_max = 2,
0206             .rates = MTK_HW_GAIN_RATES,
0207             .formats = MTK_HW_GAIN_FORMATS,
0208         },
0209         .ops = &mtk_dai_gain_ops,
0210         .symmetric_rate = 1,
0211         .symmetric_channels = 1,
0212         .symmetric_sample_bits = 1,
0213     },
0214 };
0215 
0216 int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe)
0217 {
0218     struct mtk_base_afe_dai *dai;
0219 
0220     dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
0221     if (!dai)
0222         return -ENOMEM;
0223 
0224     list_add(&dai->list, &afe->sub_dais);
0225 
0226     dai->dai_drivers = mtk_dai_gain_driver;
0227     dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_gain_driver);
0228 
0229     dai->controls = mtk_hw_gain_controls;
0230     dai->num_controls = ARRAY_SIZE(mtk_hw_gain_controls);
0231     dai->dapm_widgets = mtk_dai_hw_gain_widgets;
0232     dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_hw_gain_widgets);
0233     dai->dapm_routes = mtk_dai_hw_gain_routes;
0234     dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hw_gain_routes);
0235     return 0;
0236 }