147a70e6fSCosmin Samoila // SPDX-License-Identifier: GPL-2.0 247a70e6fSCosmin Samoila // Copyright 2018 NXP 347a70e6fSCosmin Samoila 417f2142bSSascha Hauer #include <linux/bitfield.h> 547a70e6fSCosmin Samoila #include <linux/clk.h> 647a70e6fSCosmin Samoila #include <linux/device.h> 747a70e6fSCosmin Samoila #include <linux/interrupt.h> 847a70e6fSCosmin Samoila #include <linux/kobject.h> 947a70e6fSCosmin Samoila #include <linux/kernel.h> 1047a70e6fSCosmin Samoila #include <linux/module.h> 1147a70e6fSCosmin Samoila #include <linux/of.h> 1247a70e6fSCosmin Samoila #include <linux/of_address.h> 1347a70e6fSCosmin Samoila #include <linux/of_irq.h> 1447a70e6fSCosmin Samoila #include <linux/of_platform.h> 1547a70e6fSCosmin Samoila #include <linux/pm_runtime.h> 1647a70e6fSCosmin Samoila #include <linux/regmap.h> 1747a70e6fSCosmin Samoila #include <linux/sysfs.h> 1847a70e6fSCosmin Samoila #include <linux/types.h> 192495ba26SSascha Hauer #include <linux/dma/imx-dma.h> 2047a70e6fSCosmin Samoila #include <sound/dmaengine_pcm.h> 2147a70e6fSCosmin Samoila #include <sound/pcm.h> 2247a70e6fSCosmin Samoila #include <sound/soc.h> 2347a70e6fSCosmin Samoila #include <sound/tlv.h> 2447a70e6fSCosmin Samoila #include <sound/core.h> 2547a70e6fSCosmin Samoila 2647a70e6fSCosmin Samoila #include "fsl_micfil.h" 2793f54100SShengjiu Wang #include "fsl_utils.h" 2847a70e6fSCosmin Samoila 29fb855b8dSSascha Hauer #define MICFIL_OSR_DEFAULT 16 30fb855b8dSSascha Hauer 31bea1d61dSSascha Hauer enum quality { 32bea1d61dSSascha Hauer QUALITY_HIGH, 33bea1d61dSSascha Hauer QUALITY_MEDIUM, 34bea1d61dSSascha Hauer QUALITY_LOW, 35bea1d61dSSascha Hauer QUALITY_VLOW0, 36bea1d61dSSascha Hauer QUALITY_VLOW1, 37bea1d61dSSascha Hauer QUALITY_VLOW2, 38bea1d61dSSascha Hauer }; 39bea1d61dSSascha Hauer 4047a70e6fSCosmin Samoila struct fsl_micfil { 4147a70e6fSCosmin Samoila struct platform_device *pdev; 4247a70e6fSCosmin Samoila struct regmap *regmap; 4347a70e6fSCosmin Samoila const struct fsl_micfil_soc_data *soc; 44b5cf28f7SShengjiu Wang struct clk *busclk; 4547a70e6fSCosmin Samoila struct clk *mclk; 4693f54100SShengjiu Wang struct clk *pll8k_clk; 4793f54100SShengjiu Wang struct clk *pll11k_clk; 4847a70e6fSCosmin Samoila struct snd_dmaengine_dai_dma_data dma_params_rx; 492495ba26SSascha Hauer struct sdma_peripheral_config sdmacfg; 5029dbfeecSShengjiu Wang struct snd_soc_card *card; 5147a70e6fSCosmin Samoila unsigned int dataline; 5247a70e6fSCosmin Samoila char name[32]; 5347a70e6fSCosmin Samoila int irq[MICFIL_IRQ_LINES]; 54bea1d61dSSascha Hauer enum quality quality; 553b13b143SShengjiu Wang int dc_remover; 5629dbfeecSShengjiu Wang int vad_init_mode; 5729dbfeecSShengjiu Wang int vad_enabled; 5829dbfeecSShengjiu Wang int vad_detected; 5936736505SChancel Liu struct fsl_micfil_verid verid; 6036736505SChancel Liu struct fsl_micfil_param param; 6147a70e6fSCosmin Samoila }; 6247a70e6fSCosmin Samoila 6347a70e6fSCosmin Samoila struct fsl_micfil_soc_data { 6447a70e6fSCosmin Samoila unsigned int fifos; 6547a70e6fSCosmin Samoila unsigned int fifo_depth; 6647a70e6fSCosmin Samoila unsigned int dataline; 6747a70e6fSCosmin Samoila bool imx; 6877a7a6e9SChancel Liu bool use_edma; 6936736505SChancel Liu bool use_verid; 70cb05dac1SShengjiu Wang u64 formats; 7147a70e6fSCosmin Samoila }; 7247a70e6fSCosmin Samoila 7347a70e6fSCosmin Samoila static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { 7447a70e6fSCosmin Samoila .imx = true, 7547a70e6fSCosmin Samoila .fifos = 8, 7647a70e6fSCosmin Samoila .fifo_depth = 8, 7747a70e6fSCosmin Samoila .dataline = 0xf, 78cb05dac1SShengjiu Wang .formats = SNDRV_PCM_FMTBIT_S16_LE, 79cb05dac1SShengjiu Wang }; 80cb05dac1SShengjiu Wang 81cb05dac1SShengjiu Wang static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { 82cb05dac1SShengjiu Wang .imx = true, 83cb05dac1SShengjiu Wang .fifos = 8, 84cb05dac1SShengjiu Wang .fifo_depth = 32, 85cb05dac1SShengjiu Wang .dataline = 0xf, 86cb05dac1SShengjiu Wang .formats = SNDRV_PCM_FMTBIT_S32_LE, 8747a70e6fSCosmin Samoila }; 8847a70e6fSCosmin Samoila 89a10a5254SChancel Liu static struct fsl_micfil_soc_data fsl_micfil_imx93 = { 90a10a5254SChancel Liu .imx = true, 91a10a5254SChancel Liu .fifos = 8, 92a10a5254SChancel Liu .fifo_depth = 32, 93a10a5254SChancel Liu .dataline = 0xf, 94a10a5254SChancel Liu .formats = SNDRV_PCM_FMTBIT_S32_LE, 9577a7a6e9SChancel Liu .use_edma = true, 9636736505SChancel Liu .use_verid = true, 97a10a5254SChancel Liu }; 98a10a5254SChancel Liu 9947a70e6fSCosmin Samoila static const struct of_device_id fsl_micfil_dt_ids[] = { 10047a70e6fSCosmin Samoila { .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm }, 101cb05dac1SShengjiu Wang { .compatible = "fsl,imx8mp-micfil", .data = &fsl_micfil_imx8mp }, 102a10a5254SChancel Liu { .compatible = "fsl,imx93-micfil", .data = &fsl_micfil_imx93 }, 10347a70e6fSCosmin Samoila {} 10447a70e6fSCosmin Samoila }; 10547a70e6fSCosmin Samoila MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids); 10647a70e6fSCosmin Samoila 10747a70e6fSCosmin Samoila static const char * const micfil_quality_select_texts[] = { 108bea1d61dSSascha Hauer [QUALITY_HIGH] = "High", 109bea1d61dSSascha Hauer [QUALITY_MEDIUM] = "Medium", 110bea1d61dSSascha Hauer [QUALITY_LOW] = "Low", 111bea1d61dSSascha Hauer [QUALITY_VLOW0] = "VLow0", 112bea1d61dSSascha Hauer [QUALITY_VLOW1] = "Vlow1", 113bea1d61dSSascha Hauer [QUALITY_VLOW2] = "Vlow2", 11447a70e6fSCosmin Samoila }; 11547a70e6fSCosmin Samoila 11647a70e6fSCosmin Samoila static const struct soc_enum fsl_micfil_quality_enum = 117bea1d61dSSascha Hauer SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_quality_select_texts), 11847a70e6fSCosmin Samoila micfil_quality_select_texts); 11947a70e6fSCosmin Samoila 12047a70e6fSCosmin Samoila static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); 12147a70e6fSCosmin Samoila 122bea1d61dSSascha Hauer static int micfil_set_quality(struct fsl_micfil *micfil) 123bea1d61dSSascha Hauer { 124bea1d61dSSascha Hauer u32 qsel; 125bea1d61dSSascha Hauer 126bea1d61dSSascha Hauer switch (micfil->quality) { 127bea1d61dSSascha Hauer case QUALITY_HIGH: 128bea1d61dSSascha Hauer qsel = MICFIL_QSEL_HIGH_QUALITY; 129bea1d61dSSascha Hauer break; 130bea1d61dSSascha Hauer case QUALITY_MEDIUM: 131bea1d61dSSascha Hauer qsel = MICFIL_QSEL_MEDIUM_QUALITY; 132bea1d61dSSascha Hauer break; 133bea1d61dSSascha Hauer case QUALITY_LOW: 134bea1d61dSSascha Hauer qsel = MICFIL_QSEL_LOW_QUALITY; 135bea1d61dSSascha Hauer break; 136bea1d61dSSascha Hauer case QUALITY_VLOW0: 137bea1d61dSSascha Hauer qsel = MICFIL_QSEL_VLOW0_QUALITY; 138bea1d61dSSascha Hauer break; 139bea1d61dSSascha Hauer case QUALITY_VLOW1: 140bea1d61dSSascha Hauer qsel = MICFIL_QSEL_VLOW1_QUALITY; 141bea1d61dSSascha Hauer break; 142bea1d61dSSascha Hauer case QUALITY_VLOW2: 143bea1d61dSSascha Hauer qsel = MICFIL_QSEL_VLOW2_QUALITY; 144bea1d61dSSascha Hauer break; 145bea1d61dSSascha Hauer } 146bea1d61dSSascha Hauer 147bea1d61dSSascha Hauer return regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, 148bea1d61dSSascha Hauer MICFIL_CTRL2_QSEL, 149bea1d61dSSascha Hauer FIELD_PREP(MICFIL_CTRL2_QSEL, qsel)); 150bea1d61dSSascha Hauer } 151bea1d61dSSascha Hauer 152bea1d61dSSascha Hauer static int micfil_quality_get(struct snd_kcontrol *kcontrol, 153bea1d61dSSascha Hauer struct snd_ctl_elem_value *ucontrol) 154bea1d61dSSascha Hauer { 155bea1d61dSSascha Hauer struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 156bea1d61dSSascha Hauer struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); 157bea1d61dSSascha Hauer 158bea1d61dSSascha Hauer ucontrol->value.integer.value[0] = micfil->quality; 159bea1d61dSSascha Hauer 160bea1d61dSSascha Hauer return 0; 161bea1d61dSSascha Hauer } 162bea1d61dSSascha Hauer 163bea1d61dSSascha Hauer static int micfil_quality_set(struct snd_kcontrol *kcontrol, 164bea1d61dSSascha Hauer struct snd_ctl_elem_value *ucontrol) 165bea1d61dSSascha Hauer { 166bea1d61dSSascha Hauer struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); 167bea1d61dSSascha Hauer struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); 168bea1d61dSSascha Hauer 169bea1d61dSSascha Hauer micfil->quality = ucontrol->value.integer.value[0]; 170bea1d61dSSascha Hauer 171bea1d61dSSascha Hauer return micfil_set_quality(micfil); 172bea1d61dSSascha Hauer } 173bea1d61dSSascha Hauer 17429dbfeecSShengjiu Wang static const char * const micfil_hwvad_enable[] = { 17529dbfeecSShengjiu Wang "Disable (Record only)", 17629dbfeecSShengjiu Wang "Enable (Record with Vad)", 17729dbfeecSShengjiu Wang }; 17829dbfeecSShengjiu Wang 17929dbfeecSShengjiu Wang static const char * const micfil_hwvad_init_mode[] = { 18029dbfeecSShengjiu Wang "Envelope mode", "Energy mode", 18129dbfeecSShengjiu Wang }; 18229dbfeecSShengjiu Wang 18329dbfeecSShengjiu Wang static const char * const micfil_hwvad_hpf_texts[] = { 18429dbfeecSShengjiu Wang "Filter bypass", 18529dbfeecSShengjiu Wang "Cut-off @1750Hz", 18629dbfeecSShengjiu Wang "Cut-off @215Hz", 18729dbfeecSShengjiu Wang "Cut-off @102Hz", 18829dbfeecSShengjiu Wang }; 18929dbfeecSShengjiu Wang 19029dbfeecSShengjiu Wang /* 19129dbfeecSShengjiu Wang * DC Remover Control 19229dbfeecSShengjiu Wang * Filter Bypassed 1 1 19329dbfeecSShengjiu Wang * Cut-off @21Hz 0 0 19429dbfeecSShengjiu Wang * Cut-off @83Hz 0 1 19529dbfeecSShengjiu Wang * Cut-off @152HZ 1 0 19629dbfeecSShengjiu Wang */ 19729dbfeecSShengjiu Wang static const char * const micfil_dc_remover_texts[] = { 19829dbfeecSShengjiu Wang "Cut-off @21Hz", "Cut-off @83Hz", 19929dbfeecSShengjiu Wang "Cut-off @152Hz", "Bypass", 20029dbfeecSShengjiu Wang }; 20129dbfeecSShengjiu Wang 20229dbfeecSShengjiu Wang static const struct soc_enum hwvad_enable_enum = 20329dbfeecSShengjiu Wang SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_enable), 20429dbfeecSShengjiu Wang micfil_hwvad_enable); 20529dbfeecSShengjiu Wang static const struct soc_enum hwvad_init_mode_enum = 20629dbfeecSShengjiu Wang SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_init_mode), 20729dbfeecSShengjiu Wang micfil_hwvad_init_mode); 20829dbfeecSShengjiu Wang static const struct soc_enum hwvad_hpf_enum = 20929dbfeecSShengjiu Wang SOC_ENUM_SINGLE(REG_MICFIL_VAD0_CTRL2, 0, 21029dbfeecSShengjiu Wang ARRAY_SIZE(micfil_hwvad_hpf_texts), 21129dbfeecSShengjiu Wang micfil_hwvad_hpf_texts); 21229dbfeecSShengjiu Wang static const struct soc_enum fsl_micfil_dc_remover_enum = 21329dbfeecSShengjiu Wang SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_dc_remover_texts), 21429dbfeecSShengjiu Wang micfil_dc_remover_texts); 21529dbfeecSShengjiu Wang 21629dbfeecSShengjiu Wang static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, 21729dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 21829dbfeecSShengjiu Wang { 21929dbfeecSShengjiu Wang struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 22029dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 22129dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 22229dbfeecSShengjiu Wang unsigned int *item = ucontrol->value.enumerated.item; 22329dbfeecSShengjiu Wang int val = snd_soc_enum_item_to_val(e, item[0]); 22429dbfeecSShengjiu Wang int i = 0, ret = 0; 22529dbfeecSShengjiu Wang u32 reg_val = 0; 22629dbfeecSShengjiu Wang 22729dbfeecSShengjiu Wang if (val < 0 || val > 3) 22829dbfeecSShengjiu Wang return -EINVAL; 22929dbfeecSShengjiu Wang 23029dbfeecSShengjiu Wang micfil->dc_remover = val; 23129dbfeecSShengjiu Wang 23229dbfeecSShengjiu Wang /* Calculate total value for all channels */ 23329dbfeecSShengjiu Wang for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) 23429dbfeecSShengjiu Wang reg_val |= val << MICFIL_DC_CHX_SHIFT(i); 23529dbfeecSShengjiu Wang 23629dbfeecSShengjiu Wang /* Update DC Remover mode for all channels */ 23729dbfeecSShengjiu Wang ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, 23829dbfeecSShengjiu Wang MICFIL_DC_CTRL_CONFIG, reg_val); 23929dbfeecSShengjiu Wang if (ret < 0) 24029dbfeecSShengjiu Wang return ret; 24129dbfeecSShengjiu Wang 24229dbfeecSShengjiu Wang return 0; 24329dbfeecSShengjiu Wang } 24429dbfeecSShengjiu Wang 24529dbfeecSShengjiu Wang static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, 24629dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 24729dbfeecSShengjiu Wang { 24829dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 24929dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 25029dbfeecSShengjiu Wang 25129dbfeecSShengjiu Wang ucontrol->value.enumerated.item[0] = micfil->dc_remover; 25229dbfeecSShengjiu Wang 25329dbfeecSShengjiu Wang return 0; 25429dbfeecSShengjiu Wang } 25529dbfeecSShengjiu Wang 25629dbfeecSShengjiu Wang static int hwvad_put_enable(struct snd_kcontrol *kcontrol, 25729dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 25829dbfeecSShengjiu Wang { 25929dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 26029dbfeecSShengjiu Wang struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 26129dbfeecSShengjiu Wang unsigned int *item = ucontrol->value.enumerated.item; 26229dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 26329dbfeecSShengjiu Wang int val = snd_soc_enum_item_to_val(e, item[0]); 26429dbfeecSShengjiu Wang 26529dbfeecSShengjiu Wang micfil->vad_enabled = val; 26629dbfeecSShengjiu Wang 26729dbfeecSShengjiu Wang return 0; 26829dbfeecSShengjiu Wang } 26929dbfeecSShengjiu Wang 27029dbfeecSShengjiu Wang static int hwvad_get_enable(struct snd_kcontrol *kcontrol, 27129dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 27229dbfeecSShengjiu Wang { 27329dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 27429dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 27529dbfeecSShengjiu Wang 27629dbfeecSShengjiu Wang ucontrol->value.enumerated.item[0] = micfil->vad_enabled; 27729dbfeecSShengjiu Wang 27829dbfeecSShengjiu Wang return 0; 27929dbfeecSShengjiu Wang } 28029dbfeecSShengjiu Wang 28129dbfeecSShengjiu Wang static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, 28229dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 28329dbfeecSShengjiu Wang { 28429dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 28529dbfeecSShengjiu Wang struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 28629dbfeecSShengjiu Wang unsigned int *item = ucontrol->value.enumerated.item; 28729dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 28829dbfeecSShengjiu Wang int val = snd_soc_enum_item_to_val(e, item[0]); 28929dbfeecSShengjiu Wang 29029dbfeecSShengjiu Wang /* 0 - Envelope-based Mode 29129dbfeecSShengjiu Wang * 1 - Energy-based Mode 29229dbfeecSShengjiu Wang */ 29329dbfeecSShengjiu Wang micfil->vad_init_mode = val; 29429dbfeecSShengjiu Wang 29529dbfeecSShengjiu Wang return 0; 29629dbfeecSShengjiu Wang } 29729dbfeecSShengjiu Wang 29829dbfeecSShengjiu Wang static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, 29929dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 30029dbfeecSShengjiu Wang { 30129dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 30229dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 30329dbfeecSShengjiu Wang 30429dbfeecSShengjiu Wang ucontrol->value.enumerated.item[0] = micfil->vad_init_mode; 30529dbfeecSShengjiu Wang 30629dbfeecSShengjiu Wang return 0; 30729dbfeecSShengjiu Wang } 30829dbfeecSShengjiu Wang 30929dbfeecSShengjiu Wang static int hwvad_detected(struct snd_kcontrol *kcontrol, 31029dbfeecSShengjiu Wang struct snd_ctl_elem_value *ucontrol) 31129dbfeecSShengjiu Wang { 31229dbfeecSShengjiu Wang struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); 31329dbfeecSShengjiu Wang struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); 31429dbfeecSShengjiu Wang 31529dbfeecSShengjiu Wang ucontrol->value.enumerated.item[0] = micfil->vad_detected; 31629dbfeecSShengjiu Wang 31729dbfeecSShengjiu Wang return 0; 31829dbfeecSShengjiu Wang } 31929dbfeecSShengjiu Wang 32047a70e6fSCosmin Samoila static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { 32147a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, 322cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv), 32347a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, 324cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(1), 0x8, 0xF, gain_tlv), 32547a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, 326cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(2), 0x8, 0xF, gain_tlv), 32747a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, 328cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(3), 0x8, 0xF, gain_tlv), 32947a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, 330cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(4), 0x8, 0xF, gain_tlv), 33147a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, 332cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(5), 0x8, 0xF, gain_tlv), 33347a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, 334cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv), 33547a70e6fSCosmin Samoila SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, 336cdfa92ebSChancel Liu MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv), 33747a70e6fSCosmin Samoila SOC_ENUM_EXT("MICFIL Quality Select", 33847a70e6fSCosmin Samoila fsl_micfil_quality_enum, 339bea1d61dSSascha Hauer micfil_quality_get, micfil_quality_set), 34029dbfeecSShengjiu Wang SOC_ENUM_EXT("HWVAD Enablement Switch", hwvad_enable_enum, 34129dbfeecSShengjiu Wang hwvad_get_enable, hwvad_put_enable), 34229dbfeecSShengjiu Wang SOC_ENUM_EXT("HWVAD Initialization Mode", hwvad_init_mode_enum, 34329dbfeecSShengjiu Wang hwvad_get_init_mode, hwvad_put_init_mode), 34429dbfeecSShengjiu Wang SOC_ENUM("HWVAD High-Pass Filter", hwvad_hpf_enum), 34529dbfeecSShengjiu Wang SOC_SINGLE("HWVAD ZCD Switch", REG_MICFIL_VAD0_ZCD, 0, 1, 0), 34629dbfeecSShengjiu Wang SOC_SINGLE("HWVAD ZCD Auto Threshold Switch", 34729dbfeecSShengjiu Wang REG_MICFIL_VAD0_ZCD, 2, 1, 0), 34829dbfeecSShengjiu Wang SOC_ENUM_EXT("MICFIL DC Remover Control", fsl_micfil_dc_remover_enum, 34929dbfeecSShengjiu Wang micfil_get_dc_remover_state, micfil_put_dc_remover_state), 35029dbfeecSShengjiu Wang SOC_SINGLE("HWVAD Input Gain", REG_MICFIL_VAD0_CTRL2, 8, 15, 0), 35129dbfeecSShengjiu Wang SOC_SINGLE("HWVAD Sound Gain", REG_MICFIL_VAD0_SCONFIG, 0, 15, 0), 35229dbfeecSShengjiu Wang SOC_SINGLE("HWVAD Noise Gain", REG_MICFIL_VAD0_NCONFIG, 0, 15, 0), 35329dbfeecSShengjiu Wang SOC_SINGLE_RANGE("HWVAD Detector Frame Time", REG_MICFIL_VAD0_CTRL2, 16, 0, 63, 0), 35429dbfeecSShengjiu Wang SOC_SINGLE("HWVAD Detector Initialization Time", REG_MICFIL_VAD0_CTRL1, 8, 31, 0), 35529dbfeecSShengjiu Wang SOC_SINGLE("HWVAD Noise Filter Adjustment", REG_MICFIL_VAD0_NCONFIG, 8, 31, 0), 35629dbfeecSShengjiu Wang SOC_SINGLE("HWVAD ZCD Threshold", REG_MICFIL_VAD0_ZCD, 16, 1023, 0), 35729dbfeecSShengjiu Wang SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), 35829dbfeecSShengjiu Wang SOC_SINGLE("HWVAD ZCD And Behavior Switch", 35929dbfeecSShengjiu Wang REG_MICFIL_VAD0_ZCD, 4, 1, 0), 36029dbfeecSShengjiu Wang SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), 36147a70e6fSCosmin Samoila }; 36247a70e6fSCosmin Samoila 36336736505SChancel Liu static int fsl_micfil_use_verid(struct device *dev) 36436736505SChancel Liu { 36536736505SChancel Liu struct fsl_micfil *micfil = dev_get_drvdata(dev); 36636736505SChancel Liu unsigned int val; 36736736505SChancel Liu int ret; 36836736505SChancel Liu 36936736505SChancel Liu if (!micfil->soc->use_verid) 37036736505SChancel Liu return 0; 37136736505SChancel Liu 37236736505SChancel Liu ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val); 37336736505SChancel Liu if (ret < 0) 37436736505SChancel Liu return ret; 37536736505SChancel Liu 37636736505SChancel Liu dev_dbg(dev, "VERID: 0x%016X\n", val); 37736736505SChancel Liu 37836736505SChancel Liu micfil->verid.version = val & 37936736505SChancel Liu (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK); 38036736505SChancel Liu micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT; 38136736505SChancel Liu micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK; 38236736505SChancel Liu 38336736505SChancel Liu ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val); 38436736505SChancel Liu if (ret < 0) 38536736505SChancel Liu return ret; 38636736505SChancel Liu 38736736505SChancel Liu dev_dbg(dev, "PARAM: 0x%016X\n", val); 38836736505SChancel Liu 38936736505SChancel Liu micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >> 39036736505SChancel Liu MICFIL_PARAM_NUM_HWVAD_SHIFT; 39136736505SChancel Liu micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD; 39236736505SChancel Liu micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE; 39336736505SChancel Liu micfil->param.hwvad = val & MICFIL_PARAM_HWVAD; 39436736505SChancel Liu micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS; 39536736505SChancel Liu micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS; 39636736505SChancel Liu micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER; 39736736505SChancel Liu micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH; 39836736505SChancel Liu micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >> 39936736505SChancel Liu MICFIL_PARAM_FIFO_PTRWID_SHIFT; 40036736505SChancel Liu micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >> 40136736505SChancel Liu MICFIL_PARAM_NPAIR_SHIFT; 40236736505SChancel Liu 40336736505SChancel Liu return 0; 40436736505SChancel Liu } 40536736505SChancel Liu 40647a70e6fSCosmin Samoila /* The SRES is a self-negated bit which provides the CPU with the 40747a70e6fSCosmin Samoila * capability to initialize the PDM Interface module through the 40847a70e6fSCosmin Samoila * slave-bus interface. This bit always reads as zero, and this 40947a70e6fSCosmin Samoila * bit is only effective when MDIS is cleared 41047a70e6fSCosmin Samoila */ 41147a70e6fSCosmin Samoila static int fsl_micfil_reset(struct device *dev) 41247a70e6fSCosmin Samoila { 41347a70e6fSCosmin Samoila struct fsl_micfil *micfil = dev_get_drvdata(dev); 41447a70e6fSCosmin Samoila int ret; 41547a70e6fSCosmin Samoila 416d46c2127SSascha Hauer ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, 417d46c2127SSascha Hauer MICFIL_CTRL1_MDIS); 4182c602c7eSSascha Hauer if (ret) 41947a70e6fSCosmin Samoila return ret; 42047a70e6fSCosmin Samoila 421d46c2127SSascha Hauer ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, 42247a70e6fSCosmin Samoila MICFIL_CTRL1_SRES); 4232c602c7eSSascha Hauer if (ret) 42447a70e6fSCosmin Samoila return ret; 42547a70e6fSCosmin Samoila 426292709b9SShengjiu Wang /* 427292709b9SShengjiu Wang * SRES is self-cleared bit, but REG_MICFIL_CTRL1 is defined 428292709b9SShengjiu Wang * as non-volatile register, so SRES still remain in regmap 429292709b9SShengjiu Wang * cache after set, that every update of REG_MICFIL_CTRL1, 430292709b9SShengjiu Wang * software reset happens. so clear it explicitly. 431292709b9SShengjiu Wang */ 432292709b9SShengjiu Wang ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, 433292709b9SShengjiu Wang MICFIL_CTRL1_SRES); 434292709b9SShengjiu Wang if (ret) 435292709b9SShengjiu Wang return ret; 436292709b9SShengjiu Wang 437b776c4a4SShengjiu Wang /* 438b776c4a4SShengjiu Wang * Set SRES should clear CHnF flags, But even add delay here 439b776c4a4SShengjiu Wang * the CHnF may not be cleared sometimes, so clear CHnF explicitly. 440b776c4a4SShengjiu Wang */ 441b776c4a4SShengjiu Wang ret = regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, 0xFF, 0xFF); 442b776c4a4SShengjiu Wang if (ret) 443b776c4a4SShengjiu Wang return ret; 444b776c4a4SShengjiu Wang 44547a70e6fSCosmin Samoila return 0; 44647a70e6fSCosmin Samoila } 44747a70e6fSCosmin Samoila 44847a70e6fSCosmin Samoila static int fsl_micfil_startup(struct snd_pcm_substream *substream, 44947a70e6fSCosmin Samoila struct snd_soc_dai *dai) 45047a70e6fSCosmin Samoila { 45147a70e6fSCosmin Samoila struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); 45247a70e6fSCosmin Samoila 45347a70e6fSCosmin Samoila if (!micfil) { 45411106cb3STang Bin dev_err(dai->dev, "micfil dai priv_data not set\n"); 45547a70e6fSCosmin Samoila return -EINVAL; 45647a70e6fSCosmin Samoila } 45747a70e6fSCosmin Samoila 45847a70e6fSCosmin Samoila return 0; 45947a70e6fSCosmin Samoila } 46047a70e6fSCosmin Samoila 46129dbfeecSShengjiu Wang /* Enable/disable hwvad interrupts */ 46229dbfeecSShengjiu Wang static int fsl_micfil_configure_hwvad_interrupts(struct fsl_micfil *micfil, int enable) 46329dbfeecSShengjiu Wang { 46429dbfeecSShengjiu Wang u32 vadie_reg = enable ? MICFIL_VAD0_CTRL1_IE : 0; 46529dbfeecSShengjiu Wang u32 vaderie_reg = enable ? MICFIL_VAD0_CTRL1_ERIE : 0; 46629dbfeecSShengjiu Wang 46729dbfeecSShengjiu Wang /* Voice Activity Detector Error Interruption */ 46829dbfeecSShengjiu Wang regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 46929dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_ERIE, vaderie_reg); 47029dbfeecSShengjiu Wang 47129dbfeecSShengjiu Wang /* Voice Activity Detector Interruption */ 47229dbfeecSShengjiu Wang regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 47329dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_IE, vadie_reg); 47429dbfeecSShengjiu Wang 47529dbfeecSShengjiu Wang return 0; 47629dbfeecSShengjiu Wang } 47729dbfeecSShengjiu Wang 47829dbfeecSShengjiu Wang /* Configuration done only in energy-based initialization mode */ 47929dbfeecSShengjiu Wang static int fsl_micfil_init_hwvad_energy_mode(struct fsl_micfil *micfil) 48029dbfeecSShengjiu Wang { 48129dbfeecSShengjiu Wang /* Keep the VADFRENDIS bitfield cleared. */ 48229dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, 48329dbfeecSShengjiu Wang MICFIL_VAD0_CTRL2_FRENDIS); 48429dbfeecSShengjiu Wang 48529dbfeecSShengjiu Wang /* Keep the VADPREFEN bitfield cleared. */ 48629dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, 48729dbfeecSShengjiu Wang MICFIL_VAD0_CTRL2_PREFEN); 48829dbfeecSShengjiu Wang 48929dbfeecSShengjiu Wang /* Keep the VADSFILEN bitfield cleared. */ 49029dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, 49129dbfeecSShengjiu Wang MICFIL_VAD0_SCONFIG_SFILEN); 49229dbfeecSShengjiu Wang 49329dbfeecSShengjiu Wang /* Keep the VADSMAXEN bitfield cleared. */ 49429dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, 49529dbfeecSShengjiu Wang MICFIL_VAD0_SCONFIG_SMAXEN); 49629dbfeecSShengjiu Wang 49729dbfeecSShengjiu Wang /* Keep the VADNFILAUTO bitfield asserted. */ 49829dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 49929dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NFILAUT); 50029dbfeecSShengjiu Wang 50129dbfeecSShengjiu Wang /* Keep the VADNMINEN bitfield cleared. */ 50229dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 50329dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NMINEN); 50429dbfeecSShengjiu Wang 50529dbfeecSShengjiu Wang /* Keep the VADNDECEN bitfield cleared. */ 50629dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 50729dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NDECEN); 50829dbfeecSShengjiu Wang 50929dbfeecSShengjiu Wang /* Keep the VADNOREN bitfield cleared. */ 51029dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 51129dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NOREN); 51229dbfeecSShengjiu Wang 51329dbfeecSShengjiu Wang return 0; 51429dbfeecSShengjiu Wang } 51529dbfeecSShengjiu Wang 51629dbfeecSShengjiu Wang /* Configuration done only in envelope-based initialization mode */ 51729dbfeecSShengjiu Wang static int fsl_micfil_init_hwvad_envelope_mode(struct fsl_micfil *micfil) 51829dbfeecSShengjiu Wang { 51929dbfeecSShengjiu Wang /* Assert the VADFRENDIS bitfield */ 52029dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, 52129dbfeecSShengjiu Wang MICFIL_VAD0_CTRL2_FRENDIS); 52229dbfeecSShengjiu Wang 52329dbfeecSShengjiu Wang /* Assert the VADPREFEN bitfield. */ 52429dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, 52529dbfeecSShengjiu Wang MICFIL_VAD0_CTRL2_PREFEN); 52629dbfeecSShengjiu Wang 52729dbfeecSShengjiu Wang /* Assert the VADSFILEN bitfield. */ 52829dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, 52929dbfeecSShengjiu Wang MICFIL_VAD0_SCONFIG_SFILEN); 53029dbfeecSShengjiu Wang 53129dbfeecSShengjiu Wang /* Assert the VADSMAXEN bitfield. */ 53229dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, 53329dbfeecSShengjiu Wang MICFIL_VAD0_SCONFIG_SMAXEN); 53429dbfeecSShengjiu Wang 53529dbfeecSShengjiu Wang /* Clear the VADNFILAUTO bitfield */ 53629dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 53729dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NFILAUT); 53829dbfeecSShengjiu Wang 53929dbfeecSShengjiu Wang /* Assert the VADNMINEN bitfield. */ 54029dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 54129dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NMINEN); 54229dbfeecSShengjiu Wang 54329dbfeecSShengjiu Wang /* Assert the VADNDECEN bitfield. */ 54429dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 54529dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NDECEN); 54629dbfeecSShengjiu Wang 54729dbfeecSShengjiu Wang /* Assert VADNOREN bitfield. */ 54829dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, 54929dbfeecSShengjiu Wang MICFIL_VAD0_NCONFIG_NOREN); 55029dbfeecSShengjiu Wang 55129dbfeecSShengjiu Wang return 0; 55229dbfeecSShengjiu Wang } 55329dbfeecSShengjiu Wang 55429dbfeecSShengjiu Wang /* 55529dbfeecSShengjiu Wang * Hardware Voice Active Detection: The HWVAD takes data from the input 55629dbfeecSShengjiu Wang * of a selected PDM microphone to detect if there is any 55729dbfeecSShengjiu Wang * voice activity. When a voice activity is detected, an interrupt could 55829dbfeecSShengjiu Wang * be delivered to the system. Initialization in section 8.4: 55929dbfeecSShengjiu Wang * Can work in two modes: 56029dbfeecSShengjiu Wang * -> Eneveope-based mode (section 8.4.1) 56129dbfeecSShengjiu Wang * -> Energy-based mode (section 8.4.2) 56229dbfeecSShengjiu Wang * 56329dbfeecSShengjiu Wang * It is important to remark that the HWVAD detector could be enabled 56429dbfeecSShengjiu Wang * or reset only when the MICFIL isn't running i.e. when the BSY_FIL 56529dbfeecSShengjiu Wang * bit in STAT register is cleared 56629dbfeecSShengjiu Wang */ 56729dbfeecSShengjiu Wang static int fsl_micfil_hwvad_enable(struct fsl_micfil *micfil) 56829dbfeecSShengjiu Wang { 56929dbfeecSShengjiu Wang int ret; 57029dbfeecSShengjiu Wang 57129dbfeecSShengjiu Wang micfil->vad_detected = 0; 57229dbfeecSShengjiu Wang 57329dbfeecSShengjiu Wang /* envelope-based specific initialization */ 57429dbfeecSShengjiu Wang if (micfil->vad_init_mode == MICFIL_HWVAD_ENVELOPE_MODE) 57529dbfeecSShengjiu Wang ret = fsl_micfil_init_hwvad_envelope_mode(micfil); 57629dbfeecSShengjiu Wang else 57729dbfeecSShengjiu Wang ret = fsl_micfil_init_hwvad_energy_mode(micfil); 57829dbfeecSShengjiu Wang if (ret) 57929dbfeecSShengjiu Wang return ret; 58029dbfeecSShengjiu Wang 58129dbfeecSShengjiu Wang /* Voice Activity Detector Internal Filters Initialization*/ 58229dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 58329dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_ST10); 58429dbfeecSShengjiu Wang 58529dbfeecSShengjiu Wang /* Voice Activity Detector Internal Filter */ 58629dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 58729dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_ST10); 58829dbfeecSShengjiu Wang 58929dbfeecSShengjiu Wang /* Enable Interrupts */ 59029dbfeecSShengjiu Wang ret = fsl_micfil_configure_hwvad_interrupts(micfil, 1); 59129dbfeecSShengjiu Wang if (ret) 59229dbfeecSShengjiu Wang return ret; 59329dbfeecSShengjiu Wang 59429dbfeecSShengjiu Wang /* Voice Activity Detector Reset */ 59529dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 59629dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_RST); 59729dbfeecSShengjiu Wang 59829dbfeecSShengjiu Wang /* Voice Activity Detector Enabled */ 59929dbfeecSShengjiu Wang regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 60029dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_EN); 60129dbfeecSShengjiu Wang 60229dbfeecSShengjiu Wang return 0; 60329dbfeecSShengjiu Wang } 60429dbfeecSShengjiu Wang 60529dbfeecSShengjiu Wang static int fsl_micfil_hwvad_disable(struct fsl_micfil *micfil) 60629dbfeecSShengjiu Wang { 60729dbfeecSShengjiu Wang struct device *dev = &micfil->pdev->dev; 60829dbfeecSShengjiu Wang int ret = 0; 60929dbfeecSShengjiu Wang 61029dbfeecSShengjiu Wang /* Disable HWVAD */ 61129dbfeecSShengjiu Wang regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 61229dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_EN); 61329dbfeecSShengjiu Wang 61429dbfeecSShengjiu Wang /* Disable hwvad interrupts */ 61529dbfeecSShengjiu Wang ret = fsl_micfil_configure_hwvad_interrupts(micfil, 0); 61629dbfeecSShengjiu Wang if (ret) 61729dbfeecSShengjiu Wang dev_err(dev, "Failed to disable interrupts\n"); 61829dbfeecSShengjiu Wang 61929dbfeecSShengjiu Wang return ret; 62029dbfeecSShengjiu Wang } 62129dbfeecSShengjiu Wang 62247a70e6fSCosmin Samoila static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, 62347a70e6fSCosmin Samoila struct snd_soc_dai *dai) 62447a70e6fSCosmin Samoila { 62547a70e6fSCosmin Samoila struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); 62647a70e6fSCosmin Samoila struct device *dev = &micfil->pdev->dev; 62747a70e6fSCosmin Samoila int ret; 62847a70e6fSCosmin Samoila 62947a70e6fSCosmin Samoila switch (cmd) { 63047a70e6fSCosmin Samoila case SNDRV_PCM_TRIGGER_START: 63147a70e6fSCosmin Samoila case SNDRV_PCM_TRIGGER_RESUME: 63247a70e6fSCosmin Samoila case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 63347a70e6fSCosmin Samoila ret = fsl_micfil_reset(dev); 63447a70e6fSCosmin Samoila if (ret) { 63547a70e6fSCosmin Samoila dev_err(dev, "failed to soft reset\n"); 63647a70e6fSCosmin Samoila return ret; 63747a70e6fSCosmin Samoila } 63847a70e6fSCosmin Samoila 63947a70e6fSCosmin Samoila /* DMA Interrupt Selection - DISEL bits 64047a70e6fSCosmin Samoila * 00 - DMA and IRQ disabled 64147a70e6fSCosmin Samoila * 01 - DMA req enabled 64247a70e6fSCosmin Samoila * 10 - IRQ enabled 64347a70e6fSCosmin Samoila * 11 - reserved 64447a70e6fSCosmin Samoila */ 64547a70e6fSCosmin Samoila ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, 64617f2142bSSascha Hauer MICFIL_CTRL1_DISEL, 64717f2142bSSascha Hauer FIELD_PREP(MICFIL_CTRL1_DISEL, MICFIL_CTRL1_DISEL_DMA)); 6482c602c7eSSascha Hauer if (ret) 64947a70e6fSCosmin Samoila return ret; 65047a70e6fSCosmin Samoila 65147a70e6fSCosmin Samoila /* Enable the module */ 652d46c2127SSascha Hauer ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, 65347a70e6fSCosmin Samoila MICFIL_CTRL1_PDMIEN); 6542c602c7eSSascha Hauer if (ret) 65547a70e6fSCosmin Samoila return ret; 65647a70e6fSCosmin Samoila 65729dbfeecSShengjiu Wang if (micfil->vad_enabled) 65829dbfeecSShengjiu Wang fsl_micfil_hwvad_enable(micfil); 65929dbfeecSShengjiu Wang 66047a70e6fSCosmin Samoila break; 66147a70e6fSCosmin Samoila case SNDRV_PCM_TRIGGER_STOP: 66247a70e6fSCosmin Samoila case SNDRV_PCM_TRIGGER_SUSPEND: 66347a70e6fSCosmin Samoila case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 66429dbfeecSShengjiu Wang if (micfil->vad_enabled) 66529dbfeecSShengjiu Wang fsl_micfil_hwvad_disable(micfil); 66629dbfeecSShengjiu Wang 66747a70e6fSCosmin Samoila /* Disable the module */ 668d46c2127SSascha Hauer ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, 669d46c2127SSascha Hauer MICFIL_CTRL1_PDMIEN); 6702c602c7eSSascha Hauer if (ret) 67147a70e6fSCosmin Samoila return ret; 67247a70e6fSCosmin Samoila 67347a70e6fSCosmin Samoila ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, 67417f2142bSSascha Hauer MICFIL_CTRL1_DISEL, 67517f2142bSSascha Hauer FIELD_PREP(MICFIL_CTRL1_DISEL, MICFIL_CTRL1_DISEL_DISABLE)); 6762c602c7eSSascha Hauer if (ret) 67747a70e6fSCosmin Samoila return ret; 67847a70e6fSCosmin Samoila break; 67947a70e6fSCosmin Samoila default: 68047a70e6fSCosmin Samoila return -EINVAL; 68147a70e6fSCosmin Samoila } 68247a70e6fSCosmin Samoila return 0; 68347a70e6fSCosmin Samoila } 68447a70e6fSCosmin Samoila 68593f54100SShengjiu Wang static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int sample_rate) 68693f54100SShengjiu Wang { 68793f54100SShengjiu Wang struct device *dev = &micfil->pdev->dev; 68893f54100SShengjiu Wang u64 ratio = sample_rate; 68993f54100SShengjiu Wang struct clk *clk; 69093f54100SShengjiu Wang int ret; 69193f54100SShengjiu Wang 69293f54100SShengjiu Wang /* Get root clock */ 69393f54100SShengjiu Wang clk = micfil->mclk; 69493f54100SShengjiu Wang 69593f54100SShengjiu Wang /* Disable clock first, for it was enabled by pm_runtime */ 69693f54100SShengjiu Wang clk_disable_unprepare(clk); 69793f54100SShengjiu Wang fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, 69893f54100SShengjiu Wang micfil->pll11k_clk, ratio); 69993f54100SShengjiu Wang ret = clk_prepare_enable(clk); 70093f54100SShengjiu Wang if (ret) 70193f54100SShengjiu Wang return ret; 70293f54100SShengjiu Wang 70393f54100SShengjiu Wang return 0; 70493f54100SShengjiu Wang } 70593f54100SShengjiu Wang 70647a70e6fSCosmin Samoila static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, 70747a70e6fSCosmin Samoila struct snd_pcm_hw_params *params, 70847a70e6fSCosmin Samoila struct snd_soc_dai *dai) 70947a70e6fSCosmin Samoila { 71047a70e6fSCosmin Samoila struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); 71147a70e6fSCosmin Samoila unsigned int channels = params_channels(params); 71247a70e6fSCosmin Samoila unsigned int rate = params_rate(params); 713cc5ef57dSSascha Hauer int clk_div = 8; 714cc5ef57dSSascha Hauer int osr = MICFIL_OSR_DEFAULT; 71547a70e6fSCosmin Samoila int ret; 71647a70e6fSCosmin Samoila 71747a70e6fSCosmin Samoila /* 1. Disable the module */ 718d46c2127SSascha Hauer ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, 719d46c2127SSascha Hauer MICFIL_CTRL1_PDMIEN); 7202c602c7eSSascha Hauer if (ret) 72147a70e6fSCosmin Samoila return ret; 72247a70e6fSCosmin Samoila 72347a70e6fSCosmin Samoila /* enable channels */ 72447a70e6fSCosmin Samoila ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, 72547a70e6fSCosmin Samoila 0xFF, ((1 << channels) - 1)); 7262c602c7eSSascha Hauer if (ret) 72747a70e6fSCosmin Samoila return ret; 72847a70e6fSCosmin Samoila 72993f54100SShengjiu Wang ret = fsl_micfil_reparent_rootclk(micfil, rate); 73093f54100SShengjiu Wang if (ret) 73193f54100SShengjiu Wang return ret; 73293f54100SShengjiu Wang 733cc5ef57dSSascha Hauer ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); 734cc5ef57dSSascha Hauer if (ret) 73547a70e6fSCosmin Samoila return ret; 736cc5ef57dSSascha Hauer 737cc5ef57dSSascha Hauer ret = micfil_set_quality(micfil); 738cc5ef57dSSascha Hauer if (ret) 739cc5ef57dSSascha Hauer return ret; 740cc5ef57dSSascha Hauer 741cc5ef57dSSascha Hauer ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, 742cc5ef57dSSascha Hauer MICFIL_CTRL2_CLKDIV | MICFIL_CTRL2_CICOSR, 743cc5ef57dSSascha Hauer FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) | 744cc5ef57dSSascha Hauer FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr)); 74547a70e6fSCosmin Samoila 74629dbfeecSShengjiu Wang /* Configure CIC OSR in VADCICOSR */ 74729dbfeecSShengjiu Wang regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 74829dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_CICOSR, 74929dbfeecSShengjiu Wang FIELD_PREP(MICFIL_VAD0_CTRL1_CICOSR, 16 - osr)); 75029dbfeecSShengjiu Wang 75129dbfeecSShengjiu Wang /* Configure source channel in VADCHSEL */ 75229dbfeecSShengjiu Wang regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, 75329dbfeecSShengjiu Wang MICFIL_VAD0_CTRL1_CHSEL, 75429dbfeecSShengjiu Wang FIELD_PREP(MICFIL_VAD0_CTRL1_CHSEL, (channels - 1))); 75529dbfeecSShengjiu Wang 7562495ba26SSascha Hauer micfil->dma_params_rx.peripheral_config = &micfil->sdmacfg; 7572495ba26SSascha Hauer micfil->dma_params_rx.peripheral_size = sizeof(micfil->sdmacfg); 7582495ba26SSascha Hauer micfil->sdmacfg.n_fifos_src = channels; 7592495ba26SSascha Hauer micfil->sdmacfg.sw_done = true; 76047a70e6fSCosmin Samoila micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX; 76177a7a6e9SChancel Liu if (micfil->soc->use_edma) 76277a7a6e9SChancel Liu micfil->dma_params_rx.maxburst = channels; 76347a70e6fSCosmin Samoila 76447a70e6fSCosmin Samoila return 0; 76547a70e6fSCosmin Samoila } 76647a70e6fSCosmin Samoila 76738d89a56SRikard Falkeborn static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { 76847a70e6fSCosmin Samoila .startup = fsl_micfil_startup, 76947a70e6fSCosmin Samoila .trigger = fsl_micfil_trigger, 77047a70e6fSCosmin Samoila .hw_params = fsl_micfil_hw_params, 77147a70e6fSCosmin Samoila }; 77247a70e6fSCosmin Samoila 77347a70e6fSCosmin Samoila static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) 77447a70e6fSCosmin Samoila { 77547a70e6fSCosmin Samoila struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); 7763b13b143SShengjiu Wang struct device *dev = cpu_dai->dev; 7773b13b143SShengjiu Wang unsigned int val = 0; 7783b13b143SShengjiu Wang int ret, i; 77947a70e6fSCosmin Samoila 7803b13b143SShengjiu Wang micfil->quality = QUALITY_VLOW0; 78129dbfeecSShengjiu Wang micfil->card = cpu_dai->component->card; 78247a70e6fSCosmin Samoila 7833b13b143SShengjiu Wang /* set default gain to 2 */ 7843b13b143SShengjiu Wang regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); 7853b13b143SShengjiu Wang 7863b13b143SShengjiu Wang /* set DC Remover in bypass mode*/ 7873b13b143SShengjiu Wang for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) 7883b13b143SShengjiu Wang val |= MICFIL_DC_BYPASS << MICFIL_DC_CHX_SHIFT(i); 7893b13b143SShengjiu Wang ret = regmap_update_bits(micfil->regmap, REG_MICFIL_DC_CTRL, 7903b13b143SShengjiu Wang MICFIL_DC_CTRL_CONFIG, val); 7913b13b143SShengjiu Wang if (ret) { 7923b13b143SShengjiu Wang dev_err(dev, "failed to set DC Remover mode bits\n"); 7933b13b143SShengjiu Wang return ret; 7943b13b143SShengjiu Wang } 7953b13b143SShengjiu Wang micfil->dc_remover = MICFIL_DC_BYPASS; 79647a70e6fSCosmin Samoila 79747a70e6fSCosmin Samoila snd_soc_dai_init_dma_data(cpu_dai, NULL, 79847a70e6fSCosmin Samoila &micfil->dma_params_rx); 79947a70e6fSCosmin Samoila 80047a70e6fSCosmin Samoila /* FIFO Watermark Control - FIFOWMK*/ 80147a70e6fSCosmin Samoila ret = regmap_update_bits(micfil->regmap, REG_MICFIL_FIFO_CTRL, 80217f2142bSSascha Hauer MICFIL_FIFO_CTRL_FIFOWMK, 80317f2142bSSascha Hauer FIELD_PREP(MICFIL_FIFO_CTRL_FIFOWMK, micfil->soc->fifo_depth - 1)); 8042c602c7eSSascha Hauer if (ret) 80547a70e6fSCosmin Samoila return ret; 80647a70e6fSCosmin Samoila 80747a70e6fSCosmin Samoila return 0; 80847a70e6fSCosmin Samoila } 80947a70e6fSCosmin Samoila 81047a70e6fSCosmin Samoila static struct snd_soc_dai_driver fsl_micfil_dai = { 81147a70e6fSCosmin Samoila .probe = fsl_micfil_dai_probe, 81247a70e6fSCosmin Samoila .capture = { 81347a70e6fSCosmin Samoila .stream_name = "CPU-Capture", 81447a70e6fSCosmin Samoila .channels_min = 1, 81547a70e6fSCosmin Samoila .channels_max = 8, 81699c08cdbSSascha Hauer .rates = SNDRV_PCM_RATE_8000_48000, 81799c08cdbSSascha Hauer .formats = SNDRV_PCM_FMTBIT_S16_LE, 81847a70e6fSCosmin Samoila }, 81947a70e6fSCosmin Samoila .ops = &fsl_micfil_dai_ops, 82047a70e6fSCosmin Samoila }; 82147a70e6fSCosmin Samoila 82247a70e6fSCosmin Samoila static const struct snd_soc_component_driver fsl_micfil_component = { 82347a70e6fSCosmin Samoila .name = "fsl-micfil-dai", 82447a70e6fSCosmin Samoila .controls = fsl_micfil_snd_controls, 82547a70e6fSCosmin Samoila .num_controls = ARRAY_SIZE(fsl_micfil_snd_controls), 826978bd27cSShengjiu Wang .legacy_dai_naming = 1, 82747a70e6fSCosmin Samoila }; 82847a70e6fSCosmin Samoila 82947a70e6fSCosmin Samoila /* REGMAP */ 83047a70e6fSCosmin Samoila static const struct reg_default fsl_micfil_reg_defaults[] = { 83147a70e6fSCosmin Samoila {REG_MICFIL_CTRL1, 0x00000000}, 83247a70e6fSCosmin Samoila {REG_MICFIL_CTRL2, 0x00000000}, 83347a70e6fSCosmin Samoila {REG_MICFIL_STAT, 0x00000000}, 83447a70e6fSCosmin Samoila {REG_MICFIL_FIFO_CTRL, 0x00000007}, 83547a70e6fSCosmin Samoila {REG_MICFIL_FIFO_STAT, 0x00000000}, 83647a70e6fSCosmin Samoila {REG_MICFIL_DATACH0, 0x00000000}, 83747a70e6fSCosmin Samoila {REG_MICFIL_DATACH1, 0x00000000}, 83847a70e6fSCosmin Samoila {REG_MICFIL_DATACH2, 0x00000000}, 83947a70e6fSCosmin Samoila {REG_MICFIL_DATACH3, 0x00000000}, 84047a70e6fSCosmin Samoila {REG_MICFIL_DATACH4, 0x00000000}, 84147a70e6fSCosmin Samoila {REG_MICFIL_DATACH5, 0x00000000}, 84247a70e6fSCosmin Samoila {REG_MICFIL_DATACH6, 0x00000000}, 84347a70e6fSCosmin Samoila {REG_MICFIL_DATACH7, 0x00000000}, 84447a70e6fSCosmin Samoila {REG_MICFIL_DC_CTRL, 0x00000000}, 84547a70e6fSCosmin Samoila {REG_MICFIL_OUT_CTRL, 0x00000000}, 84647a70e6fSCosmin Samoila {REG_MICFIL_OUT_STAT, 0x00000000}, 84747a70e6fSCosmin Samoila {REG_MICFIL_VAD0_CTRL1, 0x00000000}, 84847a70e6fSCosmin Samoila {REG_MICFIL_VAD0_CTRL2, 0x000A0000}, 84947a70e6fSCosmin Samoila {REG_MICFIL_VAD0_STAT, 0x00000000}, 85047a70e6fSCosmin Samoila {REG_MICFIL_VAD0_SCONFIG, 0x00000000}, 85147a70e6fSCosmin Samoila {REG_MICFIL_VAD0_NCONFIG, 0x80000000}, 85247a70e6fSCosmin Samoila {REG_MICFIL_VAD0_NDATA, 0x00000000}, 85347a70e6fSCosmin Samoila {REG_MICFIL_VAD0_ZCD, 0x00000004}, 85447a70e6fSCosmin Samoila }; 85547a70e6fSCosmin Samoila 85647a70e6fSCosmin Samoila static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) 85747a70e6fSCosmin Samoila { 85847a70e6fSCosmin Samoila switch (reg) { 85947a70e6fSCosmin Samoila case REG_MICFIL_CTRL1: 86047a70e6fSCosmin Samoila case REG_MICFIL_CTRL2: 86147a70e6fSCosmin Samoila case REG_MICFIL_STAT: 86247a70e6fSCosmin Samoila case REG_MICFIL_FIFO_CTRL: 86347a70e6fSCosmin Samoila case REG_MICFIL_FIFO_STAT: 86447a70e6fSCosmin Samoila case REG_MICFIL_DATACH0: 86547a70e6fSCosmin Samoila case REG_MICFIL_DATACH1: 86647a70e6fSCosmin Samoila case REG_MICFIL_DATACH2: 86747a70e6fSCosmin Samoila case REG_MICFIL_DATACH3: 86847a70e6fSCosmin Samoila case REG_MICFIL_DATACH4: 86947a70e6fSCosmin Samoila case REG_MICFIL_DATACH5: 87047a70e6fSCosmin Samoila case REG_MICFIL_DATACH6: 87147a70e6fSCosmin Samoila case REG_MICFIL_DATACH7: 87247a70e6fSCosmin Samoila case REG_MICFIL_DC_CTRL: 87347a70e6fSCosmin Samoila case REG_MICFIL_OUT_CTRL: 87447a70e6fSCosmin Samoila case REG_MICFIL_OUT_STAT: 87551d765f7SChancel Liu case REG_MICFIL_FSYNC_CTRL: 87651d765f7SChancel Liu case REG_MICFIL_VERID: 87751d765f7SChancel Liu case REG_MICFIL_PARAM: 87847a70e6fSCosmin Samoila case REG_MICFIL_VAD0_CTRL1: 87947a70e6fSCosmin Samoila case REG_MICFIL_VAD0_CTRL2: 88047a70e6fSCosmin Samoila case REG_MICFIL_VAD0_STAT: 88147a70e6fSCosmin Samoila case REG_MICFIL_VAD0_SCONFIG: 88247a70e6fSCosmin Samoila case REG_MICFIL_VAD0_NCONFIG: 88347a70e6fSCosmin Samoila case REG_MICFIL_VAD0_NDATA: 88447a70e6fSCosmin Samoila case REG_MICFIL_VAD0_ZCD: 88547a70e6fSCosmin Samoila return true; 88647a70e6fSCosmin Samoila default: 88747a70e6fSCosmin Samoila return false; 88847a70e6fSCosmin Samoila } 88947a70e6fSCosmin Samoila } 89047a70e6fSCosmin Samoila 89147a70e6fSCosmin Samoila static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) 89247a70e6fSCosmin Samoila { 89347a70e6fSCosmin Samoila switch (reg) { 89447a70e6fSCosmin Samoila case REG_MICFIL_CTRL1: 89547a70e6fSCosmin Samoila case REG_MICFIL_CTRL2: 89647a70e6fSCosmin Samoila case REG_MICFIL_STAT: /* Write 1 to Clear */ 89747a70e6fSCosmin Samoila case REG_MICFIL_FIFO_CTRL: 89847a70e6fSCosmin Samoila case REG_MICFIL_FIFO_STAT: /* Write 1 to Clear */ 89947a70e6fSCosmin Samoila case REG_MICFIL_DC_CTRL: 90047a70e6fSCosmin Samoila case REG_MICFIL_OUT_CTRL: 90147a70e6fSCosmin Samoila case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ 90251d765f7SChancel Liu case REG_MICFIL_FSYNC_CTRL: 90347a70e6fSCosmin Samoila case REG_MICFIL_VAD0_CTRL1: 90447a70e6fSCosmin Samoila case REG_MICFIL_VAD0_CTRL2: 90547a70e6fSCosmin Samoila case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ 90647a70e6fSCosmin Samoila case REG_MICFIL_VAD0_SCONFIG: 90747a70e6fSCosmin Samoila case REG_MICFIL_VAD0_NCONFIG: 90847a70e6fSCosmin Samoila case REG_MICFIL_VAD0_ZCD: 90947a70e6fSCosmin Samoila return true; 91047a70e6fSCosmin Samoila default: 91147a70e6fSCosmin Samoila return false; 91247a70e6fSCosmin Samoila } 91347a70e6fSCosmin Samoila } 91447a70e6fSCosmin Samoila 91547a70e6fSCosmin Samoila static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) 91647a70e6fSCosmin Samoila { 91747a70e6fSCosmin Samoila switch (reg) { 91847a70e6fSCosmin Samoila case REG_MICFIL_STAT: 91947a70e6fSCosmin Samoila case REG_MICFIL_DATACH0: 92047a70e6fSCosmin Samoila case REG_MICFIL_DATACH1: 92147a70e6fSCosmin Samoila case REG_MICFIL_DATACH2: 92247a70e6fSCosmin Samoila case REG_MICFIL_DATACH3: 92347a70e6fSCosmin Samoila case REG_MICFIL_DATACH4: 92447a70e6fSCosmin Samoila case REG_MICFIL_DATACH5: 92547a70e6fSCosmin Samoila case REG_MICFIL_DATACH6: 92647a70e6fSCosmin Samoila case REG_MICFIL_DATACH7: 92751d765f7SChancel Liu case REG_MICFIL_VERID: 92851d765f7SChancel Liu case REG_MICFIL_PARAM: 92947a70e6fSCosmin Samoila case REG_MICFIL_VAD0_STAT: 93047a70e6fSCosmin Samoila case REG_MICFIL_VAD0_NDATA: 93147a70e6fSCosmin Samoila return true; 93247a70e6fSCosmin Samoila default: 93347a70e6fSCosmin Samoila return false; 93447a70e6fSCosmin Samoila } 93547a70e6fSCosmin Samoila } 93647a70e6fSCosmin Samoila 93747a70e6fSCosmin Samoila static const struct regmap_config fsl_micfil_regmap_config = { 93847a70e6fSCosmin Samoila .reg_bits = 32, 93947a70e6fSCosmin Samoila .reg_stride = 4, 94047a70e6fSCosmin Samoila .val_bits = 32, 94147a70e6fSCosmin Samoila 94247a70e6fSCosmin Samoila .max_register = REG_MICFIL_VAD0_ZCD, 94347a70e6fSCosmin Samoila .reg_defaults = fsl_micfil_reg_defaults, 94447a70e6fSCosmin Samoila .num_reg_defaults = ARRAY_SIZE(fsl_micfil_reg_defaults), 94547a70e6fSCosmin Samoila .readable_reg = fsl_micfil_readable_reg, 94647a70e6fSCosmin Samoila .volatile_reg = fsl_micfil_volatile_reg, 94747a70e6fSCosmin Samoila .writeable_reg = fsl_micfil_writeable_reg, 94847a70e6fSCosmin Samoila .cache_type = REGCACHE_RBTREE, 94947a70e6fSCosmin Samoila }; 95047a70e6fSCosmin Samoila 95147a70e6fSCosmin Samoila /* END OF REGMAP */ 95247a70e6fSCosmin Samoila 95347a70e6fSCosmin Samoila static irqreturn_t micfil_isr(int irq, void *devid) 95447a70e6fSCosmin Samoila { 95547a70e6fSCosmin Samoila struct fsl_micfil *micfil = (struct fsl_micfil *)devid; 95647a70e6fSCosmin Samoila struct platform_device *pdev = micfil->pdev; 95747a70e6fSCosmin Samoila u32 stat_reg; 95847a70e6fSCosmin Samoila u32 fifo_stat_reg; 95947a70e6fSCosmin Samoila u32 ctrl1_reg; 96047a70e6fSCosmin Samoila bool dma_enabled; 96147a70e6fSCosmin Samoila int i; 96247a70e6fSCosmin Samoila 96347a70e6fSCosmin Samoila regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); 96447a70e6fSCosmin Samoila regmap_read(micfil->regmap, REG_MICFIL_CTRL1, &ctrl1_reg); 96547a70e6fSCosmin Samoila regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); 96647a70e6fSCosmin Samoila 96717f2142bSSascha Hauer dma_enabled = FIELD_GET(MICFIL_CTRL1_DISEL, ctrl1_reg) == MICFIL_CTRL1_DISEL_DMA; 96847a70e6fSCosmin Samoila 96947a70e6fSCosmin Samoila /* Channel 0-7 Output Data Flags */ 97047a70e6fSCosmin Samoila for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) { 97117f2142bSSascha Hauer if (stat_reg & MICFIL_STAT_CHXF(i)) 97247a70e6fSCosmin Samoila dev_dbg(&pdev->dev, 97347a70e6fSCosmin Samoila "Data available in Data Channel %d\n", i); 97447a70e6fSCosmin Samoila /* if DMA is not enabled, field must be written with 1 97547a70e6fSCosmin Samoila * to clear 97647a70e6fSCosmin Samoila */ 97747a70e6fSCosmin Samoila if (!dma_enabled) 97847a70e6fSCosmin Samoila regmap_write_bits(micfil->regmap, 97947a70e6fSCosmin Samoila REG_MICFIL_STAT, 98017f2142bSSascha Hauer MICFIL_STAT_CHXF(i), 98147a70e6fSCosmin Samoila 1); 98247a70e6fSCosmin Samoila } 98347a70e6fSCosmin Samoila 98447a70e6fSCosmin Samoila for (i = 0; i < MICFIL_FIFO_NUM; i++) { 98517f2142bSSascha Hauer if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_OVER(i)) 98647a70e6fSCosmin Samoila dev_dbg(&pdev->dev, 98747a70e6fSCosmin Samoila "FIFO Overflow Exception flag for channel %d\n", 98847a70e6fSCosmin Samoila i); 98947a70e6fSCosmin Samoila 99017f2142bSSascha Hauer if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_UNDER(i)) 99147a70e6fSCosmin Samoila dev_dbg(&pdev->dev, 99247a70e6fSCosmin Samoila "FIFO Underflow Exception flag for channel %d\n", 99347a70e6fSCosmin Samoila i); 99447a70e6fSCosmin Samoila } 99547a70e6fSCosmin Samoila 99647a70e6fSCosmin Samoila return IRQ_HANDLED; 99747a70e6fSCosmin Samoila } 99847a70e6fSCosmin Samoila 99947a70e6fSCosmin Samoila static irqreturn_t micfil_err_isr(int irq, void *devid) 100047a70e6fSCosmin Samoila { 100147a70e6fSCosmin Samoila struct fsl_micfil *micfil = (struct fsl_micfil *)devid; 100247a70e6fSCosmin Samoila struct platform_device *pdev = micfil->pdev; 100347a70e6fSCosmin Samoila u32 stat_reg; 100447a70e6fSCosmin Samoila 100547a70e6fSCosmin Samoila regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); 100647a70e6fSCosmin Samoila 1007bd2cffd1SSascha Hauer if (stat_reg & MICFIL_STAT_BSY_FIL) 100847a70e6fSCosmin Samoila dev_dbg(&pdev->dev, "isr: Decimation Filter is running\n"); 100947a70e6fSCosmin Samoila 1010bd2cffd1SSascha Hauer if (stat_reg & MICFIL_STAT_FIR_RDY) 101147a70e6fSCosmin Samoila dev_dbg(&pdev->dev, "isr: FIR Filter Data ready\n"); 101247a70e6fSCosmin Samoila 1013bd2cffd1SSascha Hauer if (stat_reg & MICFIL_STAT_LOWFREQF) { 101447a70e6fSCosmin Samoila dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); 101547a70e6fSCosmin Samoila regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, 1016bd2cffd1SSascha Hauer MICFIL_STAT_LOWFREQF, 1); 101747a70e6fSCosmin Samoila } 101847a70e6fSCosmin Samoila 101947a70e6fSCosmin Samoila return IRQ_HANDLED; 102047a70e6fSCosmin Samoila } 102147a70e6fSCosmin Samoila 102229dbfeecSShengjiu Wang static irqreturn_t voice_detected_fn(int irq, void *devid) 102329dbfeecSShengjiu Wang { 102429dbfeecSShengjiu Wang struct fsl_micfil *micfil = (struct fsl_micfil *)devid; 102529dbfeecSShengjiu Wang struct snd_kcontrol *kctl; 102629dbfeecSShengjiu Wang 102729dbfeecSShengjiu Wang if (!micfil->card) 102829dbfeecSShengjiu Wang return IRQ_HANDLED; 102929dbfeecSShengjiu Wang 103029dbfeecSShengjiu Wang kctl = snd_soc_card_get_kcontrol(micfil->card, "VAD Detected"); 103129dbfeecSShengjiu Wang if (!kctl) 103229dbfeecSShengjiu Wang return IRQ_HANDLED; 103329dbfeecSShengjiu Wang 103429dbfeecSShengjiu Wang if (micfil->vad_detected) 103529dbfeecSShengjiu Wang snd_ctl_notify(micfil->card->snd_card, 103629dbfeecSShengjiu Wang SNDRV_CTL_EVENT_MASK_VALUE, 103729dbfeecSShengjiu Wang &kctl->id); 103829dbfeecSShengjiu Wang 103929dbfeecSShengjiu Wang return IRQ_HANDLED; 104029dbfeecSShengjiu Wang } 104129dbfeecSShengjiu Wang 104229dbfeecSShengjiu Wang static irqreturn_t hwvad_isr(int irq, void *devid) 104329dbfeecSShengjiu Wang { 104429dbfeecSShengjiu Wang struct fsl_micfil *micfil = (struct fsl_micfil *)devid; 104529dbfeecSShengjiu Wang struct device *dev = &micfil->pdev->dev; 104629dbfeecSShengjiu Wang u32 vad0_reg; 104729dbfeecSShengjiu Wang int ret; 104829dbfeecSShengjiu Wang 104929dbfeecSShengjiu Wang regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg); 105029dbfeecSShengjiu Wang 105129dbfeecSShengjiu Wang /* 105229dbfeecSShengjiu Wang * The only difference between MICFIL_VAD0_STAT_EF and 105329dbfeecSShengjiu Wang * MICFIL_VAD0_STAT_IF is that the former requires Write 105429dbfeecSShengjiu Wang * 1 to Clear. Since both flags are set, it is enough 105529dbfeecSShengjiu Wang * to only read one of them 105629dbfeecSShengjiu Wang */ 105729dbfeecSShengjiu Wang if (vad0_reg & MICFIL_VAD0_STAT_IF) { 105829dbfeecSShengjiu Wang /* Write 1 to clear */ 105929dbfeecSShengjiu Wang regmap_write_bits(micfil->regmap, REG_MICFIL_VAD0_STAT, 106029dbfeecSShengjiu Wang MICFIL_VAD0_STAT_IF, 106129dbfeecSShengjiu Wang MICFIL_VAD0_STAT_IF); 106229dbfeecSShengjiu Wang 106329dbfeecSShengjiu Wang micfil->vad_detected = 1; 106429dbfeecSShengjiu Wang } 106529dbfeecSShengjiu Wang 106629dbfeecSShengjiu Wang ret = fsl_micfil_hwvad_disable(micfil); 106729dbfeecSShengjiu Wang if (ret) 106829dbfeecSShengjiu Wang dev_err(dev, "Failed to disable hwvad\n"); 106929dbfeecSShengjiu Wang 107029dbfeecSShengjiu Wang return IRQ_WAKE_THREAD; 107129dbfeecSShengjiu Wang } 107229dbfeecSShengjiu Wang 107329dbfeecSShengjiu Wang static irqreturn_t hwvad_err_isr(int irq, void *devid) 107429dbfeecSShengjiu Wang { 107529dbfeecSShengjiu Wang struct fsl_micfil *micfil = (struct fsl_micfil *)devid; 107629dbfeecSShengjiu Wang struct device *dev = &micfil->pdev->dev; 107729dbfeecSShengjiu Wang u32 vad0_reg; 107829dbfeecSShengjiu Wang 107929dbfeecSShengjiu Wang regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg); 108029dbfeecSShengjiu Wang 108129dbfeecSShengjiu Wang if (vad0_reg & MICFIL_VAD0_STAT_INSATF) 108229dbfeecSShengjiu Wang dev_dbg(dev, "voice activity input overflow/underflow detected\n"); 108329dbfeecSShengjiu Wang 108429dbfeecSShengjiu Wang return IRQ_HANDLED; 108529dbfeecSShengjiu Wang } 108629dbfeecSShengjiu Wang 108736736505SChancel Liu static int fsl_micfil_runtime_suspend(struct device *dev); 108836736505SChancel Liu static int fsl_micfil_runtime_resume(struct device *dev); 108936736505SChancel Liu 109047a70e6fSCosmin Samoila static int fsl_micfil_probe(struct platform_device *pdev) 109147a70e6fSCosmin Samoila { 109247a70e6fSCosmin Samoila struct device_node *np = pdev->dev.of_node; 109347a70e6fSCosmin Samoila struct fsl_micfil *micfil; 109447a70e6fSCosmin Samoila struct resource *res; 109547a70e6fSCosmin Samoila void __iomem *regs; 109647a70e6fSCosmin Samoila int ret, i; 109747a70e6fSCosmin Samoila 109847a70e6fSCosmin Samoila micfil = devm_kzalloc(&pdev->dev, sizeof(*micfil), GFP_KERNEL); 109947a70e6fSCosmin Samoila if (!micfil) 110047a70e6fSCosmin Samoila return -ENOMEM; 110147a70e6fSCosmin Samoila 110247a70e6fSCosmin Samoila micfil->pdev = pdev; 11037eb10bfbSJustin Stitt strscpy(micfil->name, np->name, sizeof(micfil->name)); 110447a70e6fSCosmin Samoila 1105d7388718SFabio Estevam micfil->soc = of_device_get_match_data(&pdev->dev); 110647a70e6fSCosmin Samoila 110747a70e6fSCosmin Samoila /* ipg_clk is used to control the registers 110847a70e6fSCosmin Samoila * ipg_clk_app is used to operate the filter 110947a70e6fSCosmin Samoila */ 111047a70e6fSCosmin Samoila micfil->mclk = devm_clk_get(&pdev->dev, "ipg_clk_app"); 111147a70e6fSCosmin Samoila if (IS_ERR(micfil->mclk)) { 111247a70e6fSCosmin Samoila dev_err(&pdev->dev, "failed to get core clock: %ld\n", 111347a70e6fSCosmin Samoila PTR_ERR(micfil->mclk)); 111447a70e6fSCosmin Samoila return PTR_ERR(micfil->mclk); 111547a70e6fSCosmin Samoila } 111647a70e6fSCosmin Samoila 1117b5cf28f7SShengjiu Wang micfil->busclk = devm_clk_get(&pdev->dev, "ipg_clk"); 1118b5cf28f7SShengjiu Wang if (IS_ERR(micfil->busclk)) { 1119b5cf28f7SShengjiu Wang dev_err(&pdev->dev, "failed to get ipg clock: %ld\n", 1120b5cf28f7SShengjiu Wang PTR_ERR(micfil->busclk)); 1121b5cf28f7SShengjiu Wang return PTR_ERR(micfil->busclk); 1122b5cf28f7SShengjiu Wang } 1123b5cf28f7SShengjiu Wang 112493f54100SShengjiu Wang fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk, 112593f54100SShengjiu Wang &micfil->pll11k_clk); 112693f54100SShengjiu Wang 112747a70e6fSCosmin Samoila /* init regmap */ 1128d9bf1e79SYang Yingliang regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 112947a70e6fSCosmin Samoila if (IS_ERR(regs)) 113047a70e6fSCosmin Samoila return PTR_ERR(regs); 113147a70e6fSCosmin Samoila 1132b5cf28f7SShengjiu Wang micfil->regmap = devm_regmap_init_mmio(&pdev->dev, 113347a70e6fSCosmin Samoila regs, 113447a70e6fSCosmin Samoila &fsl_micfil_regmap_config); 113547a70e6fSCosmin Samoila if (IS_ERR(micfil->regmap)) { 113647a70e6fSCosmin Samoila dev_err(&pdev->dev, "failed to init MICFIL regmap: %ld\n", 113747a70e6fSCosmin Samoila PTR_ERR(micfil->regmap)); 113847a70e6fSCosmin Samoila return PTR_ERR(micfil->regmap); 113947a70e6fSCosmin Samoila } 114047a70e6fSCosmin Samoila 114147a70e6fSCosmin Samoila /* dataline mask for RX */ 114247a70e6fSCosmin Samoila ret = of_property_read_u32_index(np, 114347a70e6fSCosmin Samoila "fsl,dataline", 114447a70e6fSCosmin Samoila 0, 114547a70e6fSCosmin Samoila &micfil->dataline); 114647a70e6fSCosmin Samoila if (ret) 114747a70e6fSCosmin Samoila micfil->dataline = 1; 114847a70e6fSCosmin Samoila 114947a70e6fSCosmin Samoila if (micfil->dataline & ~micfil->soc->dataline) { 115047a70e6fSCosmin Samoila dev_err(&pdev->dev, "dataline setting error, Mask is 0x%X\n", 115147a70e6fSCosmin Samoila micfil->soc->dataline); 115247a70e6fSCosmin Samoila return -EINVAL; 115347a70e6fSCosmin Samoila } 115447a70e6fSCosmin Samoila 115547a70e6fSCosmin Samoila /* get IRQs */ 115647a70e6fSCosmin Samoila for (i = 0; i < MICFIL_IRQ_LINES; i++) { 115747a70e6fSCosmin Samoila micfil->irq[i] = platform_get_irq(pdev, i); 115883b35f45STang Bin if (micfil->irq[i] < 0) 115947a70e6fSCosmin Samoila return micfil->irq[i]; 116047a70e6fSCosmin Samoila } 116147a70e6fSCosmin Samoila 1162a62ed960SFabio Estevam /* Digital Microphone interface interrupt */ 116347a70e6fSCosmin Samoila ret = devm_request_irq(&pdev->dev, micfil->irq[0], 1164cbd090faSSascha Hauer micfil_isr, IRQF_SHARED, 116547a70e6fSCosmin Samoila micfil->name, micfil); 116647a70e6fSCosmin Samoila if (ret) { 116747a70e6fSCosmin Samoila dev_err(&pdev->dev, "failed to claim mic interface irq %u\n", 116847a70e6fSCosmin Samoila micfil->irq[0]); 116947a70e6fSCosmin Samoila return ret; 117047a70e6fSCosmin Samoila } 117147a70e6fSCosmin Samoila 1172a62ed960SFabio Estevam /* Digital Microphone interface error interrupt */ 117347a70e6fSCosmin Samoila ret = devm_request_irq(&pdev->dev, micfil->irq[1], 1174cbd090faSSascha Hauer micfil_err_isr, IRQF_SHARED, 117547a70e6fSCosmin Samoila micfil->name, micfil); 117647a70e6fSCosmin Samoila if (ret) { 117747a70e6fSCosmin Samoila dev_err(&pdev->dev, "failed to claim mic interface error irq %u\n", 117847a70e6fSCosmin Samoila micfil->irq[1]); 117947a70e6fSCosmin Samoila return ret; 118047a70e6fSCosmin Samoila } 118147a70e6fSCosmin Samoila 118229dbfeecSShengjiu Wang /* Digital Microphone interface voice activity detector event */ 118329dbfeecSShengjiu Wang ret = devm_request_threaded_irq(&pdev->dev, micfil->irq[2], 118429dbfeecSShengjiu Wang hwvad_isr, voice_detected_fn, 118529dbfeecSShengjiu Wang IRQF_SHARED, micfil->name, micfil); 118629dbfeecSShengjiu Wang if (ret) { 118729dbfeecSShengjiu Wang dev_err(&pdev->dev, "failed to claim hwvad event irq %u\n", 118829dbfeecSShengjiu Wang micfil->irq[0]); 118929dbfeecSShengjiu Wang return ret; 119029dbfeecSShengjiu Wang } 119129dbfeecSShengjiu Wang 119229dbfeecSShengjiu Wang /* Digital Microphone interface voice activity detector error */ 119329dbfeecSShengjiu Wang ret = devm_request_irq(&pdev->dev, micfil->irq[3], 119429dbfeecSShengjiu Wang hwvad_err_isr, IRQF_SHARED, 119529dbfeecSShengjiu Wang micfil->name, micfil); 119629dbfeecSShengjiu Wang if (ret) { 119729dbfeecSShengjiu Wang dev_err(&pdev->dev, "failed to claim hwvad error irq %u\n", 119829dbfeecSShengjiu Wang micfil->irq[1]); 119929dbfeecSShengjiu Wang return ret; 120029dbfeecSShengjiu Wang } 120129dbfeecSShengjiu Wang 120247a70e6fSCosmin Samoila micfil->dma_params_rx.chan_name = "rx"; 120347a70e6fSCosmin Samoila micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0; 120447a70e6fSCosmin Samoila micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX; 120547a70e6fSCosmin Samoila 120647a70e6fSCosmin Samoila platform_set_drvdata(pdev, micfil); 120747a70e6fSCosmin Samoila 120847a70e6fSCosmin Samoila pm_runtime_enable(&pdev->dev); 120936736505SChancel Liu if (!pm_runtime_enabled(&pdev->dev)) { 121036736505SChancel Liu ret = fsl_micfil_runtime_resume(&pdev->dev); 121136736505SChancel Liu if (ret) 121236736505SChancel Liu goto err_pm_disable; 121336736505SChancel Liu } 121436736505SChancel Liu 121536736505SChancel Liu ret = pm_runtime_resume_and_get(&pdev->dev); 121636736505SChancel Liu if (ret < 0) 121736736505SChancel Liu goto err_pm_get_sync; 121836736505SChancel Liu 121936736505SChancel Liu /* Get micfil version */ 122036736505SChancel Liu ret = fsl_micfil_use_verid(&pdev->dev); 122136736505SChancel Liu if (ret < 0) 122236736505SChancel Liu dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret); 122336736505SChancel Liu 122436736505SChancel Liu ret = pm_runtime_put_sync(&pdev->dev); 122536736505SChancel Liu if (ret < 0 && ret != -ENOSYS) 122636736505SChancel Liu goto err_pm_get_sync; 122736736505SChancel Liu 1228b5cf28f7SShengjiu Wang regcache_cache_only(micfil->regmap, true); 122947a70e6fSCosmin Samoila 12300adf2920SShengjiu Wang /* 12310adf2920SShengjiu Wang * Register platform component before registering cpu dai for there 12320adf2920SShengjiu Wang * is not defer probe for platform component in snd_soc_add_pcm_runtime(). 12330adf2920SShengjiu Wang */ 12340adf2920SShengjiu Wang ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 12350adf2920SShengjiu Wang if (ret) { 12360adf2920SShengjiu Wang dev_err(&pdev->dev, "failed to pcm register\n"); 123717955abaSShengjiu Wang goto err_pm_disable; 12380adf2920SShengjiu Wang } 12390adf2920SShengjiu Wang 1240cb05dac1SShengjiu Wang fsl_micfil_dai.capture.formats = micfil->soc->formats; 1241cb05dac1SShengjiu Wang 124247a70e6fSCosmin Samoila ret = devm_snd_soc_register_component(&pdev->dev, &fsl_micfil_component, 124347a70e6fSCosmin Samoila &fsl_micfil_dai, 1); 124447a70e6fSCosmin Samoila if (ret) { 124547a70e6fSCosmin Samoila dev_err(&pdev->dev, "failed to register component %s\n", 124647a70e6fSCosmin Samoila fsl_micfil_component.name); 124717955abaSShengjiu Wang goto err_pm_disable; 124847a70e6fSCosmin Samoila } 124947a70e6fSCosmin Samoila 125047a70e6fSCosmin Samoila return ret; 125117955abaSShengjiu Wang 125236736505SChancel Liu err_pm_get_sync: 125336736505SChancel Liu if (!pm_runtime_status_suspended(&pdev->dev)) 125436736505SChancel Liu fsl_micfil_runtime_suspend(&pdev->dev); 125517955abaSShengjiu Wang err_pm_disable: 125617955abaSShengjiu Wang pm_runtime_disable(&pdev->dev); 125717955abaSShengjiu Wang 125817955abaSShengjiu Wang return ret; 125917955abaSShengjiu Wang } 126017955abaSShengjiu Wang 126117955abaSShengjiu Wang static void fsl_micfil_remove(struct platform_device *pdev) 126217955abaSShengjiu Wang { 126317955abaSShengjiu Wang pm_runtime_disable(&pdev->dev); 126447a70e6fSCosmin Samoila } 126547a70e6fSCosmin Samoila 126636736505SChancel Liu static int fsl_micfil_runtime_suspend(struct device *dev) 126747a70e6fSCosmin Samoila { 126847a70e6fSCosmin Samoila struct fsl_micfil *micfil = dev_get_drvdata(dev); 126947a70e6fSCosmin Samoila 127047a70e6fSCosmin Samoila regcache_cache_only(micfil->regmap, true); 127147a70e6fSCosmin Samoila 127247a70e6fSCosmin Samoila clk_disable_unprepare(micfil->mclk); 1273b5cf28f7SShengjiu Wang clk_disable_unprepare(micfil->busclk); 127447a70e6fSCosmin Samoila 127547a70e6fSCosmin Samoila return 0; 127647a70e6fSCosmin Samoila } 127747a70e6fSCosmin Samoila 127836736505SChancel Liu static int fsl_micfil_runtime_resume(struct device *dev) 127947a70e6fSCosmin Samoila { 128047a70e6fSCosmin Samoila struct fsl_micfil *micfil = dev_get_drvdata(dev); 128147a70e6fSCosmin Samoila int ret; 128247a70e6fSCosmin Samoila 1283b5cf28f7SShengjiu Wang ret = clk_prepare_enable(micfil->busclk); 128447a70e6fSCosmin Samoila if (ret < 0) 128547a70e6fSCosmin Samoila return ret; 128647a70e6fSCosmin Samoila 1287b5cf28f7SShengjiu Wang ret = clk_prepare_enable(micfil->mclk); 1288b5cf28f7SShengjiu Wang if (ret < 0) { 1289b5cf28f7SShengjiu Wang clk_disable_unprepare(micfil->busclk); 1290b5cf28f7SShengjiu Wang return ret; 1291b5cf28f7SShengjiu Wang } 1292b5cf28f7SShengjiu Wang 129347a70e6fSCosmin Samoila regcache_cache_only(micfil->regmap, false); 129447a70e6fSCosmin Samoila regcache_mark_dirty(micfil->regmap); 129547a70e6fSCosmin Samoila regcache_sync(micfil->regmap); 129647a70e6fSCosmin Samoila 129747a70e6fSCosmin Samoila return 0; 129847a70e6fSCosmin Samoila } 129947a70e6fSCosmin Samoila 130047a70e6fSCosmin Samoila static const struct dev_pm_ops fsl_micfil_pm_ops = { 130147a70e6fSCosmin Samoila SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, 130247a70e6fSCosmin Samoila fsl_micfil_runtime_resume, 130347a70e6fSCosmin Samoila NULL) 1304*a38a4090SChancel Liu SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 1305*a38a4090SChancel Liu pm_runtime_force_resume) 130647a70e6fSCosmin Samoila }; 130747a70e6fSCosmin Samoila 130847a70e6fSCosmin Samoila static struct platform_driver fsl_micfil_driver = { 130947a70e6fSCosmin Samoila .probe = fsl_micfil_probe, 131017955abaSShengjiu Wang .remove_new = fsl_micfil_remove, 131147a70e6fSCosmin Samoila .driver = { 131247a70e6fSCosmin Samoila .name = "fsl-micfil-dai", 131347a70e6fSCosmin Samoila .pm = &fsl_micfil_pm_ops, 131447a70e6fSCosmin Samoila .of_match_table = fsl_micfil_dt_ids, 131547a70e6fSCosmin Samoila }, 131647a70e6fSCosmin Samoila }; 131747a70e6fSCosmin Samoila module_platform_driver(fsl_micfil_driver); 131847a70e6fSCosmin Samoila 131947a70e6fSCosmin Samoila MODULE_AUTHOR("Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>"); 132047a70e6fSCosmin Samoila MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver"); 132147a70e6fSCosmin Samoila MODULE_LICENSE("GPL v2"); 1322