Path: blob/master/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c
26488 views
// SPDX-License-Identifier: GPL-2.01/*2* MediaTek ALSA SoC Audio DAI DMIC I/F Control3*4* Copyright (c) 2020 MediaTek Inc.5* Author: Bicycle Tsai <[email protected]>6* Trevor Wu <[email protected]>7* Parker Yang <[email protected]>8*/910#include <linux/delay.h>11#include <linux/pm_runtime.h>12#include <linux/regmap.h>13#include <sound/pcm_params.h>14#include "mt8188-afe-clk.h"15#include "mt8188-afe-common.h"16#include "mt8188-reg.h"1718/* DMIC HW Gain configuration maximum value. */19#define DMIC_GAIN_MAX_STEP GENMASK(19, 0)20#define DMIC_GAIN_MAX_PER_STEP GENMASK(7, 0)21#define DMIC_GAIN_MAX_TARGET GENMASK(27, 0)22#define DMIC_GAIN_MAX_CURRENT GENMASK(27, 0)2324#define CLK_PHASE_SEL_CH1 025#define CLK_PHASE_SEL_CH2 ((CLK_PHASE_SEL_CH1) + 4)2627#define DMIC1_SRC_SEL 028#define DMIC2_SRC_SEL 029#define DMIC3_SRC_SEL 230#define DMIC4_SRC_SEL 031#define DMIC5_SRC_SEL 432#define DMIC6_SRC_SEL 033#define DMIC7_SRC_SEL 634#define DMIC8_SRC_SEL 03536enum {37SUPPLY_SEQ_DMIC_GAIN,38SUPPLY_SEQ_DMIC_CK,39};4041enum {42DMIC0,43DMIC1,44DMIC2,45DMIC3,46DMIC_NUM,47};4849struct mtk_dai_dmic_ctrl_reg {50unsigned int con0;51};5253struct mtk_dai_dmic_hw_gain_ctrl_reg {54unsigned int bypass;55unsigned int con0;56};5758struct mtk_dai_dmic_priv {59unsigned int gain_on[DMIC_NUM];60unsigned int channels;61bool hires_required;62};6364static const struct mtk_dai_dmic_ctrl_reg dmic_ctrl_regs[DMIC_NUM] = {65[DMIC0] = {66.con0 = AFE_DMIC0_UL_SRC_CON0,67},68[DMIC1] = {69.con0 = AFE_DMIC1_UL_SRC_CON0,70},71[DMIC2] = {72.con0 = AFE_DMIC2_UL_SRC_CON0,73},74[DMIC3] = {75.con0 = AFE_DMIC3_UL_SRC_CON0,76},77};7879static const struct mtk_dai_dmic_ctrl_reg *get_dmic_ctrl_reg(int id)80{81if (id < 0 || id >= DMIC_NUM)82return NULL;8384return &dmic_ctrl_regs[id];85}8687static const struct mtk_dai_dmic_hw_gain_ctrl_reg88dmic_hw_gain_ctrl_regs[DMIC_NUM] = {89[DMIC0] = {90.bypass = DMIC_BYPASS_HW_GAIN,91.con0 = DMIC_GAIN1_CON0,92},93[DMIC1] = {94.bypass = DMIC_BYPASS_HW_GAIN,95.con0 = DMIC_GAIN2_CON0,96},97[DMIC2] = {98.bypass = DMIC_BYPASS_HW_GAIN,99.con0 = DMIC_GAIN3_CON0,100},101[DMIC3] = {102.bypass = DMIC_BYPASS_HW_GAIN,103.con0 = DMIC_GAIN4_CON0,104},105};106107static const struct mtk_dai_dmic_hw_gain_ctrl_reg108*get_dmic_hw_gain_ctrl_reg(struct mtk_base_afe *afe, int id)109{110if ((id < 0) || (id >= DMIC_NUM)) {111dev_dbg(afe->dev, "%s invalid id\n", __func__);112return NULL;113}114115return &dmic_hw_gain_ctrl_regs[id];116}117118static void mtk_dai_dmic_hw_gain_bypass(struct mtk_base_afe *afe,119unsigned int id, bool bypass)120{121const struct mtk_dai_dmic_hw_gain_ctrl_reg *reg;122unsigned int msk;123124reg = get_dmic_hw_gain_ctrl_reg(afe, id);125if (!reg)126return;127128switch (id) {129case DMIC0:130msk = DMIC_BYPASS_HW_GAIN_DMIC1_BYPASS;131break;132case DMIC1:133msk = DMIC_BYPASS_HW_GAIN_DMIC2_BYPASS;134break;135case DMIC2:136msk = DMIC_BYPASS_HW_GAIN_DMIC3_BYPASS;137break;138case DMIC3:139msk = DMIC_BYPASS_HW_GAIN_DMIC4_BYPASS;140break;141default:142return;143}144145if (bypass)146regmap_set_bits(afe->regmap, reg->bypass, msk);147else148regmap_clear_bits(afe->regmap, reg->bypass, msk);149}150151static void mtk_dai_dmic_hw_gain_on(struct mtk_base_afe *afe, unsigned int id,152bool on)153{154const struct mtk_dai_dmic_hw_gain_ctrl_reg *reg = get_dmic_hw_gain_ctrl_reg(afe, id);155156if (!reg)157return;158159if (on)160regmap_set_bits(afe->regmap, reg->con0, DMIC_GAIN_CON0_GAIN_ON);161else162regmap_clear_bits(afe->regmap, reg->con0, DMIC_GAIN_CON0_GAIN_ON);163}164165static const struct reg_sequence mtk_dai_dmic_iir_coeff_reg_defaults[] = {166{ AFE_DMIC0_IIR_COEF_02_01, 0x00000000 },167{ AFE_DMIC0_IIR_COEF_04_03, 0x00003FB8 },168{ AFE_DMIC0_IIR_COEF_06_05, 0x3FB80000 },169{ AFE_DMIC0_IIR_COEF_08_07, 0x3FB80000 },170{ AFE_DMIC0_IIR_COEF_10_09, 0x0000C048 },171{ AFE_DMIC1_IIR_COEF_02_01, 0x00000000 },172{ AFE_DMIC1_IIR_COEF_04_03, 0x00003FB8 },173{ AFE_DMIC1_IIR_COEF_06_05, 0x3FB80000 },174{ AFE_DMIC1_IIR_COEF_08_07, 0x3FB80000 },175{ AFE_DMIC1_IIR_COEF_10_09, 0x0000C048 },176{ AFE_DMIC2_IIR_COEF_02_01, 0x00000000 },177{ AFE_DMIC2_IIR_COEF_04_03, 0x00003FB8 },178{ AFE_DMIC2_IIR_COEF_06_05, 0x3FB80000 },179{ AFE_DMIC2_IIR_COEF_08_07, 0x3FB80000 },180{ AFE_DMIC2_IIR_COEF_10_09, 0x0000C048 },181{ AFE_DMIC3_IIR_COEF_02_01, 0x00000000 },182{ AFE_DMIC3_IIR_COEF_04_03, 0x00003FB8 },183{ AFE_DMIC3_IIR_COEF_06_05, 0x3FB80000 },184{ AFE_DMIC3_IIR_COEF_08_07, 0x3FB80000 },185{ AFE_DMIC3_IIR_COEF_10_09, 0x0000C048 },186};187188static int mtk_dai_dmic_load_iir_coeff_table(struct mtk_base_afe *afe)189{190return regmap_multi_reg_write(afe->regmap,191mtk_dai_dmic_iir_coeff_reg_defaults,192ARRAY_SIZE(mtk_dai_dmic_iir_coeff_reg_defaults));193}194195static int mtk_dai_dmic_configure_array(struct snd_soc_dai *dai)196{197struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);198const u32 mask = PWR2_TOP_CON_DMIC8_SRC_SEL_MASK |199PWR2_TOP_CON_DMIC7_SRC_SEL_MASK |200PWR2_TOP_CON_DMIC6_SRC_SEL_MASK |201PWR2_TOP_CON_DMIC5_SRC_SEL_MASK |202PWR2_TOP_CON_DMIC4_SRC_SEL_MASK |203PWR2_TOP_CON_DMIC3_SRC_SEL_MASK |204PWR2_TOP_CON_DMIC2_SRC_SEL_MASK |205PWR2_TOP_CON_DMIC1_SRC_SEL_MASK;206const u32 val = PWR2_TOP_CON_DMIC8_SRC_SEL_VAL(DMIC8_SRC_SEL) |207PWR2_TOP_CON_DMIC7_SRC_SEL_VAL(DMIC7_SRC_SEL) |208PWR2_TOP_CON_DMIC6_SRC_SEL_VAL(DMIC6_SRC_SEL) |209PWR2_TOP_CON_DMIC5_SRC_SEL_VAL(DMIC5_SRC_SEL) |210PWR2_TOP_CON_DMIC4_SRC_SEL_VAL(DMIC4_SRC_SEL) |211PWR2_TOP_CON_DMIC3_SRC_SEL_VAL(DMIC3_SRC_SEL) |212PWR2_TOP_CON_DMIC2_SRC_SEL_VAL(DMIC2_SRC_SEL) |213PWR2_TOP_CON_DMIC1_SRC_SEL_VAL(DMIC1_SRC_SEL);214215return regmap_update_bits(afe->regmap, PWR2_TOP_CON0, mask, val);216}217218/* This function assumes that the caller checked that channels is valid */219static u8 mtk_dmic_channels_to_dmic_number(unsigned int channels)220{221switch (channels) {222case 1:223return DMIC0;224case 2:225return DMIC1;226case 3:227return DMIC2;228case 4:229default:230return DMIC3;231}232}233234static void mtk_dai_dmic_hw_gain_enable(struct mtk_base_afe *afe,235unsigned int channels, bool enable)236{237struct mt8188_afe_private *afe_priv = afe->platform_priv;238struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];239u8 dmic_num;240int i;241242dmic_num = mtk_dmic_channels_to_dmic_number(channels);243for (i = dmic_num; i >= DMIC0; i--) {244if (enable && dmic_priv->gain_on[i]) {245mtk_dai_dmic_hw_gain_bypass(afe, i, false);246mtk_dai_dmic_hw_gain_on(afe, i, true);247} else {248mtk_dai_dmic_hw_gain_on(afe, i, false);249mtk_dai_dmic_hw_gain_bypass(afe, i, true);250}251}252}253254static int mtk_dmic_gain_event(struct snd_soc_dapm_widget *w,255struct snd_kcontrol *kcontrol,256int event)257{258struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);259struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);260struct mt8188_afe_private *afe_priv = afe->platform_priv;261struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];262unsigned int channels = dmic_priv->channels;263264dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",265__func__, w->name, event);266267if (!channels)268return -EINVAL;269270switch (event) {271case SND_SOC_DAPM_PRE_PMU:272mtk_dai_dmic_hw_gain_enable(afe, channels, true);273break;274case SND_SOC_DAPM_POST_PMD:275mtk_dai_dmic_hw_gain_enable(afe, channels, false);276break;277default:278break;279}280281return 0;282}283284static int mtk_dmic_event(struct snd_soc_dapm_widget *w,285struct snd_kcontrol *kcontrol,286int event)287{288struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);289struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);290struct mt8188_afe_private *afe_priv = afe->platform_priv;291struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];292const struct mtk_dai_dmic_ctrl_reg *reg = NULL;293unsigned int channels = dmic_priv->channels;294unsigned int msk;295u8 dmic_num;296int i;297298dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",299__func__, w->name, event);300301if (!channels)302return -EINVAL;303304dmic_num = mtk_dmic_channels_to_dmic_number(channels);305306switch (event) {307case SND_SOC_DAPM_PRE_PMU:308/* request fifo soft rst */309msk = 0;310for (i = dmic_num; i >= DMIC0; i--)311msk |= PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(i);312313regmap_set_bits(afe->regmap, PWR2_TOP_CON1, msk);314315msk = AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL |316AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL |317AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL |318AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL;319320for (i = dmic_num; i >= DMIC0; i--) {321reg = get_dmic_ctrl_reg(i);322if (reg)323regmap_set_bits(afe->regmap, reg->con0, msk);324}325break;326case SND_SOC_DAPM_POST_PMU:327msk = AFE_DMIC_UL_SRC_CON0_UL_SRC_ON_TMP_CTL;328329for (i = dmic_num; i >= DMIC0; i--) {330reg = get_dmic_ctrl_reg(i);331if (reg)332regmap_set_bits(afe->regmap, reg->con0, msk);333}334335if (dmic_priv->hires_required) {336mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES1]);337mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES2]);338mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES3]);339mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES4]);340}341342mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC1]);343mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC2]);344mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC3]);345mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC4]);346347/* release fifo soft rst */348msk = 0;349for (i = dmic_num; i >= DMIC0; i--)350msk |= PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(i);351352regmap_clear_bits(afe->regmap, PWR2_TOP_CON1, msk);353break;354case SND_SOC_DAPM_PRE_PMD:355msk = AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL |356AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL |357AFE_DMIC_UL_SRC_CON0_UL_SRC_ON_TMP_CTL |358AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL |359AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL;360361for (i = dmic_num; i >= DMIC0; i--) {362reg = get_dmic_ctrl_reg(i);363if (reg)364regmap_set_bits(afe->regmap, reg->con0, msk);365}366break;367case SND_SOC_DAPM_POST_PMD:368/* should delayed 1/fs(smallest is 8k) = 125us before afe off */369usleep_range(125, 126);370371mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC1]);372mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC2]);373mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC3]);374mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC4]);375376if (dmic_priv->hires_required) {377mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES1]);378mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES2]);379mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES3]);380mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES4]);381}382break;383default:384break;385}386387return 0;388}389390static int mtk_dai_dmic_hw_params(struct snd_pcm_substream *substream,391struct snd_pcm_hw_params *params,392struct snd_soc_dai *dai)393{394struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);395struct mt8188_afe_private *afe_priv = afe->platform_priv;396struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];397unsigned int rate = params_rate(params);398unsigned int channels = params_channels(params);399const struct mtk_dai_dmic_ctrl_reg *reg = NULL;400u32 val = AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_CH1(CLK_PHASE_SEL_CH1) |401AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_CH2(CLK_PHASE_SEL_CH2) |402AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL(0);403const u32 msk = AFE_DMIC_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL |404AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_MASK |405AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL_MASK |406AFE_DMIC_UL_VOICE_MODE_MASK;407u8 dmic_num;408int ret;409int i;410411if (!channels || channels > 8)412return -EINVAL;413414ret = mtk_dai_dmic_configure_array(dai);415if (ret < 0)416return ret;417418ret = mtk_dai_dmic_load_iir_coeff_table(afe);419if (ret < 0)420return ret;421422switch (rate) {423case 96000:424val |= AFE_DMIC_UL_CON0_VOCIE_MODE_96K;425dmic_priv->hires_required = 1;426break;427case 48000:428val |= AFE_DMIC_UL_CON0_VOCIE_MODE_48K;429dmic_priv->hires_required = 0;430break;431case 32000:432val |= AFE_DMIC_UL_CON0_VOCIE_MODE_32K;433dmic_priv->hires_required = 0;434break;435case 16000:436val |= AFE_DMIC_UL_CON0_VOCIE_MODE_16K;437dmic_priv->hires_required = 0;438break;439case 8000:440val |= AFE_DMIC_UL_CON0_VOCIE_MODE_8K;441dmic_priv->hires_required = 0;442break;443default:444dev_dbg(afe->dev, "%s invalid rate %u, use 48000Hz\n", __func__, rate);445val |= AFE_DMIC_UL_CON0_VOCIE_MODE_48K;446dmic_priv->hires_required = 0;447break;448}449450dmic_num = mtk_dmic_channels_to_dmic_number(channels);451for (i = dmic_num; i >= DMIC0; i--) {452reg = get_dmic_ctrl_reg(i);453if (reg) {454ret = regmap_update_bits(afe->regmap, reg->con0, msk, val);455if (ret < 0)456return ret;457}458}459460dmic_priv->channels = channels;461462return 0;463}464465static const struct snd_soc_dai_ops mtk_dai_dmic_ops = {466.hw_params = mtk_dai_dmic_hw_params,467};468469#define MTK_DMIC_RATES (SNDRV_PCM_RATE_8000 |\470SNDRV_PCM_RATE_16000 |\471SNDRV_PCM_RATE_32000 |\472SNDRV_PCM_RATE_48000 |\473SNDRV_PCM_RATE_96000)474475#define MTK_DMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\476SNDRV_PCM_FMTBIT_S32_LE)477478static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {479{480.name = "DMIC",481.id = MT8188_AFE_IO_DMIC_IN,482.capture = {483.stream_name = "DMIC Capture",484.channels_min = 1,485.channels_max = 8,486.rates = MTK_DMIC_RATES,487.formats = MTK_DMIC_FORMATS,488},489.ops = &mtk_dai_dmic_ops,490},491};492493static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {494SND_SOC_DAPM_MIXER("I004", SND_SOC_NOPM, 0, 0, NULL, 0),495SND_SOC_DAPM_MIXER("I005", SND_SOC_NOPM, 0, 0, NULL, 0),496SND_SOC_DAPM_MIXER("I006", SND_SOC_NOPM, 0, 0, NULL, 0),497SND_SOC_DAPM_MIXER("I007", SND_SOC_NOPM, 0, 0, NULL, 0),498SND_SOC_DAPM_MIXER("I008", SND_SOC_NOPM, 0, 0, NULL, 0),499SND_SOC_DAPM_MIXER("I009", SND_SOC_NOPM, 0, 0, NULL, 0),500SND_SOC_DAPM_MIXER("I010", SND_SOC_NOPM, 0, 0, NULL, 0),501SND_SOC_DAPM_MIXER("I011", SND_SOC_NOPM, 0, 0, NULL, 0),502503SND_SOC_DAPM_SUPPLY_S("DMIC_GAIN_ON", SUPPLY_SEQ_DMIC_GAIN,504SND_SOC_NOPM, 0, 0,505mtk_dmic_gain_event,506SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),507SND_SOC_DAPM_SUPPLY_S("DMIC_CK_ON", SUPPLY_SEQ_DMIC_CK,508PWR2_TOP_CON1,509PWR2_TOP_CON1_DMIC_CKDIV_ON_SHIFT, 0,510mtk_dmic_event,511SND_SOC_DAPM_PRE_POST_PMU |512SND_SOC_DAPM_PRE_POST_PMD),513SND_SOC_DAPM_INPUT("DMIC_INPUT"),514};515516static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {517{"I004", NULL, "DMIC Capture"},518{"I005", NULL, "DMIC Capture"},519{"I006", NULL, "DMIC Capture"},520{"I007", NULL, "DMIC Capture"},521{"I008", NULL, "DMIC Capture"},522{"I009", NULL, "DMIC Capture"},523{"I010", NULL, "DMIC Capture"},524{"I011", NULL, "DMIC Capture"},525{"DMIC Capture", NULL, "DMIC_CK_ON"},526{"DMIC Capture", NULL, "DMIC_GAIN_ON"},527{"DMIC Capture", NULL, "DMIC_INPUT"},528};529530static const char * const mt8188_dmic_gain_enable_text[] = {531"Bypass", "Connect",532};533534static SOC_ENUM_SINGLE_EXT_DECL(dmic_gain_on_enum,535mt8188_dmic_gain_enable_text);536537static int mtk_dai_dmic_hw_gain_ctrl_put(struct snd_kcontrol *kcontrol,538struct snd_ctl_elem_value *ucontrol)539{540struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);541struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;542struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);543struct mt8188_afe_private *afe_priv = afe->platform_priv;544struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];545unsigned int source = ucontrol->value.enumerated.item[0];546unsigned int *cached;547548if (source >= e->items)549return -EINVAL;550551if (!strcmp(kcontrol->id.name, "DMIC1_HW_GAIN_EN"))552cached = &dmic_priv->gain_on[0];553else if (!strcmp(kcontrol->id.name, "DMIC2_HW_GAIN_EN"))554cached = &dmic_priv->gain_on[1];555else if (!strcmp(kcontrol->id.name, "DMIC3_HW_GAIN_EN"))556cached = &dmic_priv->gain_on[2];557else if (!strcmp(kcontrol->id.name, "DMIC4_HW_GAIN_EN"))558cached = &dmic_priv->gain_on[3];559else560return -EINVAL;561562if (source == *cached)563return 0;564565*cached = source;566return 1;567}568569static int mtk_dai_dmic_hw_gain_ctrl_get(struct snd_kcontrol *kcontrol,570struct snd_ctl_elem_value *ucontrol)571{572struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);573struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);574struct mt8188_afe_private *afe_priv = afe->platform_priv;575struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];576unsigned int val;577578if (!strcmp(kcontrol->id.name, "DMIC1_HW_GAIN_EN"))579val = dmic_priv->gain_on[0];580else if (!strcmp(kcontrol->id.name, "DMIC2_HW_GAIN_EN"))581val = dmic_priv->gain_on[1];582else if (!strcmp(kcontrol->id.name, "DMIC3_HW_GAIN_EN"))583val = dmic_priv->gain_on[2];584else if (!strcmp(kcontrol->id.name, "DMIC4_HW_GAIN_EN"))585val = dmic_priv->gain_on[3];586else587return -EINVAL;588589ucontrol->value.enumerated.item[0] = val;590return 0;591}592593static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {594SOC_ENUM_EXT("DMIC1_HW_GAIN_EN", dmic_gain_on_enum,595mtk_dai_dmic_hw_gain_ctrl_get,596mtk_dai_dmic_hw_gain_ctrl_put),597SOC_ENUM_EXT("DMIC2_HW_GAIN_EN", dmic_gain_on_enum,598mtk_dai_dmic_hw_gain_ctrl_get,599mtk_dai_dmic_hw_gain_ctrl_put),600SOC_ENUM_EXT("DMIC3_HW_GAIN_EN", dmic_gain_on_enum,601mtk_dai_dmic_hw_gain_ctrl_get,602mtk_dai_dmic_hw_gain_ctrl_put),603SOC_ENUM_EXT("DMIC4_HW_GAIN_EN", dmic_gain_on_enum,604mtk_dai_dmic_hw_gain_ctrl_get,605mtk_dai_dmic_hw_gain_ctrl_put),606SOC_SINGLE("DMIC1_HW_GAIN_TARGET", DMIC_GAIN1_CON1,6070, DMIC_GAIN_MAX_TARGET, 0),608SOC_SINGLE("DMIC2_HW_GAIN_TARGET", DMIC_GAIN2_CON1,6090, DMIC_GAIN_MAX_TARGET, 0),610SOC_SINGLE("DMIC3_HW_GAIN_TARGET", DMIC_GAIN3_CON1,6110, DMIC_GAIN_MAX_TARGET, 0),612SOC_SINGLE("DMIC4_HW_GAIN_TARGET", DMIC_GAIN4_CON1,6130, DMIC_GAIN_MAX_TARGET, 0),614SOC_SINGLE("DMIC1_HW_GAIN_CURRENT", DMIC_GAIN1_CUR,6150, DMIC_GAIN_MAX_CURRENT, 0),616SOC_SINGLE("DMIC2_HW_GAIN_CURRENT", DMIC_GAIN2_CUR,6170, DMIC_GAIN_MAX_CURRENT, 0),618SOC_SINGLE("DMIC3_HW_GAIN_CURRENT", DMIC_GAIN3_CUR,6190, DMIC_GAIN_MAX_CURRENT, 0),620SOC_SINGLE("DMIC4_HW_GAIN_CURRENT", DMIC_GAIN4_CUR,6210, DMIC_GAIN_MAX_CURRENT, 0),622SOC_SINGLE("DMIC1_HW_GAIN_UP_STEP", DMIC_GAIN1_CON3,6230, DMIC_GAIN_MAX_STEP, 0),624SOC_SINGLE("DMIC2_HW_GAIN_UP_STEP", DMIC_GAIN2_CON3,6250, DMIC_GAIN_MAX_STEP, 0),626SOC_SINGLE("DMIC3_HW_GAIN_UP_STEP", DMIC_GAIN3_CON3,6270, DMIC_GAIN_MAX_STEP, 0),628SOC_SINGLE("DMIC4_HW_GAIN_UP_STEP", DMIC_GAIN4_CON3,6290, DMIC_GAIN_MAX_STEP, 0),630SOC_SINGLE("DMIC1_HW_GAIN_DOWN_STEP", DMIC_GAIN1_CON2,6310, DMIC_GAIN_MAX_STEP, 0),632SOC_SINGLE("DMIC2_HW_GAIN_DOWN_STEP", DMIC_GAIN2_CON2,6330, DMIC_GAIN_MAX_STEP, 0),634SOC_SINGLE("DMIC3_HW_GAIN_DOWN_STEP", DMIC_GAIN3_CON2,6350, DMIC_GAIN_MAX_STEP, 0),636SOC_SINGLE("DMIC4_HW_GAIN_DOWN_STEP", DMIC_GAIN4_CON2,6370, DMIC_GAIN_MAX_STEP, 0),638SOC_SINGLE("DMIC1_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN1_CON0,639DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),640SOC_SINGLE("DMIC2_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN2_CON0,641DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),642SOC_SINGLE("DMIC3_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN3_CON0,643DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),644SOC_SINGLE("DMIC4_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN4_CON0,645DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),646};647648static int init_dmic_priv_data(struct mtk_base_afe *afe)649{650struct mt8188_afe_private *afe_priv = afe->platform_priv;651struct mtk_dai_dmic_priv *dmic_priv;652653dmic_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_dmic_priv),654GFP_KERNEL);655if (!dmic_priv)656return -ENOMEM;657658afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN] = dmic_priv;659return 0;660}661662int mt8188_dai_dmic_register(struct mtk_base_afe *afe)663{664struct mtk_base_afe_dai *dai;665666dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);667if (!dai)668return -ENOMEM;669670list_add(&dai->list, &afe->sub_dais);671672dai->dai_drivers = mtk_dai_dmic_driver;673dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver);674dai->dapm_widgets = mtk_dai_dmic_widgets;675dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets);676dai->dapm_routes = mtk_dai_dmic_routes;677dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes);678dai->controls = mtk_dai_dmic_controls;679dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);680681return init_dmic_priv_data(afe);682}683684685