summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/adi/axi-i2s.c2
-rw-r--r--sound/soc/adi/axi-spdif.c2
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c41
-rw-r--r--sound/soc/amd/acp-rt5645.c22
-rw-r--r--sound/soc/amd/acp/acp-i2s.c24
-rw-r--r--sound/soc/amd/acp/acp-legacy-mach.c22
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c294
-rw-r--r--sound/soc/amd/acp/acp-rembrandt.c3
-rw-r--r--sound/soc/amd/acp/acp-renoir.c2
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c21
-rw-r--r--sound/soc/amd/acp/amd.h1
-rw-r--r--sound/soc/amd/acp3x-rt5682-max9836.c23
-rw-r--r--sound/soc/amd/vangogh/acp5x-mach.c3
-rw-r--r--sound/soc/atmel/atmel-i2s.c18
-rw-r--r--sound/soc/atmel/atmel-pdmic.c2
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c26
-rw-r--r--sound/soc/atmel/mchp-pdmc.c18
-rw-r--r--sound/soc/atmel/mchp-spdifrx.c16
-rw-r--r--sound/soc/atmel/mchp-spdiftx.c20
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c2
-rw-r--r--sound/soc/au1x/ac97c.c10
-rw-r--r--sound/soc/au1x/psc-ac97.c2
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c24
-rw-r--r--sound/soc/bcm/cygnus-ssp.h2
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c2
-rw-r--r--sound/soc/codecs/88pm860x-codec.c4
-rw-r--r--sound/soc/codecs/Kconfig45
-rw-r--r--sound/soc/codecs/Makefile12
-rw-r--r--sound/soc/codecs/ak4613.c11
-rw-r--r--sound/soc/codecs/aw88261.c1300
-rw-r--r--sound/soc/codecs/aw88261.h459
-rw-r--r--sound/soc/codecs/aw88395/aw88395_lib.c193
-rw-r--r--sound/soc/codecs/aw88395/aw88395_reg.h1
-rw-r--r--sound/soc/codecs/cs35l56.c52
-rw-r--r--sound/soc/codecs/cs42l43-jack.c946
-rw-r--r--sound/soc/codecs/cs42l43-sdw.c74
-rw-r--r--sound/soc/codecs/cs42l43.c2278
-rw-r--r--sound/soc/codecs/cs42l43.h131
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c2
-rw-r--r--sound/soc/codecs/cs47l15.c6
-rw-r--r--sound/soc/codecs/cs47l24.c8
-rw-r--r--sound/soc/codecs/cs47l35.c8
-rw-r--r--sound/soc/codecs/cs47l85.c8
-rw-r--r--sound/soc/codecs/cs47l90.c8
-rw-r--r--sound/soc/codecs/cs47l92.c6
-rw-r--r--sound/soc/codecs/cx2072x.c11
-rw-r--r--sound/soc/codecs/es8326.c312
-rw-r--r--sound/soc/codecs/es8326.h23
-rw-r--r--sound/soc/codecs/hdmi-codec.c44
-rw-r--r--sound/soc/codecs/jz4740.c2
-rw-r--r--sound/soc/codecs/l3.c132
-rw-r--r--sound/soc/codecs/max98363.c41
-rw-r--r--sound/soc/codecs/max98373-sdw.c47
-rw-r--r--sound/soc/codecs/max98926.c3
-rw-r--r--sound/soc/codecs/max98927.c357
-rw-r--r--sound/soc/codecs/nau8821.c42
-rw-r--r--sound/soc/codecs/nau8821.h25
-rw-r--r--sound/soc/codecs/rt1011.c2
-rw-r--r--sound/soc/codecs/rt1015.c1
-rw-r--r--sound/soc/codecs/rt1015p.c1
-rw-r--r--sound/soc/codecs/rt1016.c1
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c824
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.h183
-rw-r--r--sound/soc/codecs/rt1019.c1
-rw-r--r--sound/soc/codecs/rt1305.c2
-rw-r--r--sound/soc/codecs/rt1308-sdw.c54
-rw-r--r--sound/soc/codecs/rt1308.c2
-rw-r--r--sound/soc/codecs/rt1316-sdw.c56
-rw-r--r--sound/soc/codecs/rt1318-sdw.c43
-rw-r--r--sound/soc/codecs/rt5514-spi.c1
-rw-r--r--sound/soc/codecs/rt5514.c1
-rw-r--r--sound/soc/codecs/rt5640.c59
-rw-r--r--sound/soc/codecs/rt5640.h2
-rw-r--r--sound/soc/codecs/rt5645.c19
-rw-r--r--sound/soc/codecs/rt5659.c1
-rw-r--r--sound/soc/codecs/rt5660.c2
-rw-r--r--sound/soc/codecs/rt5665.c17
-rw-r--r--sound/soc/codecs/rt5668.c17
-rw-r--r--sound/soc/codecs/rt5682-i2c.c11
-rw-r--r--sound/soc/codecs/rt5682-sdw.c63
-rw-r--r--sound/soc/codecs/rt5682.c23
-rw-r--r--sound/soc/codecs/rt5682.h3
-rw-r--r--sound/soc/codecs/rt5682s.c16
-rw-r--r--sound/soc/codecs/rt5682s.h2
-rw-r--r--sound/soc/codecs/rt700-sdw.c7
-rw-r--r--sound/soc/codecs/rt700.c46
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c3
-rw-r--r--sound/soc/codecs/rt711-sdca.c48
-rw-r--r--sound/soc/codecs/rt711-sdw.c7
-rw-r--r--sound/soc/codecs/rt711.c47
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c47
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c3
-rw-r--r--sound/soc/codecs/rt712-sdca.c45
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c5
-rw-r--r--sound/soc/codecs/rt715-sdca.c41
-rw-r--r--sound/soc/codecs/rt715-sdw.c9
-rw-r--r--sound/soc/codecs/rt715.c100
-rw-r--r--sound/soc/codecs/rt715.h7
-rw-r--r--sound/soc/codecs/ssm3515.c2
-rw-r--r--sound/soc/codecs/sta32x.c2
-rw-r--r--sound/soc/codecs/sta350.c2
-rw-r--r--sound/soc/codecs/sta529.c2
-rw-r--r--sound/soc/codecs/stac9766.c2
-rw-r--r--sound/soc/codecs/sti-sas.c2
-rw-r--r--sound/soc/codecs/tas5805m.c3
-rw-r--r--sound/soc/codecs/tlv320aic32x4-clk.c16
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c2
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h5
-rw-r--r--sound/soc/codecs/uda134x.c587
-rw-r--r--sound/soc/codecs/uda134x.h33
-rw-r--r--sound/soc/codecs/wm2200.c12
-rw-r--r--sound/soc/codecs/wm5102.c6
-rw-r--r--sound/soc/codecs/wm5110.c8
-rw-r--r--sound/soc/codecs/wm8904.c2
-rw-r--r--sound/soc/codecs/wm8960.c42
-rw-r--r--sound/soc/codecs/wm8960.h4
-rw-r--r--sound/soc/codecs/wm8994.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c24
-rw-r--r--sound/soc/codecs/wm_adsp.h3
-rw-r--r--sound/soc/dwc/dwc-i2s.c314
-rw-r--r--sound/soc/dwc/local.h1
-rw-r--r--sound/soc/fsl/fsl_asrc.c16
-rw-r--r--sound/soc/fsl/fsl_aud2htx.c10
-rw-r--r--sound/soc/fsl/fsl_easrc.c16
-rw-r--r--sound/soc/fsl/fsl_esai.c20
-rw-r--r--sound/soc/fsl/fsl_micfil.c116
-rw-r--r--sound/soc/fsl/fsl_micfil.h64
-rw-r--r--sound/soc/fsl/fsl_qmc_audio.c28
-rw-r--r--sound/soc/fsl/fsl_sai.c24
-rw-r--r--sound/soc/fsl/fsl_spdif.c17
-rw-r--r--sound/soc/fsl/fsl_ssi.c3
-rw-r--r--sound/soc/fsl/fsl_xcvr.c16
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c1
-rw-r--r--sound/soc/fsl/imx-es8328.c25
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c2
-rw-r--r--sound/soc/generic/audio-graph-card.c141
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample.dtsi7
-rw-r--r--sound/soc/generic/audio-graph-card2.c12
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c2
-rw-r--r--sound/soc/img/img-i2s-in.c14
-rw-r--r--sound/soc/img/img-i2s-out.c14
-rw-r--r--sound/soc/img/img-parallel-out.c14
-rw-r--r--sound/soc/img/img-spdif-in.c12
-rw-r--r--sound/soc/img/img-spdif-out.c12
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c2
-rw-r--r--sound/soc/intel/atom/sst/sst_stream.c13
-rw-r--r--sound/soc/intel/avs/boards/da7219.c34
-rw-r--r--sound/soc/intel/avs/probes.c10
-rw-r--r--sound/soc/intel/avs/topology.c6
-rw-r--r--sound/soc/intel/boards/Kconfig5
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bdw_rt286.c6
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c7
-rw-r--r--sound/soc/intel/boards/bytcr_wm5102.c7
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c7
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c7
-rw-r--r--sound/soc/intel/boards/sof_da7219_max98373.c10
-rw-r--r--sound/soc/intel/boards/sof_es8336.c10
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.c170
-rw-r--r--sound/soc/intel/boards/sof_maxim_common.h21
-rw-r--r--sound/soc/intel/boards/sof_nau8825.c10
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c92
-rw-r--r--sound/soc/intel/boards/sof_sdw.c608
-rw-r--r--sound/soc/intel/boards/sof_sdw_common.h7
-rw-r--r--sound/soc/intel/boards/sof_sdw_cs_amp.c47
-rw-r--r--sound/soc/intel/boards/sof_ssp_amp.c9
-rw-r--r--sound/soc/intel/catpt/pcm.c8
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c7
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c52
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-rpl-match.c69
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c4
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c3
-rw-r--r--sound/soc/loongson/loongson_card.c2
-rw-r--r--sound/soc/loongson/loongson_i2s.c16
-rw-r--r--sound/soc/mediatek/Kconfig20
-rw-r--r--sound/soc/mediatek/Makefile1
-rw-r--r--sound/soc/mediatek/mt7986/Makefile9
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-afe-common.h49
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-afe-pcm.c622
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-dai-etdm.c411
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-reg.h196
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-wm8960.c196
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c23
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c23
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c23
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c43
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c53
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-clk.c2
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c6
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-dai-etdm.c56
-rw-r--r--sound/soc/meson/aiu-acodec-ctrl.c4
-rw-r--r--sound/soc/meson/aiu-codec-ctrl.c4
-rw-r--r--sound/soc/meson/aiu-fifo-i2s.c3
-rw-r--r--sound/soc/meson/aiu-fifo-spdif.c3
-rw-r--r--sound/soc/meson/aiu.c6
-rw-r--r--sound/soc/meson/axg-frddr.c4
-rw-r--r--sound/soc/meson/axg-pdm.c18
-rw-r--r--sound/soc/meson/axg-spdifin.c4
-rw-r--r--sound/soc/meson/axg-tdm-interface.c6
-rw-r--r--sound/soc/meson/axg-toddr.c4
-rw-r--r--sound/soc/meson/g12a-toacodec.c4
-rw-r--r--sound/soc/meson/g12a-tohdmitx.c4
-rw-r--r--sound/soc/pxa/mmp-sspa.c2
-rw-r--r--sound/soc/pxa/pxa-ssp.c12
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c4
-rw-r--r--sound/soc/qcom/apq8016_sbc.c37
-rw-r--r--sound/soc/qcom/lpass-apq8016.c4
-rw-r--r--sound/soc/qcom/lpass-cpu.c40
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c1
-rw-r--r--sound/soc/qcom/lpass-sc7180.c5
-rw-r--r--sound/soc/qcom/lpass-sc7280.c2
-rw-r--r--sound/soc/qcom/lpass.h4
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c88
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.h2
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c6
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c3
-rw-r--r--sound/soc/qcom/sc7180.c40
-rw-r--r--sound/soc/qcom/sc7280.c34
-rw-r--r--sound/soc/qcom/sdm845.c32
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c7
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c2
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.c2
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c4
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c22
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c2
-rw-r--r--sound/soc/samsung/aries_wm8994.c10
-rw-r--r--sound/soc/samsung/i2s.c5
-rw-r--r--sound/soc/samsung/littlemill.c27
-rw-r--r--sound/soc/samsung/lowland.c8
-rw-r--r--sound/soc/samsung/midas_wm1811.c34
-rw-r--r--sound/soc/samsung/odroid.c15
-rw-r--r--sound/soc/samsung/pcm.c18
-rw-r--r--sound/soc/samsung/tm2_wm5110.c10
-rw-r--r--sound/soc/sh/rcar/adg.c68
-rw-r--r--sound/soc/sh/rcar/core.c175
-rw-r--r--sound/soc/sh/rcar/rsnd.h4
-rw-r--r--sound/soc/soc-acpi.c73
-rw-r--r--sound/soc/soc-core.c10
-rw-r--r--sound/soc/soc-dai.c55
-rw-r--r--sound/soc/soc-dapm.c2
-rw-r--r--sound/soc/soc-jack.c2
-rw-r--r--sound/soc/soc-topology.c6
-rw-r--r--sound/soc/sof/amd/Kconfig12
-rw-r--r--sound/soc/sof/amd/Makefile4
-rw-r--r--sound/soc/sof/amd/acp-dsp-offset.h9
-rw-r--r--sound/soc/sof/amd/acp-ipc.c4
-rw-r--r--sound/soc/sof/amd/acp-loader.c42
-rw-r--r--sound/soc/sof/amd/acp.c72
-rw-r--r--sound/soc/sof/amd/acp.h22
-rw-r--r--sound/soc/sof/amd/pci-vangogh.c105
-rw-r--r--sound/soc/sof/amd/vangogh.c162
-rw-r--r--sound/soc/sof/intel/Kconfig16
-rw-r--r--sound/soc/sof/intel/Makefile4
-rw-r--r--sound/soc/sof/intel/cnl.c2
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c179
-rw-r--r--sound/soc/sof/intel/hda-dai.c211
-rw-r--r--sound/soc/sof/intel/hda-mlink.c45
-rw-r--r--sound/soc/sof/intel/hda-stream.c68
-rw-r--r--sound/soc/sof/intel/hda.c140
-rw-r--r--sound/soc/sof/intel/hda.h21
-rw-r--r--sound/soc/sof/intel/icl.c1
-rw-r--r--sound/soc/sof/intel/lnl.c188
-rw-r--r--sound/soc/sof/intel/mtl.c23
-rw-r--r--sound/soc/sof/intel/mtl.h22
-rw-r--r--sound/soc/sof/intel/pci-lnl.c71
-rw-r--r--sound/soc/sof/intel/shim.h1
-rw-r--r--sound/soc/sof/intel/tgl.c4
-rw-r--r--sound/soc/sof/ipc3-dtrace.c12
-rw-r--r--sound/soc/sof/ipc3-pcm.c17
-rw-r--r--sound/soc/sof/ipc3.c7
-rw-r--r--sound/soc/sof/ipc4-pcm.c21
-rw-r--r--sound/soc/sof/ipc4-topology.c167
-rw-r--r--sound/soc/sof/ipc4-topology.h4
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c40
-rw-r--r--sound/soc/sof/sof-client-probes-ipc4.c9
-rw-r--r--sound/soc/sof/sof-client-probes.c6
-rw-r--r--sound/soc/sof/topology.c29
-rw-r--r--sound/soc/starfive/jh7110_tdm.c16
-rw-r--r--sound/soc/sti/sti_uniperif.c6
-rw-r--r--sound/soc/stm/stm32_i2s.c2
-rw-r--r--sound/soc/stm/stm32_sai_sub.c18
-rw-r--r--sound/soc/stm/stm32_spdifrx.c2
-rw-r--r--sound/soc/sunxi/sun4i-codec.c6
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c18
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c4
-rw-r--r--sound/soc/sunxi/sun50i-dmic.c2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c10
-rw-r--r--sound/soc/tegra/tegra20_i2s.c2
-rw-r--r--sound/soc/tegra/tegra20_spdif.c2
-rw-r--r--sound/soc/tegra/tegra210_admaif.c12
-rw-r--r--sound/soc/tegra/tegra30_i2s.c2
-rw-r--r--sound/soc/ti/davinci-evm.c13
-rw-r--r--sound/soc/ti/davinci-i2s.c22
-rw-r--r--sound/soc/ti/davinci-mcasp.c27
-rw-r--r--sound/soc/ti/omap-dmic.c22
-rw-r--r--sound/soc/ti/omap-mcbsp.c28
-rw-r--r--sound/soc/ti/omap-mcpdm.c22
-rw-r--r--sound/soc/uniphier/aio-cpu.c161
-rw-r--r--sound/soc/uniphier/aio-ld11.c62
-rw-r--r--sound/soc/uniphier/aio-pxs2.c55
-rw-r--r--sound/soc/uniphier/aio.h10
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c2
303 files changed, 13520 insertions, 3350 deletions
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c
index d5b6f5187f8e..7b2563075743 100644
--- a/sound/soc/adi/axi-i2s.c
+++ b/sound/soc/adi/axi-i2s.c
@@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
+ .probe = axi_i2s_dai_probe,
.startup = axi_i2s_startup,
.shutdown = axi_i2s_shutdown,
.trigger = axi_i2s_trigger,
@@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
};
static struct snd_soc_dai_driver axi_i2s_dai = {
- .probe = axi_i2s_dai_probe,
.ops = &axi_i2s_dai_ops,
.symmetric_rate = 1,
};
diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c
index e4c99bbc9cdd..10545bd99704 100644
--- a/sound/soc/adi/axi-spdif.c
+++ b/sound/soc/adi/axi-spdif.c
@@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
+ .probe = axi_spdif_dai_probe,
.startup = axi_spdif_startup,
.shutdown = axi_spdif_shutdown,
.trigger = axi_spdif_trigger,
@@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
};
static struct snd_soc_dai_driver axi_spdif_dai = {
- .probe = axi_spdif_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index 7464ca2b596c..9e3133bec2b1 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -28,6 +28,21 @@
#define RT5682_PLL_FREQ (48000 * 512)
static struct snd_soc_jack cz_jack;
+static struct snd_soc_jack_pin cz_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
static struct clk *da7219_dai_wclk;
static struct clk *da7219_dai_bclk;
static struct clk *rt5682_dai_wclk;
@@ -66,11 +81,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
if (IS_ERR(da7219_dai_bclk))
return PTR_ERR(da7219_dai_bclk);
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack,
+ cz_jack_pins,
+ ARRAY_SIZE(cz_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -146,11 +163,13 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
if (IS_ERR(rt5682_dai_bclk))
return PTR_ERR(rt5682_dai_bclk);
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack,
+ cz_jack_pins,
+ ARRAY_SIZE(cz_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
@@ -631,6 +650,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
static const struct snd_soc_dapm_widget cz_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
};
@@ -654,6 +674,7 @@ static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = {
static const struct snd_kcontrol_new cz_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
};
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
index 532aa98a2241..c8ed1e0b1ccd 100644
--- a/sound/soc/amd/acp-rt5645.c
+++ b/sound/soc/amd/acp-rt5645.c
@@ -42,6 +42,16 @@
#define CZ_PLAT_CLK 24000000
static struct snd_soc_jack cz_jack;
+static struct snd_soc_jack_pin cz_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
@@ -76,11 +86,13 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
codec = asoc_rtd_to_codec(rtd, 0)->component;
card = rtd->card;
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &cz_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &cz_jack,
+ cz_jack_pins,
+ ARRAY_SIZE(cz_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 09dc5f2c0bfc..df350014966a 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -539,17 +539,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
return 0;
}
-const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
- .startup = acp_i2s_startup,
- .hw_params = acp_i2s_hwparams,
- .prepare = acp_i2s_prepare,
- .trigger = acp_i2s_trigger,
- .set_fmt = acp_i2s_set_fmt,
- .set_tdm_slot = acp_i2s_set_tdm_slot,
-};
-EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
-
-int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
+static int acp_i2s_probe(struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = dev_get_drvdata(dev);
@@ -569,7 +559,17 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON);
+
+const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
+ .probe = acp_i2s_probe,
+ .startup = acp_i2s_startup,
+ .hw_params = acp_i2s_hwparams,
+ .prepare = acp_i2s_prepare,
+ .trigger = acp_i2s_trigger,
+ .set_fmt = acp_i2s_set_fmt,
+ .set_tdm_slot = acp_i2s_set_tdm_slot,
+};
+EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c
index 676ad50638d0..6d57d17ddfd7 100644
--- a/sound/soc/amd/acp/acp-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-legacy-mach.c
@@ -75,23 +75,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
.tdm_mode = false,
};
-static const struct snd_kcontrol_new acp_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-
-};
-
-static const struct snd_soc_dapm_widget acp_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
static int acp_asoc_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = NULL;
@@ -110,11 +93,8 @@ static int acp_asoc_probe(struct platform_device *pdev)
card->dev = dev;
card->owner = THIS_MODULE;
card->name = pdev->id_entry->name;
- card->dapm_widgets = acp_widgets;
- card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
- card->controls = acp_controls;
- card->num_controls = ARRAY_SIZE(acp_controls);
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+ /* Widgets and controls added per-codec in acp-mach-common.c */
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index ff5cbc4a6427..a06af82b8056 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -28,7 +28,6 @@
#include "../../codecs/nau8821.h"
#include "acp-mach.h"
-static struct snd_soc_jack vg_headset;
#define PCO_PLAT_CLK 48000000
#define RT5682_PLL_FREQ (48000 * 512)
#define DUAL_CHANNEL 2
@@ -52,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = {
};
EXPORT_SYMBOL_GPL(acp_quirk_table);
-static struct snd_soc_jack pco_jack;
-
static const unsigned int channels[] = {
DUAL_CHANNEL,
};
@@ -87,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata,
SND_SOC_DAILINK_DEF(rt5682,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
+static struct snd_soc_jack rt5682_jack;
+static struct snd_soc_jack_pin rt5682_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new rt5682_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget rt5682_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
static const struct snd_soc_dapm_route rt5682_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
@@ -110,22 +129,38 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets,
+ ARRAY_SIZE(rt5682_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, rt5682_controls,
+ ARRAY_SIZE(rt5682_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &rt5682_jack,
+ rt5682_jack_pins,
+ ARRAY_SIZE(rt5682_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
@@ -275,6 +310,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = {
SND_SOC_DAILINK_DEF(rt5682s,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
+static struct snd_soc_jack rt5682s_jack;
+static struct snd_soc_jack_pin rt5682s_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new rt5682s_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget rt5682s_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
static const struct snd_soc_dapm_route rt5682s_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
@@ -299,22 +356,38 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
}
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets,
+ ARRAY_SIZE(rt5682s_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, rt5682s_controls,
+ ARRAY_SIZE(rt5682s_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &rt5682s_jack,
+ rt5682s_jack_pins,
+ ARRAY_SIZE(rt5682s_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
@@ -440,6 +513,16 @@ SND_SOC_DAILINK_DEF(rt1019,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
+static const struct snd_kcontrol_new rt1019_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget rt1019_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
static const struct snd_soc_dapm_route rt1019_map_lr[] = {
{ "Left Spk", NULL, "Left SPO" },
{ "Right Spk", NULL, "Right SPO" },
@@ -460,10 +543,25 @@ static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret;
if (drvdata->amp_codec_id != RT1019)
return -EINVAL;
+ ret = snd_soc_dapm_new_controls(&card->dapm, rt1019_widgets,
+ ARRAY_SIZE(rt1019_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, rt1019_controls,
+ ARRAY_SIZE(rt1019_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
ARRAY_SIZE(rt1019_map_lr));
}
@@ -594,6 +692,14 @@ static const struct snd_soc_ops acp_card_rt1019_ops = {
SND_SOC_DAILINK_DEF(max98360a,
DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
+static const struct snd_kcontrol_new max98360a_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget max98360a_widgets[] = {
+ SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
static const struct snd_soc_dapm_route max98360a_map[] = {
{"Spk", NULL, "Speaker"},
};
@@ -602,10 +708,25 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
+ int ret;
if (drvdata->amp_codec_id != MAX98360A)
return -EINVAL;
+ ret = snd_soc_dapm_new_controls(&card->dapm, max98360a_widgets,
+ ARRAY_SIZE(max98360a_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, max98360a_controls,
+ ARRAY_SIZE(max98360a_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
ARRAY_SIZE(max98360a_map));
}
@@ -671,13 +792,19 @@ SND_SOC_DAILINK_DEF(max98388,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"),
COMP_CODEC("i2c-ADS8388:01", "max98388-aif1")));
+static const struct snd_kcontrol_new max98388_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Left Spk"),
+ SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
static const struct snd_soc_dapm_widget max98388_widgets[] = {
- SND_SOC_DAPM_SPK("SPK", NULL),
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
};
static const struct snd_soc_dapm_route max98388_map[] = {
- { "SPK", NULL, "Left BE_OUT" },
- { "SPK", NULL, "Right BE_OUT" },
+ { "Left Spk", NULL, "Left BE_OUT" },
+ { "Right Spk", NULL, "Right BE_OUT" },
};
static struct snd_soc_codec_conf max98388_conf[] = {
@@ -730,6 +857,14 @@ static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd)
/* Don't need to add routes if widget addition failed */
return ret;
}
+
+ ret = snd_soc_add_card_controls(card, max98388_controls,
+ ARRAY_SIZE(max98388_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map,
ARRAY_SIZE(max98388_map));
}
@@ -762,6 +897,28 @@ static const struct snd_soc_ops acp_max98388_ops = {
SND_SOC_DAILINK_DEF(nau8825,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi")));
+static struct snd_soc_jack nau8825_jack;
+static struct snd_soc_jack_pin nau8825_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new nau8825_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget nau8825_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
static const struct snd_soc_dapm_route nau8825_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
@@ -780,22 +937,38 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != NAU8825)
return -EINVAL;
- ret = snd_soc_card_jack_new(card, "Headset Jack",
+ ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets,
+ ARRAY_SIZE(nau8825_widgets));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_add_card_controls(card, nau8825_controls,
+ ARRAY_SIZE(nau8825_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ &nau8825_jack,
+ nau8825_jack_pins,
+ ARRAY_SIZE(nau8825_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+ ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL);
if (ret) {
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
return ret;
@@ -921,8 +1094,25 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return ret;
}
+static struct snd_soc_jack nau8821_jack;
+static struct snd_soc_jack_pin nau8821_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new nau8821_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static const struct snd_soc_dapm_widget nau8821_widgets[] = {
- SND_SOC_DAPM_HP("Headphone jack", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
@@ -932,12 +1122,12 @@ static const struct snd_soc_dapm_widget nau8821_widgets[] = {
static const struct snd_soc_dapm_route nau8821_audio_route[] = {
/* HP jack connectors - unknown if we have jack detection */
- { "Headphone jack", NULL, "HPOL" },
- { "Headphone jack", NULL, "HPOR" },
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
{ "MICL", NULL, "Headset Mic" },
{ "MICR", NULL, "Headset Mic" },
{ "DMIC", NULL, "Int Mic" },
- { "Headphone jack", NULL, "Platform Clock" },
+ { "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
{ "Int Mic", NULL, "Platform Clock" },
};
@@ -966,21 +1156,31 @@ static int acp_8821_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &vg_headset);
+ ret = snd_soc_add_card_controls(card, nau8821_controls,
+ ARRAY_SIZE(nau8821_controls));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &nau8821_jack,
+ nau8821_jack_pins,
+ ARRAY_SIZE(nau8821_jack_pins));
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret;
}
- snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
- snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
- snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
- snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
- nau8821_enable_jack_detect(component, &vg_headset);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+ nau8821_enable_jack_detect(component, &nau8821_jack);
return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route,
ARRAY_SIZE(nau8821_audio_route));
diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c
index cc8284f417c0..1bf7b2e68a11 100644
--- a/sound/soc/amd/acp/acp-rembrandt.c
+++ b/sound/soc/amd/acp/acp-rembrandt.c
@@ -98,7 +98,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-i2s-bt",
@@ -124,7 +123,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-i2s-hs",
@@ -150,7 +148,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-pdm-dmic",
diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c
index 1899658ab25d..54235cad9cc9 100644
--- a/sound/soc/amd/acp/acp-renoir.c
+++ b/sound/soc/amd/acp/acp-renoir.c
@@ -97,7 +97,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-i2s-bt",
@@ -123,7 +122,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
.rate_max = 48000,
},
.ops = &asoc_acp_cpu_dai_ops,
- .probe = &asoc_acp_i2s_probe,
},
{
.name = "acp-pdm-dmic",
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index a1c893f33f74..5223033a122f 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -94,22 +94,6 @@ static struct acp_card_drvdata sof_nau8821_max98388_data = {
.tdm_mode = false,
};
-static const struct snd_kcontrol_new acp_controls[] = {
- SOC_DAPM_PIN_SWITCH("Headphone Jack"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Spk"),
- SOC_DAPM_PIN_SWITCH("Left Spk"),
- SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_soc_dapm_widget acp_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_SPK("Spk", NULL),
- SND_SOC_DAPM_SPK("Left Spk", NULL),
- SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
static int acp_sof_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = NULL;
@@ -128,11 +112,8 @@ static int acp_sof_probe(struct platform_device *pdev)
card->dev = dev;
card->owner = THIS_MODULE;
card->name = pdev->id_entry->name;
- card->dapm_widgets = acp_widgets;
- card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
- card->controls = acp_controls;
- card->num_controls = ARRAY_SIZE(acp_controls);
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+ /* Widgets and controls added per-codec in acp-mach-common.c */
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h
index 2ebe2099cbb5..d6cfae6ec5f7 100644
--- a/sound/soc/amd/acp/amd.h
+++ b/sound/soc/amd/acp/amd.h
@@ -198,7 +198,6 @@ union acp_i2stdm_mstrclkgen {
extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
extern const struct snd_soc_dai_ops acp_dmic_dai_ops;
-int asoc_acp_i2s_probe(struct snd_soc_dai *dai);
int acp_platform_register(struct device *dev);
int acp_platform_unregister(struct device *dev);
diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c
index 0543dda75b99..28ad5f5b9a76 100644
--- a/sound/soc/amd/acp3x-rt5682-max9836.c
+++ b/sound/soc/amd/acp3x-rt5682-max9836.c
@@ -28,6 +28,17 @@
#define DUAL_CHANNEL 2
static struct snd_soc_jack pco_jack;
+static struct snd_soc_jack_pin pco_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static struct clk *rt5682_dai_wclk;
static struct clk *rt5682_dai_bclk;
static struct gpio_desc *dmic_sel;
@@ -86,11 +97,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk");
rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pco_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pco_jack,
+ pco_jack_pins,
+ ARRAY_SIZE(pco_jack_pins));
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c
index 125a8e93478d..eda464545866 100644
--- a/sound/soc/amd/vangogh/acp5x-mach.c
+++ b/sound/soc/amd/vangogh/acp5x-mach.c
@@ -170,6 +170,9 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME);
int ret, bclk;
+ if (!dai)
+ return -EINVAL;
+
ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(card->dev, "can't set FS clock %d\n", ret);
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 69a88dc65165..6c20c643f321 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -532,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return err;
}
-static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
- .prepare = atmel_i2s_prepare,
- .trigger = atmel_i2s_trigger,
- .hw_params = atmel_i2s_hw_params,
- .set_fmt = atmel_i2s_set_dai_fmt,
-};
-
static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -547,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
+ .probe = atmel_i2s_dai_probe,
+ .prepare = atmel_i2s_prepare,
+ .trigger = atmel_i2s_trigger,
+ .hw_params = atmel_i2s_hw_params,
+ .set_fmt = atmel_i2s_set_dai_fmt,
+};
+
static struct snd_soc_dai_driver atmel_i2s_dai = {
- .probe = atmel_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -730,7 +730,7 @@ static void atmel_i2s_remove(struct platform_device *pdev)
static struct platform_driver atmel_i2s_driver = {
.driver = {
.name = "atmel_i2s",
- .of_match_table = of_match_ptr(atmel_i2s_dt_ids),
+ .of_match_table = atmel_i2s_dt_ids,
},
.probe = atmel_i2s_probe,
.remove_new = atmel_i2s_remove,
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c
index efcbdd1a629f..0db7815d230c 100644
--- a/sound/soc/atmel/atmel-pdmic.c
+++ b/sound/soc/atmel/atmel-pdmic.c
@@ -690,7 +690,7 @@ unregister_codec:
static struct platform_driver atmel_pdmic_driver = {
.driver = {
.name = "atmel-pdmic",
- .of_match_table = of_match_ptr(atmel_pdmic_of_match),
+ .of_match_table = atmel_pdmic_of_match,
.pm = &snd_soc_pm_ops,
},
.probe = atmel_pdmic_probe,
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 7c83d48ca1a0..25ed0b953bfd 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -870,17 +870,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
- .set_sysclk = mchp_i2s_mcc_set_sysclk,
- .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
- .startup = mchp_i2s_mcc_startup,
- .trigger = mchp_i2s_mcc_trigger,
- .hw_params = mchp_i2s_mcc_hw_params,
- .hw_free = mchp_i2s_mcc_hw_free,
- .set_fmt = mchp_i2s_mcc_set_dai_fmt,
- .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
-};
-
static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
{
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -895,6 +884,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
+ .probe = mchp_i2s_mcc_dai_probe,
+ .set_sysclk = mchp_i2s_mcc_set_sysclk,
+ .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
+ .startup = mchp_i2s_mcc_startup,
+ .trigger = mchp_i2s_mcc_trigger,
+ .hw_params = mchp_i2s_mcc_hw_params,
+ .hw_free = mchp_i2s_mcc_hw_free,
+ .set_fmt = mchp_i2s_mcc_set_dai_fmt,
+ .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
+};
+
#define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -906,7 +907,6 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
- .probe = mchp_i2s_mcc_dai_probe,
.playback = {
.stream_name = "I2SMCC-Playback",
.channels_min = 1,
@@ -1098,7 +1098,7 @@ static void mchp_i2s_mcc_remove(struct platform_device *pdev)
static struct platform_driver mchp_i2s_mcc_driver = {
.driver = {
.name = "mchp_i2s_mcc",
- .of_match_table = of_match_ptr(mchp_i2s_mcc_dt_ids),
+ .of_match_table = mchp_i2s_mcc_dt_ids,
},
.probe = mchp_i2s_mcc_probe,
.remove_new = mchp_i2s_mcc_remove,
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
index 911bc334b41e..afe213a71212 100644
--- a/sound/soc/atmel/mchp-pdmc.c
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -698,13 +698,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
- .set_fmt = mchp_pdmc_set_fmt,
- .startup = mchp_pdmc_startup,
- .hw_params = mchp_pdmc_hw_params,
- .trigger = mchp_pdmc_trigger,
-};
-
static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd)
{
struct mchp_pdmc_chmap *info;
@@ -757,8 +750,16 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd,
return ret;
}
+static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
+ .probe = mchp_pdmc_dai_probe,
+ .set_fmt = mchp_pdmc_set_fmt,
+ .startup = mchp_pdmc_startup,
+ .hw_params = mchp_pdmc_hw_params,
+ .trigger = mchp_pdmc_trigger,
+ .pcm_new = &mchp_pdmc_pcm_new,
+};
+
static struct snd_soc_dai_driver mchp_pdmc_dai = {
- .probe = mchp_pdmc_dai_probe,
.capture = {
.stream_name = "Capture",
.channels_min = 1,
@@ -769,7 +770,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = {
.formats = SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &mchp_pdmc_dai_ops,
- .pcm_new = &mchp_pdmc_pcm_new,
};
/* PDMC interrupt handler */
diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c
index ff6aba143aee..33ce5e54482b 100644
--- a/sound/soc/atmel/mchp-spdifrx.c
+++ b/sound/soc/atmel/mchp-spdifrx.c
@@ -503,11 +503,6 @@ unlock:
return ret;
}
-static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = {
- .trigger = mchp_spdifrx_trigger,
- .hw_params = mchp_spdifrx_hw_params,
-};
-
#define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -1009,10 +1004,15 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = {
+ .probe = mchp_spdifrx_dai_probe,
+ .remove = mchp_spdifrx_dai_remove,
+ .trigger = mchp_spdifrx_trigger,
+ .hw_params = mchp_spdifrx_hw_params,
+};
+
static struct snd_soc_dai_driver mchp_spdifrx_dai = {
.name = "mchp-spdifrx",
- .probe = mchp_spdifrx_dai_probe,
- .remove = mchp_spdifrx_dai_remove,
.capture = {
.stream_name = "S/PDIF Capture",
.channels_min = SPDIFRX_CHANNELS,
@@ -1197,7 +1197,7 @@ static struct platform_driver mchp_spdifrx_driver = {
.remove_new = mchp_spdifrx_remove,
.driver = {
.name = "mchp_spdifrx",
- .of_match_table = of_match_ptr(mchp_spdifrx_dt_ids),
+ .of_match_table = mchp_spdifrx_dt_ids,
.pm = pm_ptr(&mchp_spdifrx_pm_ops),
},
};
diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c
index 1d3e17119888..a201a96fa690 100644
--- a/sound/soc/atmel/mchp-spdiftx.c
+++ b/sound/soc/atmel/mchp-spdiftx.c
@@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream,
SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR);
}
-static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = {
- .startup = mchp_spdiftx_dai_startup,
- .shutdown = mchp_spdiftx_dai_shutdown,
- .trigger = mchp_spdiftx_trigger,
- .hw_params = mchp_spdiftx_hw_params,
- .hw_free = mchp_spdiftx_hw_free,
-};
-
#define MCHP_SPDIFTX_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_SPDIFTX_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -703,9 +695,17 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = {
+ .probe = mchp_spdiftx_dai_probe,
+ .startup = mchp_spdiftx_dai_startup,
+ .shutdown = mchp_spdiftx_dai_shutdown,
+ .trigger = mchp_spdiftx_trigger,
+ .hw_params = mchp_spdiftx_hw_params,
+ .hw_free = mchp_spdiftx_hw_free,
+};
+
static struct snd_soc_dai_driver mchp_spdiftx_dai = {
.name = "mchp-spdiftx",
- .probe = mchp_spdiftx_dai_probe,
.playback = {
.stream_name = "S/PDIF Playback",
.channels_min = 1,
@@ -891,7 +891,7 @@ static struct platform_driver mchp_spdiftx_driver = {
.remove_new = mchp_spdiftx_remove,
.driver = {
.name = "mchp_spdiftx",
- .of_match_table = of_match_ptr(mchp_spdiftx_dt_ids),
+ .of_match_table = mchp_spdiftx_dt_ids,
.pm = pm_ptr(&mchp_spdiftx_pm_ops)
},
};
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index efead272d92b..c809b121037f 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -430,7 +430,7 @@ MODULE_DEVICE_TABLE(of, tse850_dt_ids);
static struct platform_driver tse850_driver = {
.driver = {
.name = "axentia-tse850-pcm5142",
- .of_match_table = of_match_ptr(tse850_dt_ids),
+ .of_match_table = tse850_dt_ids,
},
.probe = tse850_probe,
.remove_new = tse850_remove,
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
index a11d6841afc2..b0e1a1253e10 100644
--- a/sound/soc/au1x/ac97c.c
+++ b/sound/soc/au1x/ac97c.c
@@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
- .startup = alchemy_ac97c_startup,
-};
-
static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
{
return ac97c_workdata ? 0 : -ENODEV;
}
+static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
+ .probe = au1xac97c_dai_probe,
+ .startup = alchemy_ac97c_startup,
+};
+
static struct snd_soc_dai_driver au1xac97c_dai_driver = {
.name = "alchemy-ac97c",
- .probe = au1xac97c_dai_probe,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 9fd91aea7d1a..5d50ebc2bdd5 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+ .probe = au1xpsc_ac97_probe,
.startup = au1xpsc_ac97_startup,
.trigger = au1xpsc_ac97_trigger,
.hw_params = au1xpsc_ac97_hw_params,
};
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
- .probe = au1xpsc_ac97_probe,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 85f705afcdbb..9bda6499e66e 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
bcm2835_i2s_stop_clock(dev);
}
+static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai,
+ &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+ &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
+ .probe = bcm2835_i2s_dai_probe,
.startup = bcm2835_i2s_startup,
.shutdown = bcm2835_i2s_shutdown,
.prepare = bcm2835_i2s_prepare,
@@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot,
};
-static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
-{
- struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
-
- snd_soc_dai_init_dma_data(dai,
- &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
- &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
-
- return 0;
-}
-
static struct snd_soc_dai_driver bcm2835_i2s_dai = {
.name = "bcm2835-i2s",
- .probe = bcm2835_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h
index 74152b2d770d..4925e03c3c30 100644
--- a/sound/soc/bcm/cygnus-ssp.h
+++ b/sound/soc/bcm/cygnus-ssp.h
@@ -117,8 +117,6 @@ struct cygnus_audio {
unsigned long vco_rate;
};
-extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd);
extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
int len);
extern int cygnus_soc_platform_register(struct device *dev,
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index afc6b5b570ea..522de4b80293 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -407,6 +407,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component)
#endif
static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+ .probe = ep93xx_i2s_dai_probe,
.startup = ep93xx_i2s_startup,
.shutdown = ep93xx_i2s_shutdown,
.hw_params = ep93xx_i2s_hw_params,
@@ -418,7 +419,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
static struct snd_soc_dai_driver ep93xx_i2s_dai = {
.symmetric_rate = 1,
- .probe = ep93xx_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 3574c68e0dda..d99b674d574b 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -143,7 +143,7 @@ struct pm860x_priv {
struct pm860x_det det;
int irq[4];
- unsigned char name[4][MAX_NAME_LEN+1];
+ unsigned char name[4][MAX_NAME_LEN];
};
/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@@ -1373,7 +1373,7 @@ static int pm860x_codec_probe(struct platform_device *pdev)
return -EINVAL;
}
pm860x->irq[i] = res->start + chip->irq_base;
- strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+ strscpy(pm860x->name[i], res->name, MAX_NAME_LEN);
}
ret = devm_snd_soc_register_component(&pdev->dev,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 88c3dbe47d71..95b5bd883215 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -15,7 +15,6 @@ config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
depends on COMPILE_TEST
imply SND_SOC_88PM860X
- imply SND_SOC_L3
imply SND_SOC_AB8500_CODEC
imply SND_SOC_AC97_CODEC
imply SND_SOC_AD1836
@@ -56,6 +55,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AUDIO_IIO_AUX
imply SND_SOC_AW8738
imply SND_SOC_AW88395
+ imply SND_SOC_AW88261
imply SND_SOC_BT_SCO
imply SND_SOC_BD28623
imply SND_SOC_CHV3_CODEC
@@ -75,6 +75,8 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_CS35L56_SDW
imply SND_SOC_CS42L42
imply SND_SOC_CS42L42_SDW
+ imply SND_SOC_CS42L43
+ imply SND_SOC_CS42L43_SDW
imply SND_SOC_CS42L51_I2C
imply SND_SOC_CS42L52
imply SND_SOC_CS42L56
@@ -184,6 +186,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT1015
imply SND_SOC_RT1015P
imply SND_SOC_RT1016
+ imply SND_SOC_RT1017_SDCA_SDW
imply SND_SOC_RT1019
imply SND_SOC_RT1305
imply SND_SOC_RT1308
@@ -266,7 +269,6 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TWL4030
imply SND_SOC_TWL6040
imply SND_SOC_UDA1334
- imply SND_SOC_UDA134X
imply SND_SOC_UDA1380
imply SND_SOC_WCD9335
imply SND_SOC_WCD934X
@@ -652,6 +654,20 @@ config SND_SOC_AW88395
digital Smart K audio amplifier with an integrated 10V
smart boost convert.
+config SND_SOC_AW88261
+ tristate "Soc Audio for awinic aw88261"
+ depends on I2C
+ select CRC8
+ select REGMAP_I2C
+ select GPIOLIB
+ select SND_SOC_AW88395_LIB
+ help
+ This option enables support for aw88261 Smart PA.
+ The awinic AW88261 is an I2S/TDM input, high efficiency
+ digital Smart K audio amplifier. The output voltage of
+ boost converter can be adjusted smartly according to
+ the input amplitude.
+
config SND_SOC_BD28623
tristate "ROHM BD28623 CODEC"
help
@@ -801,6 +817,20 @@ config SND_SOC_CS42L42_SDW
help
Enable support for Cirrus Logic CS42L42 codec with Soundwire control
+config SND_SOC_CS42L43
+ tristate "Cirrus Logic CS42L43 CODEC"
+ depends on MFD_CS42L43
+ help
+ Select this to support the audio functions of the Cirrus Logic
+ CS42L43 PC CODEC.
+
+config SND_SOC_CS42L43_SDW
+ tristate "Cirrus Logic CS42L43 CODEC (SoundWire)"
+ depends on SND_SOC_CS42L43 && MFD_CS42L43_SDW
+ help
+ Select this to support the audio functions of the Cirrus Logic
+ CS42L43 PC CODEC over SoundWire.
+
config SND_SOC_CS42L51
tristate
@@ -978,9 +1008,6 @@ config SND_SOC_JZ4770_CODEC
This driver can also be built as a module. If so, the module
will be called snd-soc-jz4770-codec.
-config SND_SOC_L3
- tristate
-
config SND_SOC_DA7210
tristate
depends on SND_SOC_I2C_AND_SPI
@@ -1428,6 +1455,11 @@ config SND_SOC_RT1016
tristate
depends on I2C
+config SND_SOC_RT1017_SDCA_SDW
+ tristate "Realtek RT1017 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ select REGMAP_SOUNDWIRE
+
config SND_SOC_RT1019
tristate
depends on I2C
@@ -1932,9 +1964,6 @@ config SND_SOC_UDA1334
and has basic features such as de-emphasis (at 44.1 kHz sampling
rate) and mute.
-config SND_SOC_UDA134X
- tristate
-
config SND_SOC_UDA1380
tristate
depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 32dcc6de58bd..c8502a49b40a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -50,6 +50,7 @@ snd-soc-aw8738-objs := aw8738.o
snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o
snd-soc-aw88395-objs := aw88395/aw88395.o \
aw88395/aw88395_device.o
+snd-soc-aw88261-objs := aw88261.o
snd-soc-bd28623-objs := bd28623.o
snd-soc-bt-sco-objs := bt-sco.o
snd-soc-chv3-codec-objs := chv3-codec.o
@@ -76,6 +77,8 @@ snd-soc-cs35l56-sdw-objs := cs35l56-sdw.o
snd-soc-cs42l42-objs := cs42l42.o
snd-soc-cs42l42-i2c-objs := cs42l42-i2c.o
snd-soc-cs42l42-sdw-objs := cs42l42-sdw.o
+snd-soc-cs42l43-objs := cs42l43.o cs42l43-jack.o
+snd-soc-cs42l43-sdw-objs := cs42l43-sdw.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
snd-soc-cs42l52-objs := cs42l52.o
@@ -128,7 +131,6 @@ snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-jz4725b-codec-objs := jz4725b.o
snd-soc-jz4760-codec-objs := jz4760.o
snd-soc-jz4770-codec-objs := jz4770.o
-snd-soc-l3-objs := l3.o
snd-soc-lm4857-objs := lm4857.o
snd-soc-lm49453-objs := lm49453.o
snd-soc-lochnagar-sc-objs := lochnagar-sc.o
@@ -205,6 +207,7 @@ snd-soc-rt1011-objs := rt1011.o
snd-soc-rt1015-objs := rt1015.o
snd-soc-rt1015p-objs := rt1015p.o
snd-soc-rt1016-objs := rt1016.o
+snd-soc-rt1017-sdca-objs := rt1017-sdca-sdw.o
snd-soc-rt1019-objs := rt1019.o
snd-soc-rt1305-objs := rt1305.o
snd-soc-rt1308-objs := rt1308.o
@@ -299,7 +302,6 @@ snd-soc-ts3a227e-objs := ts3a227e.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda1334-objs := uda1334.o
-snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o
snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
@@ -433,6 +435,7 @@ obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o
obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o
obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o
obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o
+obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o
obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
@@ -459,6 +462,8 @@ obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o
obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o
obj-$(CONFIG_SND_SOC_CS42L42_SDW) += snd-soc-cs42l42-sdw.o
+obj-$(CONFIG_SND_SOC_CS42L43) += snd-soc-cs42l43.o
+obj-$(CONFIG_SND_SOC_CS42L43_SDW) += snd-soc-cs42l43-sdw.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
@@ -511,7 +516,6 @@ obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o
obj-$(CONFIG_SND_SOC_JZ4760_CODEC) += snd-soc-jz4760-codec.o
obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o
-obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o
@@ -583,6 +587,7 @@ obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o
obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o
obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o
obj-$(CONFIG_SND_SOC_RT1016) += snd-soc-rt1016.o
+obj-$(CONFIG_SND_SOC_RT1017_SDCA_SDW) += snd-soc-rt1017-sdca.o
obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o
@@ -679,7 +684,6 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o
-obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o
obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index ad56caec9dac..619a817ee91c 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -880,20 +880,11 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
static int ak4613_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
- struct device_node *np = dev->of_node;
const struct regmap_config *regmap_cfg;
struct regmap *regmap;
struct ak4613_priv *priv;
- regmap_cfg = NULL;
- if (np)
- regmap_cfg = of_device_get_match_data(dev);
- else {
- const struct i2c_device_id *id =
- i2c_match_id(ak4613_i2c_id, i2c);
- regmap_cfg = (const struct regmap_config *)id->driver_data;
- }
-
+ regmap_cfg = i2c_get_match_data(i2c);
if (!regmap_cfg)
return -EINVAL;
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
new file mode 100644
index 000000000000..a697b5006b45
--- /dev/null
+++ b/sound/soc/codecs/aw88261.c
@@ -0,0 +1,1300 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88261.c -- AW88261 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "aw88261.h"
+#include "aw88395/aw88395_data_type.h"
+#include "aw88395/aw88395_device.h"
+
+static const struct regmap_config aw88261_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88261_REG_MAX - 1,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int real_value, volume;
+ unsigned int reg_value;
+
+ volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL);
+ real_value = DB_TO_REG_VAL(volume);
+
+ regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, &reg_value);
+
+ real_value = (real_value | (reg_value & AW88261_VOL_START_MASK));
+
+ dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value);
+
+ regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value);
+}
+
+static void aw88261_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_in_vol = desc->ctl_volume;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_in_time == 0) {
+ aw88261_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw88261_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time,
+ aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw88261_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw88261_dev_fade_out(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_out_time == 0) {
+ aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) {
+ aw88261_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88261_MUTE_VOL) {
+ aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ if (flag)
+ regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG,
+ ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG,
+ ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_DISABLE_VALUE);
+}
+
+static void aw88261_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ if (pwd)
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_PWDN_MASK, AW88261_PWDN_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_PWDN_MASK, AW88261_PWDN_WORKING_VALUE);
+}
+
+static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ if (amppd)
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_AMPPD_MASK, AW88261_AMPPD_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_AMPPD_MASK, AW88261_AMPPD_WORKING_VALUE);
+}
+
+static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw88261_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE);
+ aw88261_dev_fade_in(aw_dev);
+ }
+}
+
+static void aw88261_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ unsigned int int_status;
+
+ /* read int status and clear */
+ regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status);
+ /* make sure int status is clear */
+ regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status);
+
+ dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status);
+}
+
+static int aw88261_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88261_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ return ret;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88261_CCO_MUX_MASK);
+ if (reg_val == AW88261_CCO_MUX_DIVIDED_VALUE) {
+ dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
+ return -EPERM;
+ }
+
+ /* change mode2 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
+ ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88261_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis signal check error");
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
+ ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw88261_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int aw88261_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw88261_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw88261_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int aw88261_dev_check_sysst(struct aw_device *aw_dev)
+{
+ unsigned int check_val;
+ unsigned int reg_val;
+ int ret, i;
+
+ for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK)
+ & AW88261_BIT_SYSST_CHECK;
+ if (check_val != AW88261_BIT_SYSST_CHECK) {
+ dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
+ reg_val, AW88261_BIT_SYSST_CHECK);
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
+{
+ if (uls_hmute)
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_ULS_HMUTE_MASK,
+ AW88261_ULS_HMUTE_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+ ~AW88261_ULS_HMUTE_MASK,
+ AW88261_ULS_HMUTE_DISABLE_VALUE);
+}
+
+static void aw88261_reg_force_set(struct aw88261 *aw88261)
+{
+ if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) {
+ /* set FORCE_PWM */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG,
+ AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE);
+ /* set BOOST_OS_WIDTH */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG,
+ AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE);
+ /* set BURST_LOOPR */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG,
+ AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE);
+ /* set RSQN_DLY */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG,
+ AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE);
+ /* set BURST_SSMODE */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG,
+ AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE);
+ /* set BST_BURST */
+ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG,
+ AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE);
+ } else {
+ dev_dbg(aw88261->aw_pa->dev, "needn't set reg value");
+ }
+}
+
+static int aw88261_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk)
+{
+ u16 reg_icalk, reg_icalkl;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRH4_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_icalk = reg_val & (~AW88261_EF_ISN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_icalkl = reg_val & (~AW88261_EF_ISN_GESLP_L_MASK);
+
+ reg_icalk = (reg_icalk >> AW88261_ICALK_SHIFT) & (reg_icalkl >> AW88261_ICALKL_SHIFT);
+
+ if (reg_icalk & (~AW88261_EF_ISN_GESLP_SIGN_MASK))
+ reg_icalk = reg_icalk | ~AW88261_EF_ISN_GESLP_NEG;
+
+ *icalk = (int16_t)reg_icalk;
+
+ return ret;
+}
+
+static int aw88261_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk)
+{
+ u16 reg_vcalk, reg_vcalkl;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_vcalk = (u16)reg_val & (~AW88261_EF_VSN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88261_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_vcalkl = (u16)reg_val & (~AW88261_EF_VSN_GESLP_L_MASK);
+
+ reg_vcalk = (reg_vcalk >> AW88261_VCALK_SHIFT) & (reg_vcalkl >> AW88261_VCALKL_SHIFT);
+
+ if (reg_vcalk & AW88261_EF_VSN_GESLP_SIGN_MASK)
+ reg_vcalk = reg_vcalk | (~AW88261_EF_VSN_GESLP_NEG);
+ *vcalk = (int16_t)reg_vcalk;
+
+ return ret;
+}
+
+static int aw88261_dev_set_vcalb(struct aw_device *aw_dev)
+{
+ int16_t icalk_val, vcalk_val;
+ int icalk, vcalk, vcalb;
+ u32 reg_val;
+ int ret;
+
+ ret = aw88261_dev_get_icalk(aw_dev, &icalk_val);
+ if (ret)
+ return ret;
+
+ ret = aw88261_dev_get_vcalk(aw_dev, &vcalk_val);
+ if (ret)
+ return ret;
+
+ icalk = AW88261_CABL_BASE_VALUE + AW88261_ICABLK_FACTOR * icalk_val;
+ vcalk = AW88261_CABL_BASE_VALUE + AW88261_VCABLK_FACTOR * vcalk_val;
+ if (!vcalk)
+ return -EINVAL;
+
+ vcalb = AW88261_VCAL_FACTOR * icalk / vcalk;
+ reg_val = (unsigned int)vcalb;
+
+ dev_dbg(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x",
+ icalk, vcalk, vcalb, reg_val);
+ ret = regmap_write(aw_dev->regmap, AW88261_VSNTM1_REG, reg_val);
+
+ return ret;
+}
+
+static int aw88261_dev_reg_update(struct aw88261 *aw88261,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int read_val, efcheck_val, read_vol;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u16 reg_val;
+ u8 reg_addr;
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ if (reg_addr == AW88261_SYSCTRL_REG) {
+ aw88261->amppd_st = reg_val & (~AW88261_AMPPD_MASK);
+ ret = regmap_read(aw_dev->regmap, reg_addr, &read_val);
+ if (ret)
+ break;
+
+ read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) |
+ (~AW88261_HMUTE_MASK);
+ reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK);
+ reg_val |= read_val;
+
+ /* enable uls hmute */
+ reg_val &= AW88261_ULS_HMUTE_MASK;
+ reg_val |= AW88261_ULS_HMUTE_ENABLE_VALUE;
+ }
+
+ if (reg_addr == AW88261_DBGCTRL_REG) {
+ efcheck_val = reg_val & (~AW88261_EF_DBMD_MASK);
+ if (efcheck_val == AW88261_OR_VALUE)
+ aw88261->efuse_check = AW88261_EF_OR_CHECK;
+ else
+ aw88261->efuse_check = AW88261_EF_AND_CHECK;
+ }
+
+ /* i2stxen */
+ if (reg_addr == AW88261_I2SCTRL3_REG) {
+ /* close tx */
+ reg_val &= AW88261_I2STXEN_MASK;
+ reg_val |= AW88261_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88261_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88261_VOL_MASK)) >>
+ AW88261_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume =
+ REG_VAL_TO_DB(read_vol);
+ }
+
+ if (reg_addr == AW88261_VSNTM1_REG)
+ continue;
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ break;
+ }
+
+ ret = aw88261_dev_set_vcalb(aw_dev);
+ if (ret)
+ return ret;
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+
+ /* keep min volume */
+ aw88261_dev_set_volume(aw_dev, vol_desc->mute_volume);
+
+ return ret;
+}
+
+static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return NULL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ return prof_info->prof_name_list[prof_desc->id];
+}
+
+static int aw88261_dev_get_prof_data(struct aw_device *aw_dev, int index,
+ struct aw_prof_desc **prof_desc)
+{
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
+ __func__, index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ *prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ return 0;
+}
+
+static int aw88261_dev_fw_update(struct aw88261 *aw88261)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index);
+ if (!prof_name) {
+ dev_err(aw_dev->dev, "get prof name failed");
+ return -EINVAL;
+ }
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88261_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+ if (ret)
+ return ret;
+
+ /* update reg */
+ sec_desc = prof_index_desc->sec_desc;
+ ret = aw88261_dev_reg_update(aw88261, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return ret;
+}
+
+static int aw88261_dev_start(struct aw88261 *aw88261)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88261_DEV_PW_ON) {
+ dev_info(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ /* power on */
+ aw88261_dev_pwd(aw_dev, false);
+ usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+
+ ret = aw88261_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw88261_dev_amppd(aw_dev, false);
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw88261_dev_check_sysst(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ /* enable tx feedback */
+ aw88261_dev_i2s_tx_enable(aw_dev, true);
+
+ if (aw88261->amppd_st)
+ aw88261_dev_amppd(aw_dev, true);
+
+ aw88261_reg_force_set(aw88261);
+
+ /* close uls mute */
+ aw88261_dev_uls_hmute(aw_dev, false);
+
+ /* close mute */
+ if (!aw88261->mute_st)
+ aw88261_dev_mute(aw_dev, false);
+
+ /* clear inturrupt */
+ aw88261_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88261_DEV_PW_ON;
+
+ return 0;
+
+sysst_check_fail:
+ aw88261_dev_i2s_tx_enable(aw_dev, false);
+ aw88261_dev_clear_int_status(aw_dev);
+ aw88261_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw88261_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88261_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw88261_dev_stop(struct aw_device *aw_dev)
+{
+ if (aw_dev->status == AW88261_DEV_PW_OFF) {
+ dev_info(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88261_DEV_PW_OFF;
+
+ /* clear inturrupt */
+ aw88261_dev_clear_int_status(aw_dev);
+
+ aw88261_dev_uls_hmute(aw_dev, true);
+ /* set mute */
+ aw88261_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw88261_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 100);
+
+ /* enable amppd */
+ aw88261_dev_amppd(aw_dev, true);
+
+ /* set power down */
+ aw88261_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88261_reg_update(struct aw88261 *aw88261, bool force)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int ret;
+
+ if (force) {
+ ret = regmap_write(aw_dev->regmap,
+ AW88261_ID_REG, AW88261_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw88261_dev_fw_update(aw88261);
+ if (ret)
+ return ret;
+ } else {
+ if (aw_dev->prof_cur != aw_dev->prof_index) {
+ ret = aw88261_dev_fw_update(aw88261);
+ if (ret)
+ return ret;
+ } else {
+ ret = 0;
+ }
+ }
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return ret;
+}
+
+static void aw88261_start_pa(struct aw88261 *aw88261)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88261_START_RETRIES; i++) {
+ ret = aw88261_reg_update(aw88261, aw88261->phase_sync);
+ if (ret) {
+ dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i);
+ continue;
+ }
+ ret = aw88261_dev_start(aw88261);
+ if (ret) {
+ dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i);
+ continue;
+ } else {
+ dev_info(aw88261->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+static void aw88261_startup_work(struct work_struct *work)
+{
+ struct aw88261 *aw88261 =
+ container_of(work, struct aw88261, start_work.work);
+
+ mutex_lock(&aw88261->lock);
+ aw88261_start_pa(aw88261);
+ mutex_unlock(&aw88261->lock);
+}
+
+static void aw88261_start(struct aw88261 *aw88261, bool sync_start)
+{
+ if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK)
+ return;
+
+ if (aw88261->aw_pa->status == AW88261_DEV_PW_ON)
+ return;
+
+ if (sync_start == AW88261_SYNC_START)
+ aw88261_start_pa(aw88261);
+ else
+ queue_delayed_work(system_wq,
+ &aw88261->start_work,
+ AW88261_START_WORK_DELAY_MS);
+}
+
+static struct snd_soc_dai_driver aw88261_dai[] = {
+ {
+ .name = "aw88261-aif",
+ .id = 1,
+ .playback = {
+ .stream_name = "Speaker_Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88261_RATES,
+ .formats = AW88261_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Speaker_Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88261_RATES,
+ .formats = AW88261_FORMATS,
+ },
+ },
+};
+
+static int aw88261_get_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88261->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+ return 0;
+}
+
+static int aw88261_set_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int time;
+
+ time = ucontrol->value.integer.value[0];
+
+ if (time < mc->min || time > mc->max)
+ return -EINVAL;
+
+ if (time != aw_dev->fade_in_time) {
+ aw_dev->fade_in_time = time;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88261_get_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88261->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+ return 0;
+}
+
+static int aw88261_set_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int time;
+
+ time = ucontrol->value.integer.value[0];
+ if (time < mc->min || time > mc->max)
+ return -EINVAL;
+
+ if (time != aw_dev->fade_out_time) {
+ aw_dev->fade_out_time = time;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88261_dev_set_profile_index(struct aw_device *aw_dev, int index)
+{
+ /* check the index whether is valid */
+ if ((index >= aw_dev->prof_info.count) || (index < 0))
+ return -EINVAL;
+ /* check the index whether change */
+ if (aw_dev->prof_index == index)
+ return -EPERM;
+
+ aw_dev->prof_index = index;
+
+ return 0;
+}
+
+static int aw88261_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ const char *prof_name;
+ char *name;
+ int count;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw88261->aw_pa->prof_info.count;
+ if (count <= 0) {
+ uinfo->value.enumerated.items = 0;
+ return 0;
+ }
+
+ uinfo->value.enumerated.items = count;
+
+ if (uinfo->value.enumerated.item >= count)
+ uinfo->value.enumerated.item = count - 1;
+
+ name = uinfo->value.enumerated.name;
+ count = uinfo->value.enumerated.item;
+
+ prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count);
+ if (!prof_name) {
+ strscpy(uinfo->value.enumerated.name, "null",
+ strlen("null") + 1);
+ return 0;
+ }
+
+ strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));
+
+ return 0;
+}
+
+static int aw88261_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88261->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ /* pa stop or stopping just set profile */
+ mutex_lock(&aw88261->lock);
+ ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]);
+ if (ret) {
+ dev_dbg(codec->dev, "profile index does not change");
+ mutex_unlock(&aw88261->lock);
+ return 0;
+ }
+
+ if (aw88261->aw_pa->status) {
+ aw88261_dev_stop(aw88261->aw_pa);
+ aw88261_start(aw88261, AW88261_SYNC_START);
+ }
+
+ mutex_unlock(&aw88261->lock);
+
+ return 1;
+}
+
+static int aw88261_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc;
+
+ ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+ return 0;
+}
+
+static int aw88261_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (vol_desc->ctl_volume != value) {
+ vol_desc->ctl_volume = value;
+ aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step;
+
+ return 0;
+}
+
+static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (aw88261->aw_pa->fade_step != value) {
+ aw88261->aw_pa->fade_step = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new aw88261_controls[] = {
+ SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG,
+ 6, AW88261_MUTE_VOL, 0, aw88261_volume_get,
+ aw88261_volume_set),
+ SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0,
+ aw88261_get_fade_step, aw88261_set_fade_step),
+ SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88261_get_fade_in_time, aw88261_set_fade_in_time),
+ SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88261_get_fade_out_time, aw88261_set_fade_out_time),
+ AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info,
+ aw88261_profile_get, aw88261_profile_set),
+};
+
+static int aw88261_playback_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&aw88261->lock);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ aw88261_start(aw88261, AW88261_ASYNC_START);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ aw88261_dev_stop(aw88261->aw_pa);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&aw88261->lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88261_dapm_widgets[] = {
+ /* playback */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0,
+ aw88261_playback_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+ /* capture */
+ SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_INPUT("ADC Input"),
+};
+
+static const struct snd_soc_dapm_route aw88261_audio_map[] = {
+ {"DAC Output", NULL, "AIF_RX"},
+ {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88261_frcset_check(struct aw88261 *aw88261)
+{
+ unsigned int reg_val;
+ u16 temh, teml, tem;
+ int ret;
+
+ ret = regmap_read(aw88261->regmap, AW88261_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+ temh = ((u16)reg_val & (~AW88261_TEMH_MASK));
+
+ ret = regmap_read(aw88261->regmap, AW88261_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+ teml = ((u16)reg_val & (~AW88261_TEML_MASK));
+
+ if (aw88261->efuse_check == AW88261_EF_OR_CHECK)
+ tem = (temh | teml);
+ else
+ tem = (temh & teml);
+
+ if (tem == AW88261_DEFAULT_CFG)
+ aw88261->frcset_en = AW88261_FRCSET_ENABLE;
+ else
+ aw88261->frcset_en = AW88261_FRCSET_DISABLE;
+
+ dev_dbg(aw88261->aw_pa->dev, "tem is 0x%04x, frcset_en is %d",
+ tem, aw88261->frcset_en);
+
+ return ret;
+}
+
+static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88261_ID_REG, AW88261_SOFT_RESET_VALUE);
+ if (ret)
+ return ret;
+
+ aw_dev->fade_in_time = AW88261_500_US;
+ aw_dev->fade_out_time = AW88261_500_US;
+ aw_dev->prof_cur = AW88261_INIT_PROFILE;
+ aw_dev->prof_index = AW88261_INIT_PROFILE;
+
+ ret = aw88261_dev_fw_update(aw88261);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = aw88261_frcset_check(aw88261);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw88261_frcset_check ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88261_dev_clear_int_status(aw_dev);
+
+ aw88261_dev_uls_hmute(aw_dev, true);
+
+ aw88261_dev_mute(aw_dev, true);
+
+ aw88261_dev_i2s_tx_enable(aw_dev, false);
+
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 100);
+
+ aw88261_dev_amppd(aw_dev, true);
+
+ aw88261_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static int aw88261_request_firmware_file(struct aw88261 *aw88261)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev);
+ if (ret)
+ return dev_err_probe(aw88261->aw_pa->dev, ret,
+ "load [%s] failed!", AW88261_ACF_FILE);
+
+ dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88261_ACF_FILE, cont ? cont->size : 0);
+
+ aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
+ if (!aw88261->aw_cfg) {
+ release_firmware(cont);
+ return -ENOMEM;
+ }
+ aw88261->aw_cfg->len = (int)cont->size;
+ memcpy(aw88261->aw_cfg->data, cont->data, cont->size);
+ release_firmware(cont);
+
+ ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg);
+ if (ret) {
+ dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw88261->lock);
+ /* aw device init */
+ ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
+ if (ret)
+ dev_err(aw88261->aw_pa->dev, "dev init failed");
+ mutex_unlock(&aw88261->lock);
+
+ return ret;
+}
+
+static int aw88261_codec_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work);
+
+ ret = aw88261_request_firmware_file(aw88261);
+ if (ret)
+ return dev_err_probe(aw88261->aw_pa->dev, ret,
+ "aw88261_request_firmware_file failed\n");
+
+ /* add widgets */
+ ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets,
+ ARRAY_SIZE(aw88261_dapm_widgets));
+ if (ret)
+ return ret;
+
+ /* add route */
+ ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map,
+ ARRAY_SIZE(aw88261_audio_map));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_add_component_controls(component, aw88261_controls,
+ ARRAY_SIZE(aw88261_controls));
+
+ return ret;
+}
+
+static void aw88261_codec_remove(struct snd_soc_component *aw_codec)
+{
+ struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec);
+
+ cancel_delayed_work_sync(&aw88261->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88261 = {
+ .probe = aw88261_codec_probe,
+ .remove = aw88261_codec_remove,
+};
+
+static void aw88261_hw_reset(struct aw88261 *aw88261)
+{
+ gpiod_set_value_cansleep(aw88261->reset_gpio, 0);
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 10);
+ gpiod_set_value_cansleep(aw88261->reset_gpio, 1);
+ usleep_range(AW88261_1000_US, AW88261_1000_US + 10);
+}
+
+static void aw88261_parse_channel_dt(struct aw88261 *aw88261)
+{
+ struct aw_device *aw_dev = aw88261->aw_pa;
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value = AW88261_DEV_DEFAULT_CH;
+ u32 sync_enable = false;
+
+ of_property_read_u32(np, "sound-channel", &channel_value);
+ of_property_read_u32(np, "sync-flag", &sync_enable);
+
+ aw_dev->channel = channel_value;
+ aw88261->phase_sync = sync_enable;
+}
+
+static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ /* read chip id */
+ ret = regmap_read(regmap, AW88261_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88261_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device");
+ return -ENXIO;
+ }
+
+ dev_info(&i2c->dev, "chip id = %x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+
+ (*aw88261)->aw_pa = aw_dev;
+ aw_dev->i2c = i2c;
+ aw_dev->regmap = regmap;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->chip_id = AW88261_CHIP_ID;
+ aw_dev->acf = NULL;
+ aw_dev->prof_info.prof_desc = NULL;
+ aw_dev->prof_info.count = 0;
+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+ aw_dev->channel = 0;
+ aw_dev->fw_status = AW88261_DEV_FW_FAILED;
+ aw_dev->fade_step = AW88261_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE;
+ aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL;
+ aw88261_parse_channel_dt(*aw88261);
+
+ return ret;
+}
+
+static int aw88261_i2c_probe(struct i2c_client *i2c)
+{
+ struct aw88261 *aw88261;
+ int ret;
+
+ ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
+ if (!ret)
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed");
+
+ aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL);
+ if (!aw88261)
+ return -ENOMEM;
+
+ mutex_init(&aw88261->lock);
+
+ i2c_set_clientdata(i2c, aw88261);
+
+ aw88261->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(aw88261->reset_gpio))
+ dev_info(&i2c->dev, "reset gpio not defined\n");
+ else
+ aw88261_hw_reset(aw88261);
+
+ aw88261->regmap = devm_regmap_init_i2c(i2c, &aw88261_remap_config);
+ if (IS_ERR(aw88261->regmap)) {
+ ret = PTR_ERR(aw88261->regmap);
+ return dev_err_probe(&i2c->dev, ret, "failed to init regmap: %d\n", ret);
+ }
+
+ /* aw pa init */
+ ret = aw88261_init(&aw88261, i2c, aw88261->regmap);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw88261,
+ aw88261_dai, ARRAY_SIZE(aw88261_dai));
+ if (ret)
+ dev_err(&i2c->dev, "failed to register aw88261: %d", ret);
+
+ return ret;
+}
+
+static const struct i2c_device_id aw88261_i2c_id[] = {
+ { AW88261_I2C_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id);
+
+static struct i2c_driver aw88261_i2c_driver = {
+ .driver = {
+ .name = AW88261_I2C_NAME,
+ },
+ .probe = aw88261_i2c_probe,
+ .id_table = aw88261_i2c_id,
+};
+module_i2c_driver(aw88261_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88261 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h
new file mode 100644
index 000000000000..4f3dbf438510
--- /dev/null
+++ b/sound/soc/codecs/aw88261.h
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88261.h -- AW88261 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88261_H__
+#define __AW88261_H__
+
+#define AW88261_ID_REG (0x00)
+#define AW88261_SYSST_REG (0x01)
+#define AW88261_SYSINT_REG (0x02)
+#define AW88261_SYSINTM_REG (0x03)
+#define AW88261_SYSCTRL_REG (0x04)
+#define AW88261_SYSCTRL2_REG (0x05)
+#define AW88261_I2SCTRL1_REG (0x06)
+#define AW88261_I2SCTRL2_REG (0x07)
+#define AW88261_I2SCTRL3_REG (0x08)
+#define AW88261_DACCFG1_REG (0x09)
+#define AW88261_DACCFG2_REG (0x0A)
+#define AW88261_DACCFG3_REG (0x0B)
+#define AW88261_DACCFG4_REG (0x0C)
+#define AW88261_DACCFG5_REG (0x0D)
+#define AW88261_DACCFG6_REG (0x0E)
+#define AW88261_DACCFG7_REG (0x0F)
+#define AW88261_DACCFG8_REG (0x10)
+#define AW88261_PWMCTRL1_REG (0x11)
+#define AW88261_PWMCTRL2_REG (0x12)
+#define AW88261_I2SCFG1_REG (0x13)
+#define AW88261_DBGCTRL_REG (0x14)
+#define AW88261_DACCFG9_REG (0x15)
+#define AW88261_DACCFG10_REG (0x16)
+#define AW88261_DACST_REG (0x20)
+#define AW88261_VBAT_REG (0x21)
+#define AW88261_TEMP_REG (0x22)
+#define AW88261_PVDD_REG (0x23)
+#define AW88261_ISNDAT_REG (0x24)
+#define AW88261_VSNDAT_REG (0x25)
+#define AW88261_I2SINT_REG (0x26)
+#define AW88261_I2SCAPCNT_REG (0x27)
+#define AW88261_ANASTA1_REG (0x28)
+#define AW88261_ANASTA2_REG (0x29)
+#define AW88261_ANASTA3_REG (0x2A)
+#define AW88261_TESTDET_REG (0x2B)
+#define AW88261_DSMCFG1_REG (0x30)
+#define AW88261_DSMCFG2_REG (0x31)
+#define AW88261_DSMCFG3_REG (0x32)
+#define AW88261_DSMCFG4_REG (0x33)
+#define AW88261_DSMCFG5_REG (0x34)
+#define AW88261_DSMCFG6_REG (0x35)
+#define AW88261_DSMCFG7_REG (0x36)
+#define AW88261_DSMCFG8_REG (0x37)
+#define AW88261_TESTIN_REG (0x38)
+#define AW88261_TESTOUT_REG (0x39)
+#define AW88261_SADCCTRL1_REG (0x3A)
+#define AW88261_SADCCTRL2_REG (0x3B)
+#define AW88261_SADCCTRL3_REG (0x3C)
+#define AW88261_SADCCTRL4_REG (0x3D)
+#define AW88261_SADCCTRL5_REG (0x3E)
+#define AW88261_SADCCTRL6_REG (0x3F)
+#define AW88261_SADCCTRL7_REG (0x40)
+#define AW88261_VSNTM1_REG (0x50)
+#define AW88261_VSNTM2_REG (0x51)
+#define AW88261_ISNCTRL1_REG (0x52)
+#define AW88261_ISNCTRL2_REG (0x53)
+#define AW88261_PLLCTRL1_REG (0x54)
+#define AW88261_PLLCTRL2_REG (0x55)
+#define AW88261_PLLCTRL3_REG (0x56)
+#define AW88261_CDACTRL1_REG (0x57)
+#define AW88261_CDACTRL2_REG (0x58)
+#define AW88261_DITHERCFG1_REG (0x59)
+#define AW88261_DITHERCFG2_REG (0x5A)
+#define AW88261_DITHERCFG3_REG (0x5B)
+#define AW88261_CPCTRL_REG (0x5C)
+#define AW88261_BSTCTRL1_REG (0x60)
+#define AW88261_BSTCTRL2_REG (0x61)
+#define AW88261_BSTCTRL3_REG (0x62)
+#define AW88261_BSTCTRL4_REG (0x63)
+#define AW88261_BSTCTRL5_REG (0x64)
+#define AW88261_BSTCTRL6_REG (0x65)
+#define AW88261_BSTCTRL7_REG (0x66)
+#define AW88261_BSTCTRL8_REG (0x67)
+#define AW88261_BSTCTRL9_REG (0x68)
+#define AW88261_TM_REG (0x6F)
+#define AW88261_TESTCTRL1_REG (0x70)
+#define AW88261_TESTCTRL2_REG (0x71)
+#define AW88261_EFCTRL1_REG (0x72)
+#define AW88261_EFCTRL2_REG (0x73)
+#define AW88261_EFWH_REG (0x74)
+#define AW88261_EFWM2_REG (0x75)
+#define AW88261_EFWM1_REG (0x76)
+#define AW88261_EFWL_REG (0x77)
+#define AW88261_EFRH4_REG (0x78)
+#define AW88261_EFRH3_REG (0x79)
+#define AW88261_EFRH2_REG (0x7A)
+#define AW88261_EFRH1_REG (0x7B)
+#define AW88261_EFRL4_REG (0x7C)
+#define AW88261_EFRL3_REG (0x7D)
+#define AW88261_EFRL2_REG (0x7E)
+#define AW88261_EFRL1_REG (0x7F)
+
+#define AW88261_REG_MAX (0x80)
+#define AW88261_EF_DBMD_MASK (0xfff7)
+#define AW88261_OR_VALUE (0x0008)
+
+#define AW88261_TEMH_MASK (0x83ff)
+#define AW88261_TEML_MASK (0x83ff)
+#define AW88261_DEFAULT_CFG (0x0000)
+
+#define AW88261_ICALK_SHIFT (0)
+#define AW88261_ICALKL_SHIFT (0)
+#define AW88261_VCALK_SHIFT (0)
+#define AW88261_VCALKL_SHIFT (0)
+
+#define AW88261_AMPPD_START_BIT (1)
+#define AW88261_AMPPD_BITS_LEN (1)
+#define AW88261_AMPPD_MASK \
+ (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT))
+
+#define AW88261_UVLS_START_BIT (14)
+#define AW88261_UVLS_NORMAL (0)
+#define AW88261_UVLS_NORMAL_VALUE \
+ (AW88261_UVLS_NORMAL << AW88261_UVLS_START_BIT)
+
+#define AW88261_BSTOCS_START_BIT (11)
+#define AW88261_BSTOCS_OVER_CURRENT (1)
+#define AW88261_BSTOCS_OVER_CURRENT_VALUE \
+ (AW88261_BSTOCS_OVER_CURRENT << AW88261_BSTOCS_START_BIT)
+
+#define AW88261_BSTS_START_BIT (9)
+#define AW88261_BSTS_FINISHED (1)
+#define AW88261_BSTS_FINISHED_VALUE \
+ (AW88261_BSTS_FINISHED << AW88261_BSTS_START_BIT)
+
+#define AW88261_SWS_START_BIT (8)
+#define AW88261_SWS_SWITCHING (1)
+#define AW88261_SWS_SWITCHING_VALUE \
+ (AW88261_SWS_SWITCHING << AW88261_SWS_START_BIT)
+
+#define AW88261_NOCLKS_START_BIT (5)
+#define AW88261_NOCLKS_NO_CLOCK (1)
+#define AW88261_NOCLKS_NO_CLOCK_VALUE \
+ (AW88261_NOCLKS_NO_CLOCK << AW88261_NOCLKS_START_BIT)
+
+#define AW88261_CLKS_START_BIT (4)
+#define AW88261_CLKS_STABLE (1)
+#define AW88261_CLKS_STABLE_VALUE \
+ (AW88261_CLKS_STABLE << AW88261_CLKS_START_BIT)
+
+#define AW88261_OCDS_START_BIT (3)
+#define AW88261_OCDS_OC (1)
+#define AW88261_OCDS_OC_VALUE \
+ (AW88261_OCDS_OC << AW88261_OCDS_START_BIT)
+
+#define AW88261_OTHS_START_BIT (1)
+#define AW88261_OTHS_OT (1)
+#define AW88261_OTHS_OT_VALUE \
+ (AW88261_OTHS_OT << AW88261_OTHS_START_BIT)
+
+#define AW88261_PLLS_START_BIT (0)
+#define AW88261_PLLS_LOCKED (1)
+#define AW88261_PLLS_LOCKED_VALUE \
+ (AW88261_PLLS_LOCKED << AW88261_PLLS_START_BIT)
+
+#define AW88261_BIT_PLL_CHECK \
+ (AW88261_CLKS_STABLE_VALUE | \
+ AW88261_PLLS_LOCKED_VALUE)
+
+#define AW88261_BIT_SYSST_CHECK_MASK \
+ (~(AW88261_UVLS_NORMAL_VALUE | \
+ AW88261_BSTOCS_OVER_CURRENT_VALUE | \
+ AW88261_BSTS_FINISHED_VALUE | \
+ AW88261_SWS_SWITCHING_VALUE | \
+ AW88261_NOCLKS_NO_CLOCK_VALUE | \
+ AW88261_CLKS_STABLE_VALUE | \
+ AW88261_OCDS_OC_VALUE | \
+ AW88261_OTHS_OT_VALUE | \
+ AW88261_PLLS_LOCKED_VALUE))
+
+#define AW88261_BIT_SYSST_CHECK \
+ (AW88261_BSTS_FINISHED_VALUE | \
+ AW88261_SWS_SWITCHING_VALUE | \
+ AW88261_CLKS_STABLE_VALUE | \
+ AW88261_PLLS_LOCKED_VALUE)
+
+#define AW88261_ULS_HMUTE_START_BIT (14)
+#define AW88261_ULS_HMUTE_BITS_LEN (1)
+#define AW88261_ULS_HMUTE_MASK \
+ (~(((1<<AW88261_ULS_HMUTE_BITS_LEN)-1) << AW88261_ULS_HMUTE_START_BIT))
+
+#define AW88261_ULS_HMUTE_DISABLE (0)
+#define AW88261_ULS_HMUTE_DISABLE_VALUE \
+ (AW88261_ULS_HMUTE_DISABLE << AW88261_ULS_HMUTE_START_BIT)
+
+#define AW88261_ULS_HMUTE_ENABLE (1)
+#define AW88261_ULS_HMUTE_ENABLE_VALUE \
+ (AW88261_ULS_HMUTE_ENABLE << AW88261_ULS_HMUTE_START_BIT)
+
+#define AW88261_HMUTE_START_BIT (8)
+#define AW88261_HMUTE_BITS_LEN (1)
+#define AW88261_HMUTE_MASK \
+ (~(((1<<AW88261_HMUTE_BITS_LEN)-1) << AW88261_HMUTE_START_BIT))
+
+#define AW88261_HMUTE_DISABLE (0)
+#define AW88261_HMUTE_DISABLE_VALUE \
+ (AW88261_HMUTE_DISABLE << AW88261_HMUTE_START_BIT)
+
+#define AW88261_HMUTE_ENABLE (1)
+#define AW88261_HMUTE_ENABLE_VALUE \
+ (AW88261_HMUTE_ENABLE << AW88261_HMUTE_START_BIT)
+
+#define AW88261_AMPPD_START_BIT (1)
+#define AW88261_AMPPD_BITS_LEN (1)
+#define AW88261_AMPPD_MASK \
+ (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT))
+
+#define AW88261_AMPPD_WORKING (0)
+#define AW88261_AMPPD_WORKING_VALUE \
+ (AW88261_AMPPD_WORKING << AW88261_AMPPD_START_BIT)
+
+#define AW88261_AMPPD_POWER_DOWN (1)
+#define AW88261_AMPPD_POWER_DOWN_VALUE \
+ (AW88261_AMPPD_POWER_DOWN << AW88261_AMPPD_START_BIT)
+
+#define AW88261_PWDN_START_BIT (0)
+#define AW88261_PWDN_BITS_LEN (1)
+#define AW88261_PWDN_MASK \
+ (~(((1<<AW88261_PWDN_BITS_LEN)-1) << AW88261_PWDN_START_BIT))
+
+#define AW88261_PWDN_WORKING (0)
+#define AW88261_PWDN_WORKING_VALUE \
+ (AW88261_PWDN_WORKING << AW88261_PWDN_START_BIT)
+
+#define AW88261_PWDN_POWER_DOWN (1)
+#define AW88261_PWDN_POWER_DOWN_VALUE \
+ (AW88261_PWDN_POWER_DOWN << AW88261_PWDN_START_BIT)
+
+#define AW88261_MUTE_VOL (90 * 8)
+#define AW88261_VOLUME_STEP_DB (6 * 8)
+
+#define AW88261_VOL_6DB_START (6)
+
+#define AW88261_VOL_START_BIT (0)
+#define AW88261_VOL_BITS_LEN (10)
+#define AW88261_VOL_MASK \
+ (~(((1<<AW88261_VOL_BITS_LEN)-1) << AW88261_VOL_START_BIT))
+
+#define AW88261_VOL_DEFAULT_VALUE (0)
+
+#define AW88261_I2STXEN_START_BIT (6)
+#define AW88261_I2STXEN_BITS_LEN (1)
+#define AW88261_I2STXEN_MASK \
+ (~(((1<<AW88261_I2STXEN_BITS_LEN)-1) << AW88261_I2STXEN_START_BIT))
+
+#define AW88261_I2STXEN_DISABLE (0)
+#define AW88261_I2STXEN_DISABLE_VALUE \
+ (AW88261_I2STXEN_DISABLE << AW88261_I2STXEN_START_BIT)
+
+#define AW88261_I2STXEN_ENABLE (1)
+#define AW88261_I2STXEN_ENABLE_VALUE \
+ (AW88261_I2STXEN_ENABLE << AW88261_I2STXEN_START_BIT)
+
+#define AW88261_CCO_MUX_START_BIT (14)
+#define AW88261_CCO_MUX_BITS_LEN (1)
+#define AW88261_CCO_MUX_MASK \
+ (~(((1<<AW88261_CCO_MUX_BITS_LEN)-1) << AW88261_CCO_MUX_START_BIT))
+
+#define AW88261_CCO_MUX_DIVIDED (0)
+#define AW88261_CCO_MUX_DIVIDED_VALUE \
+ (AW88261_CCO_MUX_DIVIDED << AW88261_CCO_MUX_START_BIT)
+
+#define AW88261_CCO_MUX_BYPASS (1)
+#define AW88261_CCO_MUX_BYPASS_VALUE \
+ (AW88261_CCO_MUX_BYPASS << AW88261_CCO_MUX_START_BIT)
+
+#define AW88261_EF_VSN_GESLP_H_START_BIT (0)
+#define AW88261_EF_VSN_GESLP_H_BITS_LEN (10)
+#define AW88261_EF_VSN_GESLP_H_MASK \
+ (~(((1<<AW88261_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_H_START_BIT))
+
+#define AW88261_EF_VSN_GESLP_L_START_BIT (0)
+#define AW88261_EF_VSN_GESLP_L_BITS_LEN (10)
+#define AW88261_EF_VSN_GESLP_L_MASK \
+ (~(((1<<AW88261_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_L_START_BIT))
+
+#define AW88261_FORCE_PWM_START_BIT (12)
+#define AW88261_FORCE_PWM_BITS_LEN (1)
+#define AW88261_FORCE_PWM_MASK \
+ (~(((1<<AW88261_FORCE_PWM_BITS_LEN)-1) << AW88261_FORCE_PWM_START_BIT))
+
+#define AW88261_FORCE_PWM_FORCEMINUS_PWM (1)
+#define AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE \
+ (AW88261_FORCE_PWM_FORCEMINUS_PWM << AW88261_FORCE_PWM_START_BIT)
+
+#define AW88261_BST_OS_WIDTH_START_BIT (0)
+#define AW88261_BST_OS_WIDTH_BITS_LEN (3)
+#define AW88261_BST_OS_WIDTH_MASK \
+ (~(((1<<AW88261_BST_OS_WIDTH_BITS_LEN)-1) << AW88261_BST_OS_WIDTH_START_BIT))
+
+#define AW88261_BST_OS_WIDTH_50NS (4)
+#define AW88261_BST_OS_WIDTH_50NS_VALUE \
+ (AW88261_BST_OS_WIDTH_50NS << AW88261_BST_OS_WIDTH_START_BIT)
+
+/* BST_LOOPR bit 1:0 (BSTCTRL6 0x65) */
+#define AW88261_BST_LOOPR_START_BIT (0)
+#define AW88261_BST_LOOPR_BITS_LEN (2)
+#define AW88261_BST_LOOPR_MASK \
+ (~(((1<<AW88261_BST_LOOPR_BITS_LEN)-1) << AW88261_BST_LOOPR_START_BIT))
+
+#define AW88261_BST_LOOPR_340K (2)
+#define AW88261_BST_LOOPR_340K_VALUE \
+ (AW88261_BST_LOOPR_340K << AW88261_BST_LOOPR_START_BIT)
+
+/* RSQN_DLY bit 15:14 (BSTCTRL7 0x66) */
+#define AW88261_RSQN_DLY_START_BIT (14)
+#define AW88261_RSQN_DLY_BITS_LEN (2)
+#define AW88261_RSQN_DLY_MASK \
+ (~(((1<<AW88261_RSQN_DLY_BITS_LEN)-1) << AW88261_RSQN_DLY_START_BIT))
+
+#define AW88261_RSQN_DLY_35NS (2)
+#define AW88261_RSQN_DLY_35NS_VALUE \
+ (AW88261_RSQN_DLY_35NS << AW88261_RSQN_DLY_START_BIT)
+
+/* BURST_SSMODE bit 3 (BSTCTRL8 0x67) */
+#define AW88261_BURST_SSMODE_START_BIT (3)
+#define AW88261_BURST_SSMODE_BITS_LEN (1)
+#define AW88261_BURST_SSMODE_MASK \
+ (~(((1<<AW88261_BURST_SSMODE_BITS_LEN)-1) << AW88261_BURST_SSMODE_START_BIT))
+
+#define AW88261_BURST_SSMODE_FAST (0)
+#define AW88261_BURST_SSMODE_FAST_VALUE \
+ (AW88261_BURST_SSMODE_FAST << AW88261_BURST_SSMODE_START_BIT)
+
+/* BST_BURST bit 9:7 (BSTCTRL9 0x68) */
+#define AW88261_BST_BURST_START_BIT (7)
+#define AW88261_BST_BURST_BITS_LEN (3)
+#define AW88261_BST_BURST_MASK \
+ (~(((1<<AW88261_BST_BURST_BITS_LEN)-1) << AW88261_BST_BURST_START_BIT))
+
+#define AW88261_BST_BURST_30MA (2)
+#define AW88261_BST_BURST_30MA_VALUE \
+ (AW88261_BST_BURST_30MA << AW88261_BST_BURST_START_BIT)
+
+#define AW88261_EF_VSN_GESLP_SIGN_MASK (~0x0200)
+#define AW88261_EF_VSN_GESLP_NEG (~0xfc00)
+
+#define AW88261_EF_ISN_GESLP_SIGN_MASK (~0x0200)
+#define AW88261_EF_ISN_GESLP_NEG (~0xfc00)
+
+#define AW88261_EF_ISN_GESLP_H_START_BIT (0)
+#define AW88261_EF_ISN_GESLP_H_BITS_LEN (10)
+#define AW88261_EF_ISN_GESLP_H_MASK \
+ (~(((1<<AW88261_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_H_START_BIT))
+
+#define AW88261_EF_ISN_GESLP_L_START_BIT (0)
+#define AW88261_EF_ISN_GESLP_L_BITS_LEN (10)
+#define AW88261_EF_ISN_GESLP_L_MASK \
+ (~(((1<<AW88261_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_L_START_BIT))
+
+#define AW88261_CABL_BASE_VALUE (1000)
+#define AW88261_ICABLK_FACTOR (1)
+#define AW88261_VCABLK_FACTOR (1)
+
+#define AW88261_VCAL_FACTOR (1<<13)
+
+#define AW88261_START_RETRIES (5)
+#define AW88261_START_WORK_DELAY_MS (0)
+
+#define AW88261_I2C_NAME "aw88261_smartpa"
+
+#define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_96000)
+#define AW88261_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define FADE_TIME_MAX 100000
+#define FADE_TIME_MIN 0
+
+#define AW88261_DEV_DEFAULT_CH (0)
+#define AW88261_ACF_FILE "aw88261_acf.bin"
+#define AW88261_DEV_SYSST_CHECK_MAX (10)
+#define AW88261_SOFT_RESET_VALUE (0x55aa)
+#define AW88261_REG_TO_DB (0x3f)
+#define AW88261_VOL_START_MASK (0xfc00)
+#define AW88261_INIT_PROFILE (0)
+
+#define REG_VAL_TO_DB(value) ((((value) >> AW88261_VOL_6DB_START) * \
+ AW88261_VOLUME_STEP_DB) + \
+ ((value) & AW88261_REG_TO_DB))
+#define DB_TO_REG_VAL(value) ((((value) / AW88261_VOLUME_STEP_DB) << \
+ AW88261_VOL_6DB_START) + \
+ ((value) % AW88261_VOLUME_STEP_DB))
+
+#define AW88261_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = profile_info, \
+ .get = profile_get, \
+ .put = profile_set, \
+}
+
+enum {
+ AW88261_SYNC_START = 0,
+ AW88261_ASYNC_START,
+};
+
+enum aw88261_id {
+ AW88261_CHIP_ID = 0x2113,
+};
+
+enum {
+ AW88261_500_US = 500,
+ AW88261_1000_US = 1000,
+ AW88261_2000_US = 2000,
+};
+
+enum {
+ AW88261_DEV_PW_OFF = 0,
+ AW88261_DEV_PW_ON,
+};
+
+enum {
+ AW88261_DEV_FW_FAILED = 0,
+ AW88261_DEV_FW_OK,
+};
+
+enum {
+ AW88261_EF_AND_CHECK = 0,
+ AW88261_EF_OR_CHECK,
+};
+
+enum {
+ AW88261_FRCSET_DISABLE = 0,
+ AW88261_FRCSET_ENABLE,
+};
+
+struct aw88261 {
+ struct aw_device *aw_pa;
+ struct mutex lock;
+ struct gpio_desc *reset_gpio;
+ struct delayed_work start_work;
+ struct regmap *regmap;
+ struct aw_container *aw_cfg;
+
+ int efuse_check;
+ int frcset_en;
+ unsigned int mute_st;
+ unsigned int amppd_st;
+
+ unsigned char phase_sync;
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c
index 05bcf49da857..8ee1baa03269 100644
--- a/sound/soc/codecs/aw88395/aw88395_lib.c
+++ b/sound/soc/codecs/aw88395/aw88395_lib.c
@@ -11,6 +11,7 @@
#include <linux/i2c.h>
#include "aw88395_lib.h"
#include "aw88395_device.h"
+#include "aw88395_reg.h"
#define AW88395_CRC8_POLYNOMIAL 0x8C
DECLARE_CRC8_TABLE(aw_crc8_table);
@@ -429,6 +430,53 @@ parse_bin_failed:
return ret;
}
+static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
+ uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc)
+{
+ struct aw_bin *aw_bin;
+ int ret;
+
+ aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL);
+ if (!aw_bin)
+ return -ENOMEM;
+
+ aw_bin->info.len = data_len;
+ memcpy(aw_bin->info.data, data, data_len);
+
+ ret = aw_parsing_bin_file(aw_dev, aw_bin);
+ if (ret < 0) {
+ dev_err(aw_dev->dev, "parse bin failed");
+ goto parse_bin_failed;
+ }
+
+ if ((aw_bin->all_bin_parse_num != 1) ||
+ (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
+ dev_err(aw_dev->dev, "bin num or type error");
+ goto parse_bin_failed;
+ }
+
+ if (aw_bin->header_info[0].valid_data_len % 4) {
+ dev_err(aw_dev->dev, "bin data len get error!");
+ goto parse_bin_failed;
+ }
+
+ prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =
+ data + aw_bin->header_info[0].valid_data_addr;
+ prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len =
+ aw_bin->header_info[0].valid_data_len;
+ prof_desc->prof_st = AW88395_PROFILE_OK;
+
+ devm_kfree(aw_dev->dev, aw_bin);
+ aw_bin = NULL;
+
+ return 0;
+
+parse_bin_failed:
+ devm_kfree(aw_dev->dev, aw_bin);
+ aw_bin = NULL;
+ return ret;
+}
+
static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr,
struct aw_cfg_dde *cfg_dde, struct aw_prof_desc *scene_prof_desc)
{
@@ -447,6 +495,9 @@ static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg
return aw_dev_prof_parse_multi_bin(
aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,
cfg_dde->data_size, scene_prof_desc);
+ case ACF_SEC_TYPE_HDR_REG:
+ return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,
+ cfg_dde->data_size, scene_prof_desc);
default:
dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type);
break;
@@ -527,7 +578,49 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev,
return 0;
}
-static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
+static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
+ struct aw_all_prof_info all_prof_info)
+{
+ struct aw_prof_desc *prof_desc = all_prof_info.prof_desc;
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ int num = 0;
+ int i;
+
+ for (i = 0; i < AW88395_PROFILE_MAX; i++) {
+ if (prof_desc[i].prof_st == AW88395_PROFILE_OK)
+ prof_info->count++;
+ }
+
+ dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count);
+
+ if (!prof_info->count) {
+ dev_err(aw_dev->dev, "no profile data");
+ return -EPERM;
+ }
+
+ prof_info->prof_desc = devm_kcalloc(aw_dev->dev,
+ prof_info->count, sizeof(struct aw_prof_desc),
+ GFP_KERNEL);
+ if (!prof_info->prof_desc)
+ return -ENOMEM;
+
+ for (i = 0; i < AW88395_PROFILE_MAX; i++) {
+ if (prof_desc[i].prof_st == AW88395_PROFILE_OK) {
+ if (num >= prof_info->count) {
+ dev_err(aw_dev->dev, "overflow count[%d]",
+ prof_info->count);
+ return -EINVAL;
+ }
+ prof_info->prof_desc[num] = prof_desc[i];
+ prof_info->prof_desc[num].id = i;
+ num++;
+ }
+ }
+
+ return 0;
+}
+
+static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
struct aw_all_prof_info all_prof_info)
{
struct aw_prof_desc *prof_desc = all_prof_info.prof_desc;
@@ -606,9 +699,22 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
goto exit;
}
- ret = aw_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
- if (ret < 0)
- goto exit;
+ switch (aw_dev->chip_id) {
+ case AW88395_CHIP_ID:
+ ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
+ if (ret < 0)
+ goto exit;
+ break;
+ case AW88261_CHIP_ID:
+ ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
+ if (ret < 0)
+ goto exit;
+ break;
+ default:
+ dev_err(aw_dev->dev, "valid prof unsupported");
+ ret = -EINVAL;
+ break;
+ }
aw_dev->prof_info.prof_name_list = profile_name;
@@ -679,16 +785,37 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain
struct aw_cfg_dde_v1 *cfg_dde =
(struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);
unsigned int i;
+ int ret;
- for (i = 0; i < cfg_hdr->ddt_num; ++i) {
- if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
- (aw_dev->chip_id == cfg_dde[i].chip_id) &&
- (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
- (aw_dev->i2c->addr == cfg_dde[i].dev_addr))
- (*scene_num)++;
+ switch (aw_dev->chip_id) {
+ case AW88395_CHIP_ID:
+ for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+ if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
+ (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+ (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
+ (aw_dev->i2c->addr == cfg_dde[i].dev_addr))
+ (*scene_num)++;
+ }
+ ret = 0;
+ break;
+ case AW88261_CHIP_ID:
+ for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+ if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||
+ (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&
+ (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+ (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
+ (aw_dev->i2c->addr == cfg_dde[i].dev_addr))
+ (*scene_num)++;
+ }
+ ret = 0;
+ break;
+ default:
+ dev_err(aw_dev->dev, "unsupported device");
+ ret = -EINVAL;
+ break;
}
- return 0;
+ return ret;
}
static int aw_get_default_scene_count_v1(struct aw_device *aw_dev,
@@ -699,15 +826,35 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev,
struct aw_cfg_dde_v1 *cfg_dde =
(struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);
unsigned int i;
+ int ret;
- for (i = 0; i < cfg_hdr->ddt_num; ++i) {
- if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
- (aw_dev->chip_id == cfg_dde[i].chip_id) &&
- (aw_dev->channel == cfg_dde[i].dev_index))
- (*scene_num)++;
+ switch (aw_dev->chip_id) {
+ case AW88395_CHIP_ID:
+ for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+ if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
+ (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+ (aw_dev->channel == cfg_dde[i].dev_index))
+ (*scene_num)++;
+ }
+ ret = 0;
+ break;
+ case AW88261_CHIP_ID:
+ for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+ if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||
+ (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&
+ (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+ (aw_dev->channel == cfg_dde[i].dev_index))
+ (*scene_num)++;
+ }
+ ret = 0;
+ break;
+ default:
+ dev_err(aw_dev->dev, "unsupported device");
+ ret = -EINVAL;
+ break;
}
- return 0;
+ return ret;
}
static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev,
@@ -756,6 +903,18 @@ static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev,
prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;
(*cur_scene_id)++;
break;
+ case ACF_SEC_TYPE_HDR_REG:
+ ret = aw_dev_parse_reg_bin_with_hdr(aw_dev,
+ (uint8_t *)prof_hdr + cfg_dde->data_offset,
+ cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]);
+ if (ret < 0) {
+ dev_err(aw_dev->dev, "parse reg bin with hdr failed");
+ return ret;
+ }
+ prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str;
+ prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;
+ (*cur_scene_id)++;
+ break;
default:
dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type);
return -EINVAL;
diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h
index e64f24e97150..e7a7c02efaf3 100644
--- a/sound/soc/codecs/aw88395/aw88395_reg.h
+++ b/sound/soc/codecs/aw88395/aw88395_reg.h
@@ -96,6 +96,7 @@
enum aw88395_id {
AW88395_CHIP_ID = 0x2049,
+ AW88261_CHIP_ID = 0x2113,
};
#define AW88395_REG_MAX (0x7D)
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index ea3a4557619a..600b79c62ec4 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -357,22 +357,11 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
return 0;
}
-static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
- unsigned int reg, unsigned long mask)
+static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask)
{
- unsigned int reg_val, channel_shift;
+ unsigned int channel_shift;
int bit_num;
- /* Init all slots to 63 */
- switch (reg) {
- case CS35L56_ASP1_FRAME_CONTROL1:
- reg_val = 0x3f3f3f3f;
- break;
- case CS35L56_ASP1_FRAME_CONTROL5:
- reg_val = 0x3f3f3f;
- break;
- }
-
/* Enable consecutive TX1..TXn for each of the slots set in mask */
channel_shift = 0;
for_each_set_bit(bit_num, &mask, 32) {
@@ -381,7 +370,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
channel_shift += 8;
}
- regmap_write(cs35l56->base.regmap, reg, reg_val);
+ return reg_val;
}
static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -417,8 +406,11 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
if (rx_mask == 0)
rx_mask = 0xf; // ASPTX1..TX4 in slots 0..3
- cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask);
- cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask);
+ /* Default unused slots to 63 */
+ regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1,
+ cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask));
+ regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5,
+ cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask));
dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask);
@@ -663,7 +655,7 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
int ret;
/* Use wm_adsp to load and apply the firmware patch and coefficient files */
- ret = wm_adsp_power_up(&cs35l56->dsp);
+ ret = wm_adsp_power_up(&cs35l56->dsp, true);
if (ret)
dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
else
@@ -672,8 +664,17 @@ static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
static void cs35l56_patch(struct cs35l56_private *cs35l56)
{
+ unsigned int firmware_missing;
int ret;
+ ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing);
+ if (ret) {
+ dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+ return;
+ }
+
+ firmware_missing &= CS35L56_FIRMWARE_MISSING;
+
/*
* Disable SoundWire interrupts to prevent race with IRQ work.
* Setting sdw_irq_no_unmask prevents the handler re-enabling
@@ -692,8 +693,12 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
if (ret)
goto err;
- /* Use wm_adsp to load and apply the firmware patch and coefficient files */
- ret = wm_adsp_power_up(&cs35l56->dsp);
+ /*
+ * Use wm_adsp to load and apply the firmware patch and coefficient files,
+ * but only if firmware is missing. If firmware is already patched just
+ * power-up wm_adsp without downloading firmware.
+ */
+ ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing);
if (ret) {
dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
goto err;
@@ -959,6 +964,12 @@ int cs35l56_system_resume(struct device *dev)
dev_dbg(dev, "system_resume\n");
+ /*
+ * We might have done a hard reset or the CS35L56 was power-cycled
+ * so wait for control port to be ready.
+ */
+ cs35l56_wait_control_port_ready();
+
/* Undo pm_runtime_force_suspend() before re-enabling the irq */
ret = pm_runtime_force_resume(dev);
if (cs35l56->base.irq)
@@ -977,6 +988,7 @@ int cs35l56_system_resume(struct device *dev)
return ret;
cs35l56->base.fw_patched = false;
+ wm_adsp_power_down(&cs35l56->dsp);
queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
/*
@@ -1072,6 +1084,8 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n");
if (cs35l56->base.reset_gpio) {
+ /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */
+ gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
cs35l56_wait_min_reset_pulse();
gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
}
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
new file mode 100644
index 000000000000..92e37bc1df9d
--- /dev/null
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -0,0 +1,946 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 CODEC driver jack handling
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/build_bug.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <sound/control.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-component.h>
+#include <sound/soc.h>
+
+#include "cs42l43.h"
+
+static const unsigned int cs42l43_accdet_us[] = {
+ 20, 100, 1000, 10000, 50000, 75000, 100000, 200000
+};
+
+static const unsigned int cs42l43_accdet_db_ms[] = {
+ 0, 125, 250, 500, 750, 1000, 1250, 1500
+};
+
+static const unsigned int cs42l43_accdet_ramp_ms[] = { 10, 40, 90, 170 };
+
+static const unsigned int cs42l43_accdet_bias_sense[] = {
+ 14, 23, 41, 50, 60, 68, 86, 95, 0,
+};
+
+static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const prop,
+ unsigned int defval, unsigned int *val,
+ const unsigned int *values, const int nvalues)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ int i, ret;
+
+ ret = device_property_read_u32(cs42l43->dev, prop, &defval);
+ if (ret != -EINVAL && ret < 0) {
+ dev_err(priv->dev, "Property %s malformed: %d\n", prop, ret);
+ return ret;
+ }
+
+ if (val)
+ *val = defval;
+
+ for (i = 0; i < nvalues; i++)
+ if (defval == values[i])
+ return i;
+
+ dev_err(priv->dev, "Invalid value for property %s: %d\n", prop, defval);
+ return -EINVAL;
+}
+
+int cs42l43_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *d)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ /* This tip sense invert is always set, HW wants an inverted signal */
+ unsigned int tip_deb = CS42L43_TIPSENSE_INV_MASK;
+ unsigned int hs2 = 0x2 << CS42L43_HSDET_MODE_SHIFT;
+ unsigned int autocontrol = 0, pdncntl = 0;
+ int ret;
+
+ dev_dbg(priv->dev, "Configure accessory detect\n");
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret);
+ return ret;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ priv->jack_hp = jack;
+
+ if (!jack)
+ goto done;
+
+ ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms");
+ if (ret != -EINVAL) {
+ if (ret < 0) {
+ dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n",
+ ret);
+ goto error;
+ }
+
+ if (ret > CS42L43_N_BUTTONS) {
+ ret = -EINVAL;
+ dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n");
+ goto error;
+ }
+
+ device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms",
+ priv->buttons, ret);
+ } else {
+ priv->buttons[0] = 70;
+ priv->buttons[1] = 185;
+ priv->buttons[2] = 355;
+ priv->buttons[3] = 735;
+ }
+
+ ret = cs42l43_find_index(priv, "cirrus,detect-us", 10000, &priv->detect_us,
+ cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us));
+ if (ret < 0)
+ goto error;
+
+ hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT;
+
+ priv->bias_low = device_property_read_bool(cs42l43->dev, "cirrus,bias-low");
+
+ ret = cs42l43_find_index(priv, "cirrus,bias-ramp-ms", 170,
+ &priv->bias_ramp_ms, cs42l43_accdet_ramp_ms,
+ ARRAY_SIZE(cs42l43_accdet_ramp_ms));
+ if (ret < 0)
+ goto error;
+
+ hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,bias-sense-microamp", 0,
+ &priv->bias_sense_ua, cs42l43_accdet_bias_sense,
+ ARRAY_SIZE(cs42l43_accdet_bias_sense));
+ if (ret < 0)
+ goto error;
+
+ if (priv->bias_sense_ua)
+ autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT;
+
+ if (!device_property_read_bool(cs42l43->dev, "cirrus,button-automute"))
+ autocontrol |= CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK;
+
+ ret = device_property_read_u32(cs42l43->dev, "cirrus,tip-debounce-ms",
+ &priv->tip_debounce_ms);
+ if (ret < 0 && ret != -EINVAL) {
+ dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret);
+ goto error;
+ }
+
+ /* This tip sense invert is set normally, as TIPSENSE_INV already inverted */
+ if (device_property_read_bool(cs42l43->dev, "cirrus,tip-invert"))
+ autocontrol |= 0x1 << CS42L43_JACKDET_INV_SHIFT;
+
+ if (device_property_read_bool(cs42l43->dev, "cirrus,tip-disable-pullup"))
+ autocontrol |= 0x1 << CS42L43_JACKDET_MODE_SHIFT;
+ else
+ autocontrol |= 0x3 << CS42L43_JACKDET_MODE_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,tip-fall-db-ms", 500,
+ NULL, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,tip-rise-db-ms", 500,
+ NULL, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT;
+
+ if (device_property_read_bool(cs42l43->dev, "cirrus,use-ring-sense")) {
+ unsigned int ring_deb = 0;
+
+ priv->use_ring_sense = true;
+
+ /* HW wants an inverted signal, so invert the invert */
+ if (!device_property_read_bool(cs42l43->dev, "cirrus,ring-invert"))
+ ring_deb |= CS42L43_RINGSENSE_INV_MASK;
+
+ if (!device_property_read_bool(cs42l43->dev,
+ "cirrus,ring-disable-pullup"))
+ ring_deb |= CS42L43_RINGSENSE_PULLUP_PDNB_MASK;
+
+ ret = cs42l43_find_index(priv, "cirrus,ring-fall-db-ms", 500,
+ NULL, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT;
+
+ ret = cs42l43_find_index(priv, "cirrus,ring-rise-db-ms", 500,
+ NULL, cs42l43_accdet_db_ms,
+ ARRAY_SIZE(cs42l43_accdet_db_ms));
+ if (ret < 0)
+ goto error;
+
+ ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT;
+ pdncntl |= CS42L43_RING_SENSE_EN_MASK;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_RINGSENSE_DEB_CTRL,
+ CS42L43_RINGSENSE_INV_MASK |
+ CS42L43_RINGSENSE_PULLUP_PDNB_MASK |
+ CS42L43_RINGSENSE_FALLING_DB_TIME_MASK |
+ CS42L43_RINGSENSE_RISING_DB_TIME_MASK,
+ ring_deb);
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_TIPSENSE_DEB_CTRL,
+ CS42L43_TIPSENSE_INV_MASK |
+ CS42L43_TIPSENSE_FALLING_DB_TIME_MASK |
+ CS42L43_TIPSENSE_RISING_DB_TIME_MASK, tip_deb);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK |
+ CS42L43_AUTO_HSDET_TIME_MASK, hs2);
+
+done:
+ ret = 0;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |
+ CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,
+ CS42L43_RING_SENSE_EN_MASK, pdncntl);
+
+ dev_dbg(priv->dev, "Successfully configured accessory detect\n");
+
+error:
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return ret;
+}
+
+static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT;
+
+ dev_dbg(priv->dev, "Start headset bias\n");
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);
+
+ if (!force_high && priv->bias_low)
+ val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, val);
+
+ msleep(priv->bias_ramp_ms);
+}
+
+static void cs42l43_stop_hs_bias(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Stop headset bias\n");
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, 0);
+}
+
+irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+
+ queue_delayed_work(system_wq, &priv->bias_sense_timeout,
+ msecs_to_jiffies(250));
+
+ return IRQ_HANDLED;
+}
+
+#define CS42L43_JACK_PRESENT 0x3
+#define CS42L43_JACK_ABSENT 0x0
+
+#define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT)
+#define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE)
+#define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET)
+#define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
+#define CS42L43_JACK_LINEIN (SND_JACK_MECHANICAL | SND_JACK_LINEIN)
+#define CS42L43_JACK_EXTENSION (SND_JACK_MECHANICAL)
+#define CS42L43_JACK_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | \
+ SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5)
+
+static inline bool cs42l43_jack_present(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int sts = 0;
+
+ regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts);
+
+ sts = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;
+
+ return sts == CS42L43_JACK_PRESENT;
+}
+
+static void cs42l43_start_button_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val = 0x3 << CS42L43_BUTTON_DETECT_MODE_SHIFT;
+
+ dev_dbg(priv->dev, "Start button detect\n");
+
+ priv->button_detect_running = true;
+
+ if (priv->bias_low)
+ val = 0x1 << CS42L43_BUTTON_DETECT_MODE_SHIFT;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_BUTTON_DETECT_MODE_MASK |
+ CS42L43_MIC_LVL_DET_DISABLE_MASK, val);
+
+ if (priv->bias_sense_ua) {
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_HSBIAS_SENSE_EN_MASK |
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
+ CS42L43_HSBIAS_SENSE_EN_MASK |
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
+ }
+}
+
+static void cs42l43_stop_button_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Stop button detect\n");
+
+ if (priv->bias_sense_ua) {
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_HSBIAS_SENSE_EN_MASK |
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0);
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_BUTTON_DETECT_MODE_MASK |
+ CS42L43_MIC_LVL_DET_DISABLE_MASK,
+ CS42L43_MIC_LVL_DET_DISABLE_MASK);
+
+ priv->button_detect_running = false;
+}
+
+#define CS42L43_BUTTON_COMB_MAX 512
+#define CS42L43_BUTTON_ROUT 2210
+
+void cs42l43_button_press_work(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ button_press_work.work);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int buttons = 0;
+ unsigned int val = 0;
+ int i, ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for button press: %d\n", ret);
+ return;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ if (!priv->button_detect_running) {
+ dev_dbg(priv->dev, "Spurious button press IRQ\n");
+ goto error;
+ }
+
+ regmap_read(cs42l43->regmap, CS42L43_DETECT_STATUS_1, &val);
+
+ /* Bail if jack removed, the button is irrelevant and likely invalid */
+ if (!cs42l43_jack_present(priv)) {
+ dev_dbg(priv->dev, "Button ignored due to removal\n");
+ goto error;
+ }
+
+ if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) {
+ dev_dbg(priv->dev, "Button ignored due to bias sense\n");
+ goto error;
+ }
+
+ val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT;
+ val = ((CS42L43_BUTTON_COMB_MAX << 20) / (val + 1)) - (1 << 20);
+ if (val)
+ val = (CS42L43_BUTTON_ROUT << 20) / val;
+ else
+ val = UINT_MAX;
+
+ for (i = 0; i < CS42L43_N_BUTTONS; i++) {
+ if (val < priv->buttons[i]) {
+ buttons = SND_JACK_BTN_0 >> i;
+ dev_dbg(priv->dev, "Detected button %d at %d Ohms\n", i, val);
+ break;
+ }
+ }
+
+ if (!buttons)
+ dev_dbg(priv->dev, "Unrecognised button: %d Ohms\n", val);
+
+ snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS);
+
+error:
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+}
+
+irqreturn_t cs42l43_button_press(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+
+ // Wait for 2 full cycles of comb filter to ensure good reading
+ queue_delayed_work(system_wq, &priv->button_press_work,
+ msecs_to_jiffies(10));
+
+ return IRQ_HANDLED;
+}
+
+void cs42l43_button_release_work(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ button_release_work);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for button release: %d\n", ret);
+ return;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ if (priv->button_detect_running) {
+ dev_dbg(priv->dev, "Button release IRQ\n");
+
+ snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);
+ } else {
+ dev_dbg(priv->dev, "Spurious button release IRQ\n");
+ }
+
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+}
+
+irqreturn_t cs42l43_button_release(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+
+ queue_work(system_wq, &priv->button_release_work);
+
+ return IRQ_HANDLED;
+}
+
+void cs42l43_bias_sense_timeout(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ bias_sense_timeout.work);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret);
+ return;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ if (cs42l43_jack_present(priv) && priv->button_detect_running) {
+ dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n");
+
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap,
+ CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
+ CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
+ }
+
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+}
+
+static void cs42l43_start_load_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Start load detect\n");
+
+ snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component));
+
+ priv->load_detect_running = true;
+
+ if (priv->hp_ena) {
+ unsigned long time_left;
+
+ reinit_completion(&priv->hp_shutdown);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, 0);
+
+ time_left = wait_for_completion_timeout(&priv->hp_shutdown,
+ msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
+ if (!time_left)
+ dev_err(priv->dev, "Load detect HP power down timed out\n");
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
+ CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2, CS42L43_HP_HPF_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL,
+ CS42L43_ADPTPWR_MODE_MASK, 0x4 << CS42L43_ADPTPWR_MODE_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL,
+ CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK, 0x6);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1,
+ CS42L43_HP_MSTR_VOL_CTRL_EN_MASK, 0);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA,
+ CS42L43_HPLOAD_DET_EN_MASK,
+ CS42L43_HPLOAD_DET_EN_MASK);
+
+ snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component));
+}
+
+static void cs42l43_stop_load_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Stop load detect\n");
+
+ snd_soc_dapm_mutex_lock(snd_soc_component_get_dapm(priv->component));
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_LOADDETENA,
+ CS42L43_HPLOAD_DET_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HS_CLAMP_DISABLE_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG1,
+ CS42L43_HP_MSTR_VOL_CTRL_EN_MASK,
+ CS42L43_HP_MSTR_VOL_CTRL_EN_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PGAVOL,
+ CS42L43_HP_DIG_VOL_RAMP_MASK | CS42L43_HP_ANA_VOL_RAMP_MASK,
+ 0x4 << CS42L43_HP_DIG_VOL_RAMP_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL,
+ CS42L43_ADPTPWR_MODE_MASK, 0x7 << CS42L43_ADPTPWR_MODE_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,
+ CS42L43_HSBIAS_MODE_MASK, 0x1 << CS42L43_HSBIAS_MODE_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_DACCNFG2,
+ CS42L43_HP_HPF_EN_MASK, CS42L43_HP_HPF_EN_MASK);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
+ CS42L43_ADC1_EN_MASK | CS42L43_ADC2_EN_MASK,
+ priv->adc_ena);
+
+ if (priv->hp_ena) {
+ unsigned long time_left;
+
+ reinit_completion(&priv->hp_startup);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ CS42L43_HP_EN_MASK, priv->hp_ena);
+
+ time_left = wait_for_completion_timeout(&priv->hp_startup,
+ msecs_to_jiffies(CS42L43_HP_TIMEOUT_MS));
+ if (!time_left)
+ dev_err(priv->dev, "Load detect HP restore timed out\n");
+ }
+
+ priv->load_detect_running = false;
+
+ snd_soc_dapm_mutex_unlock(snd_soc_component_get_dapm(priv->component));
+}
+
+static int cs42l43_run_load_detect(struct cs42l43_codec *priv, bool mic)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val = 0;
+ unsigned long time_left;
+
+ reinit_completion(&priv->load_detect);
+
+ cs42l43_start_load_detect(priv);
+ time_left = wait_for_completion_timeout(&priv->load_detect,
+ msecs_to_jiffies(CS42L43_LOAD_TIMEOUT_MS));
+ cs42l43_stop_load_detect(priv);
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ regmap_read(cs42l43->regmap, CS42L43_LOADDETRESULTS, &val);
+
+ dev_dbg(priv->dev, "Headphone load detect: 0x%x\n", val);
+
+ /* Bail if jack removed, the load is irrelevant and likely invalid */
+ if (!cs42l43_jack_present(priv))
+ return -ENODEV;
+
+ if (mic) {
+ cs42l43_start_hs_bias(priv, false);
+ cs42l43_start_button_detect(priv);
+
+ return CS42L43_JACK_HEADSET;
+ }
+
+ switch (val & CS42L43_AMP3_RES_DET_MASK) {
+ case 0x0: // low impedance
+ case 0x1: // high impedance
+ return CS42L43_JACK_HEADPHONE;
+ case 0x2: // lineout
+ case 0x3: // Open circuit
+ return CS42L43_JACK_LINEOUT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cs42l43_run_type_detect(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ int timeout_ms = ((2 * priv->detect_us) / 1000) + 200;
+ unsigned int type = 0xff;
+ unsigned long time_left;
+
+ reinit_completion(&priv->type_detect);
+
+ cs42l43_start_hs_bias(priv, true);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK, 0x3 << CS42L43_HSDET_MODE_SHIFT);
+
+ time_left = wait_for_completion_timeout(&priv->type_detect,
+ msecs_to_jiffies(timeout_ms));
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK, 0x2 << CS42L43_HSDET_MODE_SHIFT);
+ cs42l43_stop_hs_bias(priv);
+
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ regmap_read(cs42l43->regmap, CS42L43_HS_STAT, &type);
+
+ dev_dbg(priv->dev, "Type detect: 0x%x\n", type);
+
+ /* Bail if jack removed, the type is irrelevant and likely invalid */
+ if (!cs42l43_jack_present(priv))
+ return -ENODEV;
+
+ switch (type & CS42L43_HSDET_TYPE_STS_MASK) {
+ case 0x0: // CTIA
+ case 0x1: // OMTP
+ return cs42l43_run_load_detect(priv, true);
+ case 0x2: // 3-pole
+ return cs42l43_run_load_detect(priv, false);
+ case 0x3: // Open-circuit
+ return CS42L43_JACK_EXTENSION;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void cs42l43_clear_jack(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ cs42l43_stop_button_detect(priv);
+ cs42l43_stop_hs_bias(priv);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,
+ CS42L43_JACK_STEREO_CONFIG_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK | CS42L43_HSDET_MANUAL_MODE_MASK,
+ 0x2 << CS42L43_HSDET_MODE_SHIFT);
+
+ snd_soc_jack_report(priv->jack_hp, 0, 0xFFFF);
+}
+
+void cs42l43_tip_sense_work(struct work_struct *work)
+{
+ struct cs42l43_codec *priv = container_of(work, struct cs42l43_codec,
+ tip_sense_work.work);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int sts = 0;
+ unsigned int tip, ring;
+ int ret, report;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for tip work: %d\n", ret);
+ return;
+ }
+
+ mutex_lock(&priv->jack_lock);
+
+ regmap_read(cs42l43->regmap, CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS, &sts);
+
+ dev_dbg(priv->dev, "Tip sense: 0x%x\n", sts);
+
+ tip = (sts >> CS42L43_TIPSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;
+ ring = (sts >> CS42L43_RINGSENSE_PLUG_DB_STS_SHIFT) & CS42L43_JACK_PRESENT;
+
+ if (tip == CS42L43_JACK_PRESENT) {
+ if (cs42l43->sdw && !priv->jack_present) {
+ priv->jack_present = true;
+ pm_runtime_get(priv->dev);
+ }
+
+ if (priv->use_ring_sense && ring == CS42L43_JACK_ABSENT) {
+ report = CS42L43_JACK_OPTICAL;
+ } else {
+ report = cs42l43_run_type_detect(priv);
+ if (report < 0) {
+ dev_err(priv->dev, "Jack detect failed: %d\n", report);
+ goto error;
+ }
+ }
+
+ snd_soc_jack_report(priv->jack_hp, report, report);
+ } else {
+ priv->jack_override = 0;
+
+ cs42l43_clear_jack(priv);
+
+ if (cs42l43->sdw && priv->jack_present) {
+ pm_runtime_put(priv->dev);
+ priv->jack_present = false;
+ }
+ }
+
+error:
+ mutex_unlock(&priv->jack_lock);
+
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+}
+
+irqreturn_t cs42l43_tip_sense(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+
+ cancel_delayed_work(&priv->bias_sense_timeout);
+ cancel_delayed_work(&priv->tip_sense_work);
+ cancel_delayed_work(&priv->button_press_work);
+ cancel_work(&priv->button_release_work);
+
+ queue_delayed_work(system_long_wq, &priv->tip_sense_work,
+ msecs_to_jiffies(priv->tip_debounce_ms));
+
+ return IRQ_HANDLED;
+}
+
+enum cs42l43_raw_jack {
+ CS42L43_JACK_RAW_CTIA = 0,
+ CS42L43_JACK_RAW_OMTP,
+ CS42L43_JACK_RAW_HEADPHONE,
+ CS42L43_JACK_RAW_LINE_OUT,
+ CS42L43_JACK_RAW_LINE_IN,
+ CS42L43_JACK_RAW_MICROPHONE,
+ CS42L43_JACK_RAW_OPTICAL,
+};
+
+#define CS42L43_JACK_3_POLE_SWITCHES ((0x2 << CS42L43_HSDET_MANUAL_MODE_SHIFT) | \
+ CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK | \
+ CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK | \
+ CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK | \
+ CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK | \
+ CS42L43_HSGND_HS3_SEL_MASK | \
+ CS42L43_HSGND_HS4_SEL_MASK)
+
+static const struct cs42l43_jack_override_mode {
+ unsigned int hsdet_mode;
+ unsigned int mic_ctrl;
+ unsigned int clamp_ctrl;
+ int report;
+} cs42l43_jack_override_modes[] = {
+ [CS42L43_JACK_RAW_CTIA] = {
+ .hsdet_mode = CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS4_SEL_MASK |
+ CS42L43_HSGND_HS3_SEL_MASK,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_HEADSET,
+ },
+ [CS42L43_JACK_RAW_OMTP] = {
+ .hsdet_mode = (0x1 << CS42L43_HSDET_MANUAL_MODE_SHIFT) |
+ CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS3_SEL_MASK |
+ CS42L43_HSGND_HS4_SEL_MASK,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_HEADSET,
+ },
+ [CS42L43_JACK_RAW_HEADPHONE] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_HEADPHONE,
+ },
+ [CS42L43_JACK_RAW_LINE_OUT] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_LINEOUT,
+ },
+ [CS42L43_JACK_RAW_LINE_IN] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .mic_ctrl = 0x2 << CS42L43_JACK_STEREO_CONFIG_SHIFT,
+ .report = CS42L43_JACK_LINEIN,
+ },
+ [CS42L43_JACK_RAW_MICROPHONE] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) |
+ CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK,
+ .report = CS42L43_JACK_LINEIN,
+ },
+ [CS42L43_JACK_RAW_OPTICAL] = {
+ .hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ .clamp_ctrl = CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ .report = CS42L43_JACK_OPTICAL,
+ },
+};
+
+static const char * const cs42l43_jack_text[] = {
+ "None", "CTIA", "OMTP", "Headphone", "Line-Out",
+ "Line-In", "Microphone", "Optical",
+};
+
+SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_jack_enum, cs42l43_jack_text);
+
+int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&priv->jack_lock);
+ ucontrol->value.integer.value[0] = priv->jack_override;
+ mutex_unlock(&priv->jack_lock);
+
+ return 0;
+}
+
+int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int override = ucontrol->value.integer.value[0];
+
+ BUILD_BUG_ON(ARRAY_SIZE(cs42l43_jack_override_modes) !=
+ ARRAY_SIZE(cs42l43_jack_text) - 1);
+
+ if (override >= e->items)
+ return -EINVAL;
+
+ mutex_lock(&priv->jack_lock);
+
+ if (!cs42l43_jack_present(priv)) {
+ mutex_unlock(&priv->jack_lock);
+ return -EBUSY;
+ }
+
+ if (override == priv->jack_override) {
+ mutex_unlock(&priv->jack_lock);
+ return 0;
+ }
+
+ priv->jack_override = override;
+
+ cs42l43_clear_jack(priv);
+
+ if (!override) {
+ queue_delayed_work(system_long_wq, &priv->tip_sense_work, 0);
+ } else {
+ override--;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
+ CS42L43_HSDET_MODE_MASK |
+ CS42L43_HSDET_MANUAL_MODE_MASK |
+ CS42L43_AMP3_4_GNDREF_HS3_SEL_MASK |
+ CS42L43_AMP3_4_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS3_SEL_MASK |
+ CS42L43_HSBIAS_GNDREF_HS4_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS3_SEL_MASK |
+ CS42L43_HSBIAS_OUT_HS4_SEL_MASK |
+ CS42L43_HSGND_HS3_SEL_MASK |
+ CS42L43_HSGND_HS4_SEL_MASK,
+ cs42l43_jack_override_modes[override].hsdet_mode);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CTRL,
+ CS42L43_HS2_BIAS_EN_MASK | CS42L43_HS1_BIAS_EN_MASK |
+ CS42L43_JACK_STEREO_CONFIG_MASK,
+ cs42l43_jack_override_modes[override].mic_ctrl);
+ regmap_update_bits(cs42l43->regmap, CS42L43_STEREO_MIC_CLAMP_CTRL,
+ CS42L43_SMIC_HPAMP_CLAMP_DIS_FRC_MASK,
+ cs42l43_jack_override_modes[override].clamp_ctrl);
+
+ switch (override) {
+ case CS42L43_JACK_RAW_CTIA:
+ case CS42L43_JACK_RAW_OMTP:
+ cs42l43_start_hs_bias(priv, false);
+ cs42l43_start_button_detect(priv);
+ break;
+ case CS42L43_JACK_RAW_LINE_IN:
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL1,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ADC_B_CTRL2,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK,
+ CS42L43_PGA_WIDESWING_MODE_EN_MASK);
+ break;
+ case CS42L43_JACK_RAW_MICROPHONE:
+ cs42l43_start_hs_bias(priv, false);
+ break;
+ default:
+ break;
+ }
+
+ snd_soc_jack_report(priv->jack_hp,
+ cs42l43_jack_override_modes[override].report,
+ cs42l43_jack_override_modes[override].report);
+ }
+
+ mutex_unlock(&priv->jack_lock);
+
+ return 1;
+}
diff --git a/sound/soc/codecs/cs42l43-sdw.c b/sound/soc/codecs/cs42l43-sdw.c
new file mode 100644
index 000000000000..55ac5fe8c3db
--- /dev/null
+++ b/sound/soc/codecs/cs42l43-sdw.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 CODEC driver SoundWire handling
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/errno.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/sdw.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+
+#include "cs42l43.h"
+
+int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent);
+ struct sdw_stream_config sconfig = {0};
+ struct sdw_port_config pconfig = {0};
+ int ret;
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ snd_sdw_params_to_config(substream, params, &sconfig, &pconfig);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ pconfig.num = dai->id;
+ else
+ pconfig.num = dai->id;
+
+ ret = sdw_stream_add_slave(sdw, &sconfig, &pconfig, 1, sdw_stream);
+ if (ret) {
+ dev_err(priv->dev, "Failed to add sdw stream: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, SND_SOC_CS42L43);
+
+int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct sdw_stream_runtime *sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+ struct sdw_slave *sdw = dev_to_sdw_dev(priv->dev->parent);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ return sdw_stream_remove_slave(sdw, sdw_stream);
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, SND_SOC_CS42L43);
+
+int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, SND_SOC_CS42L43);
+
+MODULE_DESCRIPTION("CS42L43 CODEC SoundWire Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
new file mode 100644
index 000000000000..24e718e51174
--- /dev/null
+++ b/sound/soc/codecs/cs42l43.c
@@ -0,0 +1,2278 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 CODEC driver
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gcd.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-component.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc-dai.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42l43.h"
+
+#define CS42L43_DECL_MUX(name, reg) \
+static SOC_VALUE_ENUM_SINGLE_DECL(cs42l43_##name##_enum, reg, \
+ 0, CS42L43_MIXER_SRC_MASK, \
+ cs42l43_mixer_texts, cs42l43_mixer_values); \
+static const struct snd_kcontrol_new cs42l43_##name##_mux = \
+ SOC_DAPM_ENUM("Route", cs42l43_##name##_enum)
+
+#define CS42L43_DECL_MIXER(name, reg) \
+ CS42L43_DECL_MUX(name##_in1, reg); \
+ CS42L43_DECL_MUX(name##_in2, reg + 0x4); \
+ CS42L43_DECL_MUX(name##_in3, reg + 0x8); \
+ CS42L43_DECL_MUX(name##_in4, reg + 0xC)
+
+#define CS42L43_DAPM_MUX(name_str, name) \
+ SND_SOC_DAPM_MUX(name_str " Input", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_mux)
+
+#define CS42L43_DAPM_MIXER(name_str, name) \
+ SND_SOC_DAPM_MUX(name_str " Input 1", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in1_mux), \
+ SND_SOC_DAPM_MUX(name_str " Input 2", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in2_mux), \
+ SND_SOC_DAPM_MUX(name_str " Input 3", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in3_mux), \
+ SND_SOC_DAPM_MUX(name_str " Input 4", SND_SOC_NOPM, 0, 0, &cs42l43_##name##_in4_mux), \
+ SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
+
+#define CS42L43_BASE_ROUTES(name_str) \
+ { name_str, "Tone Generator 1", "Tone 1" }, \
+ { name_str, "Tone Generator 2", "Tone 2" }, \
+ { name_str, "Decimator 1", "Decimator 1" }, \
+ { name_str, "Decimator 2", "Decimator 2" }, \
+ { name_str, "Decimator 3", "Decimator 3" }, \
+ { name_str, "Decimator 4", "Decimator 4" }, \
+ { name_str, "ASPRX1", "ASPRX1" }, \
+ { name_str, "ASPRX2", "ASPRX2" }, \
+ { name_str, "ASPRX3", "ASPRX3" }, \
+ { name_str, "ASPRX4", "ASPRX4" }, \
+ { name_str, "ASPRX5", "ASPRX5" }, \
+ { name_str, "ASPRX6", "ASPRX6" }, \
+ { name_str, "DP5RX1", "DP5RX1" }, \
+ { name_str, "DP5RX2", "DP5RX2" }, \
+ { name_str, "DP6RX1", "DP6RX1" }, \
+ { name_str, "DP6RX2", "DP6RX2" }, \
+ { name_str, "DP7RX1", "DP7RX1" }, \
+ { name_str, "DP7RX2", "DP7RX2" }, \
+ { name_str, "ASRC INT1", "ASRC_INT1" }, \
+ { name_str, "ASRC INT2", "ASRC_INT2" }, \
+ { name_str, "ASRC INT3", "ASRC_INT3" }, \
+ { name_str, "ASRC INT4", "ASRC_INT4" }, \
+ { name_str, "ASRC DEC1", "ASRC_DEC1" }, \
+ { name_str, "ASRC DEC2", "ASRC_DEC2" }, \
+ { name_str, "ASRC DEC3", "ASRC_DEC3" }, \
+ { name_str, "ASRC DEC4", "ASRC_DEC4" }, \
+ { name_str, "ISRC1 INT1", "ISRC1INT1" }, \
+ { name_str, "ISRC1 INT2", "ISRC1INT2" }, \
+ { name_str, "ISRC1 DEC1", "ISRC1DEC1" }, \
+ { name_str, "ISRC1 DEC2", "ISRC1DEC2" }, \
+ { name_str, "ISRC2 INT1", "ISRC2INT1" }, \
+ { name_str, "ISRC2 INT2", "ISRC2INT2" }, \
+ { name_str, "ISRC2 DEC1", "ISRC2DEC1" }, \
+ { name_str, "ISRC2 DEC2", "ISRC2DEC2" }, \
+ { name_str, "EQ1", "EQ" }, \
+ { name_str, "EQ2", "EQ" }
+
+#define CS42L43_MUX_ROUTES(name_str, widget) \
+ { widget, NULL, name_str " Input" }, \
+ { name_str " Input", NULL, "Mixer Core" }, \
+ CS42L43_BASE_ROUTES(name_str " Input")
+
+#define CS42L43_MIXER_ROUTES(name_str, widget) \
+ { name_str " Mixer", NULL, name_str " Input 1" }, \
+ { name_str " Mixer", NULL, name_str " Input 2" }, \
+ { name_str " Mixer", NULL, name_str " Input 3" }, \
+ { name_str " Mixer", NULL, name_str " Input 4" }, \
+ { widget, NULL, name_str " Mixer" }, \
+ { name_str " Mixer", NULL, "Mixer Core" }, \
+ CS42L43_BASE_ROUTES(name_str " Input 1"), \
+ CS42L43_BASE_ROUTES(name_str " Input 2"), \
+ CS42L43_BASE_ROUTES(name_str " Input 3"), \
+ CS42L43_BASE_ROUTES(name_str " Input 4")
+
+#define CS42L43_MIXER_VOLUMES(name_str, base) \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 1 Volume", base, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 2 Volume", base + 4, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 3 Volume", base + 8, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv), \
+ SOC_SINGLE_RANGE_TLV(name_str " Input 4 Volume", base + 12, \
+ CS42L43_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \
+ cs42l43_mixer_tlv)
+
+#define CS42L43_IRQ_ERROR(name) \
+static irqreturn_t cs42l43_##name(int irq, void *data) \
+{ \
+ struct cs42l43_codec *priv = data; \
+ dev_err(priv->dev, "Error " #name " IRQ\n"); \
+ return IRQ_HANDLED; \
+}
+
+CS42L43_IRQ_ERROR(pll_lost_lock)
+CS42L43_IRQ_ERROR(spkr_clock_stop)
+CS42L43_IRQ_ERROR(spkl_clock_stop)
+CS42L43_IRQ_ERROR(spkr_brown_out)
+CS42L43_IRQ_ERROR(spkl_brown_out)
+CS42L43_IRQ_ERROR(spkr_therm_shutdown)
+CS42L43_IRQ_ERROR(spkl_therm_shutdown)
+CS42L43_IRQ_ERROR(spkr_therm_warm)
+CS42L43_IRQ_ERROR(spkl_therm_warm)
+CS42L43_IRQ_ERROR(spkr_sc_detect)
+CS42L43_IRQ_ERROR(spkl_sc_detect)
+CS42L43_IRQ_ERROR(hp_ilimit)
+
+#define CS42L43_IRQ_COMPLETE(name) \
+static irqreturn_t cs42l43_##name(int irq, void *data) \
+{ \
+ struct cs42l43_codec *priv = data; \
+ dev_dbg(priv->dev, #name " completed\n"); \
+ complete(&priv->name); \
+ return IRQ_HANDLED; \
+}
+
+CS42L43_IRQ_COMPLETE(pll_ready)
+CS42L43_IRQ_COMPLETE(hp_startup)
+CS42L43_IRQ_COMPLETE(hp_shutdown)
+CS42L43_IRQ_COMPLETE(type_detect)
+CS42L43_IRQ_COMPLETE(spkr_shutdown)
+CS42L43_IRQ_COMPLETE(spkl_shutdown)
+CS42L43_IRQ_COMPLETE(spkr_startup)
+CS42L43_IRQ_COMPLETE(spkl_startup)
+CS42L43_IRQ_COMPLETE(load_detect)
+
+static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ const char * const controls[] = {
+ "Decimator 1 Switch",
+ "Decimator 2 Switch",
+ "Decimator 3 Switch",
+ "Decimator 4 Switch",
+ };
+ int i, ret;
+
+ dev_dbg(priv->dev, "Microphone shutter changed\n");
+
+ if (!priv->component)
+ return IRQ_NONE;
+
+ for (i = 0; i < ARRAY_SIZE(controls); i++) {
+ ret = snd_soc_component_notify_control(priv->component,
+ controls[i]);
+ if (ret)
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cs42l43_spk_shutter(int irq, void *data)
+{
+ struct cs42l43_codec *priv = data;
+ int ret;
+
+ dev_dbg(priv->dev, "Speaker shutter changed\n");
+
+ if (!priv->component)
+ return IRQ_NONE;
+
+ ret = snd_soc_component_notify_control(priv->component,
+ "Speaker Digital Switch");
+ if (ret)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
+static const unsigned int cs42l43_sample_rates[] = {
+ 8000, 16000, 24000, 32000, 44100, 48000, 96000, 192000,
+};
+
+#define CS42L43_CONSUMER_RATE_MASK 0xFF
+#define CS42L43_PROVIDER_RATE_MASK 0xEF // 44.1k only supported as consumer
+
+static const struct snd_pcm_hw_constraint_list cs42l43_constraint = {
+ .count = ARRAY_SIZE(cs42l43_sample_rates),
+ .list = cs42l43_sample_rates,
+};
+
+static int cs42l43_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
+
+ if (provider)
+ priv->constraint.mask = CS42L43_PROVIDER_RATE_MASK;
+ else
+ priv->constraint.mask = CS42L43_CONSUMER_RATE_MASK;
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &priv->constraint);
+}
+
+static int cs42l43_convert_sample_rate(unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return 0x11;
+ case 16000:
+ return 0x12;
+ case 24000:
+ return 0x02;
+ case 32000:
+ return 0x13;
+ case 44100:
+ return 0x0B;
+ case 48000:
+ return 0x03;
+ case 96000:
+ return 0x04;
+ case 192000:
+ return 0x05;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cs42l43_set_sample_rate(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ ret = cs42l43_convert_sample_rate(params_rate(params));
+ if (ret < 0) {
+ dev_err(priv->dev, "Failed to convert sample rate: %d\n", ret);
+ return ret;
+ }
+
+ //FIXME: For now lets just set sample rate 1, this needs expanded in the future
+ regmap_update_bits(cs42l43->regmap, CS42L43_SAMPLE_RATE1,
+ CS42L43_SAMPLE_RATE_MASK, ret);
+
+ return 0;
+}
+
+static int cs42l43_asp_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(dai->component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int dsp_mode = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CTRL,
+ CS42L43_ASP_FSYNC_MODE_MASK);
+ int provider = !!regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
+ int n_chans = params_channels(params);
+ int data_width = params_width(params);
+ int n_slots = n_chans;
+ int slot_width = data_width;
+ int frame, bclk_target, i;
+ unsigned int reg;
+ int *slots;
+
+ if (priv->n_slots) {
+ n_slots = priv->n_slots;
+ slot_width = priv->slot_width;
+ }
+
+ if (!dsp_mode && (n_slots & 0x1)) {
+ dev_dbg(priv->dev, "Forcing balanced channels on ASP\n");
+ n_slots++;
+ }
+
+ frame = n_slots * slot_width;
+ bclk_target = params_rate(params) * frame;
+
+ if (provider) {
+ unsigned int gcd_nm = gcd(bclk_target, CS42L43_INTERNAL_SYSCLK);
+ int n = bclk_target / gcd_nm;
+ int m = CS42L43_INTERNAL_SYSCLK / gcd_nm;
+
+ if (n > (CS42L43_ASP_BCLK_N_MASK >> CS42L43_ASP_BCLK_N_SHIFT) ||
+ m > CS42L43_ASP_BCLK_M_MASK) {
+ dev_err(priv->dev, "Can't produce %dHz bclk\n", bclk_target);
+ return -EINVAL;
+ }
+
+ dev_dbg(priv->dev, "bclk %d/%d = %dHz, with %dx%d frame\n",
+ n, m, bclk_target, n_slots, slot_width);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG1,
+ CS42L43_ASP_BCLK_N_MASK | CS42L43_ASP_BCLK_M_MASK,
+ n << CS42L43_ASP_BCLK_N_SHIFT |
+ m << CS42L43_ASP_BCLK_M_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL1,
+ CS42L43_ASP_FSYNC_M_MASK, frame);
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL4,
+ CS42L43_ASP_NUM_BCLKS_PER_FSYNC_MASK,
+ frame << CS42L43_ASP_NUM_BCLKS_PER_FSYNC_SHIFT);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ reg = CS42L43_ASP_TX_CH1_CTRL;
+ slots = priv->tx_slots;
+ } else {
+ reg = CS42L43_ASP_RX_CH1_CTRL;
+ slots = priv->rx_slots;
+ }
+
+ for (i = 0; i < n_chans; i++, reg += 4) {
+ int slot_phase = dsp_mode | (i & CS42L43_ASP_CH_SLOT_PHASE_MASK);
+ int slot_pos;
+
+ if (dsp_mode)
+ slot_pos = slots[i] * slot_width;
+ else
+ slot_pos = (slots[i] / 2) * slot_width;
+
+ dev_dbg(priv->dev, "Configure channel %d at slot %d (%d,%d)\n",
+ i, slots[i], slot_pos, slot_phase);
+
+ regmap_update_bits(cs42l43->regmap, reg,
+ CS42L43_ASP_CH_WIDTH_MASK |
+ CS42L43_ASP_CH_SLOT_MASK |
+ CS42L43_ASP_CH_SLOT_PHASE_MASK,
+ ((data_width - 1) << CS42L43_ASP_CH_WIDTH_SHIFT) |
+ (slot_pos << CS42L43_ASP_CH_SLOT_SHIFT) |
+ slot_phase);
+ }
+
+ return cs42l43_set_sample_rate(substream, params, dai);
+}
+
+static int cs42l43_asp_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int provider = regmap_test_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK);
+ struct snd_soc_dapm_route routes[] = {
+ { "BCLK", NULL, "FSYNC" },
+ };
+ unsigned int asp_ctrl = 0;
+ unsigned int data_ctrl = 0;
+ unsigned int fsync_ctrl = 0;
+ unsigned int clk_config = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT;
+ fallthrough;
+ case SND_SOC_DAIFMT_DSP_B:
+ asp_ctrl |= CS42L43_ASP_FSYNC_MODE_MASK;
+ data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ data_ctrl |= 2 << CS42L43_ASP_FSYNC_FRAME_START_DLY_SHIFT;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ data_ctrl |= CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK;
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported DAI format 0x%x\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_CBC_CFC:
+ if (provider)
+ snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
+ break;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ if (!provider)
+ snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
+ clk_config |= CS42L43_ASP_MASTER_MODE_MASK;
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported ASP mode 0x%x\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ clk_config |= CS42L43_ASP_BCLK_INV_MASK; /* Yes BCLK_INV = NB */
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ clk_config |= CS42L43_ASP_BCLK_INV_MASK;
+ fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK |
+ CS42L43_ASP_FSYNC_OUT_INV_MASK;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ fsync_ctrl |= CS42L43_ASP_FSYNC_IN_INV_MASK |
+ CS42L43_ASP_FSYNC_OUT_INV_MASK;
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported invert mode 0x%x\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CTRL,
+ CS42L43_ASP_FSYNC_MODE_MASK,
+ asp_ctrl);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_DATA_CTRL,
+ CS42L43_ASP_FSYNC_FRAME_START_DLY_MASK |
+ CS42L43_ASP_FSYNC_FRAME_START_PHASE_MASK,
+ data_ctrl);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_CLK_CONFIG2,
+ CS42L43_ASP_MASTER_MODE_MASK |
+ CS42L43_ASP_BCLK_INV_MASK,
+ clk_config);
+ regmap_update_bits(cs42l43->regmap, CS42L43_ASP_FSYNC_CTRL3,
+ CS42L43_ASP_FSYNC_IN_INV_MASK |
+ CS42L43_ASP_FSYNC_OUT_INV_MASK,
+ fsync_ctrl);
+
+ return 0;
+}
+
+static void cs42l43_mask_to_slots(struct cs42l43_codec *priv, unsigned int mask, int *slots)
+{
+ int i;
+
+ for (i = 0; i < CS42L43_ASP_MAX_CHANNELS; ++i) {
+ int slot = ffs(mask) - 1;
+
+ if (slot < 0)
+ return;
+
+ slots[i] = slot;
+
+ mask &= ~(1 << slot);
+ }
+
+ if (mask)
+ dev_warn(priv->dev, "Too many channels in TDM mask\n");
+}
+
+static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ priv->n_slots = slots;
+ priv->slot_width = slot_width;
+
+ if (!slots) {
+ tx_mask = CS42L43_DEFAULT_SLOTS;
+ rx_mask = CS42L43_DEFAULT_SLOTS;
+ }
+
+ cs42l43_mask_to_slots(priv, tx_mask, priv->tx_slots);
+ cs42l43_mask_to_slots(priv, rx_mask, priv->rx_slots);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs42l43_asp_ops = {
+ .startup = cs42l43_startup,
+ .hw_params = cs42l43_asp_hw_params,
+ .set_fmt = cs42l43_asp_set_fmt,
+ .set_tdm_slot = cs42l43_asp_set_tdm_slot,
+};
+
+static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = cs42l43_sdw_add_peripheral(substream, params, dai);
+ if (ret)
+ return ret;
+
+ return cs42l43_set_sample_rate(substream, params, dai);
+};
+
+static const struct snd_soc_dai_ops cs42l43_sdw_ops = {
+ .startup = cs42l43_startup,
+ .set_stream = cs42l43_sdw_set_stream,
+ .hw_params = cs42l43_sdw_hw_params,
+ .hw_free = cs42l43_sdw_remove_peripheral,
+};
+
+#define CS42L43_ASP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+#define CS42L43_SDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver cs42l43_dais[] = {
+ {
+ .name = "cs42l43-asp",
+ .ops = &cs42l43_asp_ops,
+ .symmetric_rate = 1,
+ .capture = {
+ .stream_name = "ASP Capture",
+ .channels_min = 1,
+ .channels_max = CS42L43_ASP_MAX_CHANNELS,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_ASP_FORMATS,
+ },
+ .playback = {
+ .stream_name = "ASP Playback",
+ .channels_min = 1,
+ .channels_max = CS42L43_ASP_MAX_CHANNELS,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_ASP_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp1",
+ .id = 1,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP1 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp2",
+ .id = 2,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp3",
+ .id = 3,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP3 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp4",
+ .id = 4,
+ .ops = &cs42l43_sdw_ops,
+ .capture = {
+ .stream_name = "DP4 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp5",
+ .id = 5,
+ .ops = &cs42l43_sdw_ops,
+ .playback = {
+ .stream_name = "DP5 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp6",
+ .id = 6,
+ .ops = &cs42l43_sdw_ops,
+ .playback = {
+ .stream_name = "DP6 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+ {
+ .name = "cs42l43-dp7",
+ .id = 7,
+ .ops = &cs42l43_sdw_ops,
+ .playback = {
+ .stream_name = "DP7 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS42L43_SDW_FORMATS,
+ },
+ },
+};
+
+static const DECLARE_TLV_DB_SCALE(cs42l43_mixer_tlv, -3200, 100, 0);
+
+static const char * const cs42l43_ramp_text[] = {
+ "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
+ "15ms/6dB", "30ms/6dB",
+};
+
+static const char * const cs42l43_adc1_input_text[] = { "IN1", "IN2" };
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_adc1_input, CS42L43_ADC_B_CTRL1,
+ CS42L43_ADC_AIN_SEL_SHIFT,
+ cs42l43_adc1_input_text);
+
+static const struct snd_kcontrol_new cs42l43_adc1_input_ctl =
+ SOC_DAPM_ENUM("ADC1 Input", cs42l43_adc1_input);
+
+static const char * const cs42l43_dec_mode_text[] = { "ADC", "PDM" };
+
+static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec1_mode, cs42l43_dec_mode_text);
+static SOC_ENUM_SINGLE_VIRT_DECL(cs42l43_dec2_mode, cs42l43_dec_mode_text);
+
+static const struct snd_kcontrol_new cs42l43_dec_mode_ctl[] = {
+ SOC_DAPM_ENUM("Decimator 1 Mode", cs42l43_dec1_mode),
+ SOC_DAPM_ENUM("Decimator 2 Mode", cs42l43_dec2_mode),
+};
+
+static const char * const cs42l43_pdm_clk_text[] = {
+ "3.072MHz", "1.536MHz", "768kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_pdm1_clk, CS42L43_PDM_CONTROL,
+ CS42L43_PDM1_CLK_DIV_SHIFT, cs42l43_pdm_clk_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_pdm2_clk, CS42L43_PDM_CONTROL,
+ CS42L43_PDM2_CLK_DIV_SHIFT, cs42l43_pdm_clk_text);
+
+static DECLARE_TLV_DB_SCALE(cs42l43_adc_tlv, -600, 600, 0);
+static DECLARE_TLV_DB_SCALE(cs42l43_dec_tlv, -6400, 50, 0);
+
+static const char * const cs42l43_wnf_corner_text[] = {
+ "160Hz", "180Hz", "200Hz", "220Hz", "240Hz", "260Hz", "280Hz", "300Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_wnf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_WNF_CF_SHIFT, cs42l43_wnf_corner_text);
+
+static const char * const cs42l43_hpf_corner_text[] = {
+ "3Hz", "12Hz", "48Hz", "96Hz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_hpf_corner, CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_HPF_CF_SHIFT, cs42l43_hpf_corner_text);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec1_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_up, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec2_ramp_down, CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec3_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VD_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_up, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VI_RAMP_SHIFT, cs42l43_ramp_text);
+static SOC_ENUM_SINGLE_DECL(cs42l43_dec4_ramp_down, CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VD_RAMP_SHIFT, cs42l43_ramp_text);
+
+static DECLARE_TLV_DB_SCALE(cs42l43_speaker_tlv, -6400, 50, 0);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_up, CS42L43_AMP1_2_VOL_RAMP,
+ CS42L43_AMP1_2_VI_RAMP_SHIFT, cs42l43_ramp_text);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_speaker_ramp_down, CS42L43_AMP1_2_VOL_RAMP,
+ CS42L43_AMP1_2_VD_RAMP_SHIFT, cs42l43_ramp_text);
+
+static DECLARE_TLV_DB_SCALE(cs42l43_headphone_tlv, -11450, 50, 1);
+
+static const char * const cs42l43_headphone_ramp_text[] = {
+ "1", "2", "4", "6", "8", "11", "12", "16", "22", "24", "33", "36", "44",
+ "48", "66", "72",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_headphone_ramp, CS42L43_PGAVOL,
+ CS42L43_HP_PATH_VOL_RAMP_SHIFT,
+ cs42l43_headphone_ramp_text);
+
+static const char * const cs42l43_tone_freq_text[] = {
+ "1kHz", "2kHz", "4kHz", "6kHz", "8kHz",
+};
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_tone1_freq, CS42L43_TONE_CH1_CTRL,
+ CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text);
+
+static SOC_ENUM_SINGLE_DECL(cs42l43_tone2_freq, CS42L43_TONE_CH2_CTRL,
+ CS42L43_TONE_FREQ_SHIFT, cs42l43_tone_freq_text);
+
+static const char * const cs42l43_mixer_texts[] = {
+ "None",
+ "Tone Generator 1", "Tone Generator 2",
+ "Decimator 1", "Decimator 2", "Decimator 3", "Decimator 4",
+ "ASPRX1", "ASPRX2", "ASPRX3", "ASPRX4", "ASPRX5", "ASPRX6",
+ "DP5RX1", "DP5RX2", "DP6RX1", "DP6RX2", "DP7RX1", "DP7RX2",
+ "ASRC INT1", "ASRC INT2", "ASRC INT3", "ASRC INT4",
+ "ASRC DEC1", "ASRC DEC2", "ASRC DEC3", "ASRC DEC4",
+ "ISRC1 INT1", "ISRC1 INT2",
+ "ISRC1 DEC1", "ISRC1 DEC2",
+ "ISRC2 INT1", "ISRC2 INT2",
+ "ISRC2 DEC1", "ISRC2 DEC2",
+ "EQ1", "EQ2",
+};
+
+static const unsigned int cs42l43_mixer_values[] = {
+ 0x00, // None
+ 0x04, 0x05, // Tone Generator 1, 2
+ 0x10, 0x11, 0x12, 0x13, // Decimator 1, 2, 3, 4
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, // ASPRX1,2,3,4,5,6
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // DP5, 6, 7RX1, 2
+ 0x40, 0x41, 0x42, 0x43, // ASRC INT1, 2, 3, 4
+ 0x44, 0x45, 0x46, 0x47, // ASRC DEC1, 2, 3, 4
+ 0x50, 0x51, // ISRC1 INT1, 2
+ 0x52, 0x53, // ISRC1 DEC1, 2
+ 0x54, 0x55, // ISRC2 INT1, 2
+ 0x56, 0x57, // ISRC2 DEC1, 2
+ 0x58, 0x59, // EQ1, 2
+};
+
+CS42L43_DECL_MUX(asptx1, CS42L43_ASPTX1_INPUT);
+CS42L43_DECL_MUX(asptx2, CS42L43_ASPTX2_INPUT);
+CS42L43_DECL_MUX(asptx3, CS42L43_ASPTX3_INPUT);
+CS42L43_DECL_MUX(asptx4, CS42L43_ASPTX4_INPUT);
+CS42L43_DECL_MUX(asptx5, CS42L43_ASPTX5_INPUT);
+CS42L43_DECL_MUX(asptx6, CS42L43_ASPTX6_INPUT);
+
+CS42L43_DECL_MUX(dp1tx1, CS42L43_SWIRE_DP1_CH1_INPUT);
+CS42L43_DECL_MUX(dp1tx2, CS42L43_SWIRE_DP1_CH2_INPUT);
+CS42L43_DECL_MUX(dp1tx3, CS42L43_SWIRE_DP1_CH3_INPUT);
+CS42L43_DECL_MUX(dp1tx4, CS42L43_SWIRE_DP1_CH4_INPUT);
+CS42L43_DECL_MUX(dp2tx1, CS42L43_SWIRE_DP2_CH1_INPUT);
+CS42L43_DECL_MUX(dp2tx2, CS42L43_SWIRE_DP2_CH2_INPUT);
+CS42L43_DECL_MUX(dp3tx1, CS42L43_SWIRE_DP3_CH1_INPUT);
+CS42L43_DECL_MUX(dp3tx2, CS42L43_SWIRE_DP3_CH2_INPUT);
+CS42L43_DECL_MUX(dp4tx1, CS42L43_SWIRE_DP4_CH1_INPUT);
+CS42L43_DECL_MUX(dp4tx2, CS42L43_SWIRE_DP4_CH2_INPUT);
+
+CS42L43_DECL_MUX(asrcint1, CS42L43_ASRC_INT1_INPUT1);
+CS42L43_DECL_MUX(asrcint2, CS42L43_ASRC_INT2_INPUT1);
+CS42L43_DECL_MUX(asrcint3, CS42L43_ASRC_INT3_INPUT1);
+CS42L43_DECL_MUX(asrcint4, CS42L43_ASRC_INT4_INPUT1);
+CS42L43_DECL_MUX(asrcdec1, CS42L43_ASRC_DEC1_INPUT1);
+CS42L43_DECL_MUX(asrcdec2, CS42L43_ASRC_DEC2_INPUT1);
+CS42L43_DECL_MUX(asrcdec3, CS42L43_ASRC_DEC3_INPUT1);
+CS42L43_DECL_MUX(asrcdec4, CS42L43_ASRC_DEC4_INPUT1);
+
+CS42L43_DECL_MUX(isrc1int1, CS42L43_ISRC1INT1_INPUT1);
+CS42L43_DECL_MUX(isrc1int2, CS42L43_ISRC1INT2_INPUT1);
+CS42L43_DECL_MUX(isrc1dec1, CS42L43_ISRC1DEC1_INPUT1);
+CS42L43_DECL_MUX(isrc1dec2, CS42L43_ISRC1DEC2_INPUT1);
+CS42L43_DECL_MUX(isrc2int1, CS42L43_ISRC2INT1_INPUT1);
+CS42L43_DECL_MUX(isrc2int2, CS42L43_ISRC2INT2_INPUT1);
+CS42L43_DECL_MUX(isrc2dec1, CS42L43_ISRC2DEC1_INPUT1);
+CS42L43_DECL_MUX(isrc2dec2, CS42L43_ISRC2DEC2_INPUT1);
+
+CS42L43_DECL_MUX(spdif1, CS42L43_SPDIF1_INPUT1);
+CS42L43_DECL_MUX(spdif2, CS42L43_SPDIF2_INPUT1);
+
+CS42L43_DECL_MIXER(eq1, CS42L43_EQ1MIX_INPUT1);
+CS42L43_DECL_MIXER(eq2, CS42L43_EQ2MIX_INPUT1);
+
+CS42L43_DECL_MIXER(amp1, CS42L43_AMP1MIX_INPUT1);
+CS42L43_DECL_MIXER(amp2, CS42L43_AMP2MIX_INPUT1);
+
+CS42L43_DECL_MIXER(amp3, CS42L43_AMP3MIX_INPUT1);
+CS42L43_DECL_MIXER(amp4, CS42L43_AMP4MIX_INPUT1);
+
+static int cs42l43_dapm_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_dapm_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_dapm_get_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_get_enum_double(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_dapm_put_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ int ret;
+
+ snd_soc_dapm_mutex_lock(dapm);
+ ret = snd_soc_put_enum_double(kcontrol, ucontrol);
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return ret;
+}
+
+static int cs42l43_eq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ memcpy(ucontrol->value.integer.value, priv->eq_coeffs, sizeof(priv->eq_coeffs));
+
+ return 0;
+}
+
+static int cs42l43_eq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ snd_soc_dapm_mutex_lock(dapm);
+
+ memcpy(priv->eq_coeffs, ucontrol->value.integer.value, sizeof(priv->eq_coeffs));
+
+ snd_soc_dapm_mutex_unlock(dapm);
+
+ return 0;
+}
+
+static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ mutex_lock(&priv->spk_vu_lock);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
+ CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK);
+ regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
+ CS42L43_AMP1_2_VU_MASK, 0);
+
+ mutex_unlock(&priv->spk_vu_lock);
+}
+
+static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->dev);
+ if (ret) {
+ dev_err(priv->dev, "Failed to resume for shutters: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * SHUTTER_CONTROL is a mix of volatile and non-volatile bits, so must
+ * be cached for the non-volatiles, so drop it from the cache here so
+ * we force a read.
+ */
+ ret = regcache_drop_region(cs42l43->regmap, CS42L43_SHUTTER_CONTROL,
+ CS42L43_SHUTTER_CONTROL);
+ if (ret) {
+ dev_err(priv->dev, "Failed to drop shutter from cache: %d\n", ret);
+ goto error;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to check shutter status: %d\n", ret);
+ goto error;
+ }
+
+ ret = !(val & BIT(shift));
+
+ dev_dbg(priv->dev, "%s shutter is %s\n",
+ BIT(shift) == CS42L43_STATUS_MIC_SHUTTER_MUTE_MASK ? "Mic" : "Speaker",
+ ret ? "open" : "closed");
+
+error:
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return ret;
+}
+
+static int cs42l43_decim_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = cs42l43_shutter_get(priv, CS42L43_STATUS_MIC_SHUTTER_MUTE_SHIFT);
+ if (ret < 0)
+ return ret;
+ else if (!ret)
+ ucontrol->value.integer.value[0] = ret;
+ else
+ ret = cs42l43_dapm_get_volsw(kcontrol, ucontrol);
+
+ return ret;
+}
+
+static int cs42l43_spk_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = cs42l43_shutter_get(priv, CS42L43_STATUS_SPK_SHUTTER_MUTE_SHIFT);
+ if (ret < 0)
+ return ret;
+ else if (!ret)
+ ucontrol->value.integer.value[0] = ret;
+ else
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
+
+ return ret;
+}
+
+static int cs42l43_spk_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret > 0)
+ cs42l43_spk_vu_sync(priv);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new cs42l43_controls[] = {
+ SOC_ENUM_EXT("Jack Override", cs42l43_jack_enum,
+ cs42l43_jack_get, cs42l43_jack_put),
+
+ SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2,
+ CS42L43_ADC_PGA_GAIN_SHIFT,
+ 0xF, 5, cs42l43_adc_tlv),
+
+ SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL,
+ CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0),
+ SOC_DOUBLE("PDM2 Invert Switch", CS42L43_DMIC_PDM_CTRL,
+ CS42L43_PDM2L_INV_SHIFT, CS42L43_PDM2R_INV_SHIFT, 1, 0),
+ SOC_ENUM("PDM1 Clock", cs42l43_pdm1_clk),
+ SOC_ENUM("PDM2 Clock", cs42l43_pdm2_clk),
+
+ SOC_SINGLE("Decimator 1 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 2 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 3 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 4 WNF Switch", CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_WNF_EN_SHIFT, 1, 0),
+
+ SOC_ENUM("Decimator 1 WNF Corner Frequency", cs42l43_dec1_wnf_corner),
+ SOC_ENUM("Decimator 2 WNF Corner Frequency", cs42l43_dec2_wnf_corner),
+ SOC_ENUM("Decimator 3 WNF Corner Frequency", cs42l43_dec3_wnf_corner),
+ SOC_ENUM("Decimator 4 WNF Corner Frequency", cs42l43_dec4_wnf_corner),
+
+ SOC_SINGLE("Decimator 1 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL1,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 2 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL2,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 3 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL3,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Decimator 4 HPF Switch", CS42L43_DECIM_HPF_WNF_CTRL4,
+ CS42L43_DECIM_HPF_EN_SHIFT, 1, 0),
+
+ SOC_ENUM("Decimator 1 HPF Corner Frequency", cs42l43_dec1_hpf_corner),
+ SOC_ENUM("Decimator 2 HPF Corner Frequency", cs42l43_dec2_hpf_corner),
+ SOC_ENUM("Decimator 3 HPF Corner Frequency", cs42l43_dec3_hpf_corner),
+ SOC_ENUM("Decimator 4 HPF Corner Frequency", cs42l43_dec4_hpf_corner),
+
+ SOC_SINGLE_TLV("Decimator 1 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 1 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM1_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 2 Volume", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 2 Switch", CS42L43_DECIM_VOL_CTRL_CH1_CH2,
+ CS42L43_DECIM2_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 3 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 3 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM3_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+ SOC_SINGLE_TLV("Decimator 4 Volume", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_VOL_SHIFT, 0xBF, 0, cs42l43_dec_tlv),
+ SOC_SINGLE_EXT("Decimator 4 Switch", CS42L43_DECIM_VOL_CTRL_CH3_CH4,
+ CS42L43_DECIM4_MUTE_SHIFT, 1, 1,
+ cs42l43_decim_get, cs42l43_dapm_put_volsw),
+
+ SOC_ENUM_EXT("Decimator 1 Ramp Up", cs42l43_dec1_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 1 Ramp Down", cs42l43_dec1_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Up", cs42l43_dec2_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 2 Ramp Down", cs42l43_dec2_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Up", cs42l43_dec3_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 3 Ramp Down", cs42l43_dec3_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Up", cs42l43_dec4_ramp_up,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+ SOC_ENUM_EXT("Decimator 4 Ramp Down", cs42l43_dec4_ramp_down,
+ cs42l43_dapm_get_enum, cs42l43_dapm_put_enum),
+
+ SOC_DOUBLE_R_EXT("Speaker Digital Switch",
+ CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
+ CS42L43_AMP_MUTE_SHIFT, 1, 1,
+ cs42l43_spk_get, cs42l43_spk_put),
+
+ SOC_DOUBLE_R_EXT_TLV("Speaker Digital Volume",
+ CS42L43_INTP_VOLUME_CTRL1, CS42L43_INTP_VOLUME_CTRL2,
+ CS42L43_AMP_VOL_SHIFT,
+ 0xBF, 0, snd_soc_get_volsw, cs42l43_spk_put,
+ cs42l43_speaker_tlv),
+
+ SOC_ENUM("Speaker Ramp Up", cs42l43_speaker_ramp_up),
+ SOC_ENUM("Speaker Ramp Down", cs42l43_speaker_ramp_down),
+
+ CS42L43_MIXER_VOLUMES("Speaker L", CS42L43_AMP1MIX_INPUT1),
+ CS42L43_MIXER_VOLUMES("Speaker R", CS42L43_AMP2MIX_INPUT1),
+
+ SOC_DOUBLE_SX_TLV("Headphone Digital Volume", CS42L43_HPPATHVOL,
+ CS42L43_AMP3_PATH_VOL_SHIFT, CS42L43_AMP4_PATH_VOL_SHIFT,
+ 0x11B, 229, cs42l43_headphone_tlv),
+
+ SOC_DOUBLE("Headphone Invert Switch", CS42L43_DACCNFG1,
+ CS42L43_AMP3_INV_SHIFT, CS42L43_AMP4_INV_SHIFT, 1, 0),
+
+ SOC_SINGLE("Headphone Zero Cross Switch", CS42L43_PGAVOL,
+ CS42L43_HP_PATH_VOL_ZC_SHIFT, 1, 0),
+ SOC_SINGLE("Headphone Ramp Switch", CS42L43_PGAVOL,
+ CS42L43_HP_PATH_VOL_SFT_SHIFT, 1, 0),
+ SOC_ENUM("Headphone Ramp Rate", cs42l43_headphone_ramp),
+
+ CS42L43_MIXER_VOLUMES("Headphone L", CS42L43_AMP3MIX_INPUT1),
+ CS42L43_MIXER_VOLUMES("Headphone R", CS42L43_AMP4MIX_INPUT1),
+
+ SOC_ENUM("Tone 1 Frequency", cs42l43_tone1_freq),
+ SOC_ENUM("Tone 2 Frequency", cs42l43_tone2_freq),
+
+ SOC_DOUBLE_EXT("EQ Switch",
+ CS42L43_MUTE_EQ_IN0, CS42L43_MUTE_EQ_CH1_SHIFT,
+ CS42L43_MUTE_EQ_CH2_SHIFT, 1, 1,
+ cs42l43_dapm_get_volsw, cs42l43_dapm_put_volsw),
+
+ SND_SOC_BYTES_E("EQ Coefficients", 0, CS42L43_N_EQ_COEFFS,
+ cs42l43_eq_get, cs42l43_eq_put),
+
+ CS42L43_MIXER_VOLUMES("EQ1", CS42L43_EQ1MIX_INPUT1),
+ CS42L43_MIXER_VOLUMES("EQ2", CS42L43_EQ2MIX_INPUT1),
+};
+
+static int cs42l43_eq_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int val;
+ int i, ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0,
+ CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK,
+ CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0,
+ CS42L43_WRITE_MODE_MASK, CS42L43_WRITE_MODE_MASK);
+
+ for (i = 0; i < CS42L43_N_EQ_COEFFS; i++)
+ regmap_write(cs42l43->regmap, CS42L43_COEFF_DATA_IN0,
+ priv->eq_coeffs[i]);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_COEFF_RD_WR0,
+ CS42L43_WRITE_MODE_MASK, 0);
+
+ return 0;
+ case SND_SOC_DAPM_POST_PMU:
+ ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_INIT_DONE0,
+ val, (val & CS42L43_INITIALIZE_DONE_MASK),
+ 2000, 10000);
+ if (ret)
+ dev_err(priv->dev, "Failed to start EQs: %d\n", ret);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_MUTE_EQ_IN0,
+ CS42L43_MUTE_EQ_CH1_MASK | CS42L43_MUTE_EQ_CH2_MASK, 0);
+ return ret;
+ default:
+ return 0;
+ }
+}
+
+struct cs42l43_pll_config {
+ unsigned int freq;
+
+ unsigned int div;
+ unsigned int mode;
+ unsigned int cal;
+};
+
+static const struct cs42l43_pll_config cs42l43_pll_configs[] = {
+ { 2400000, 0x50000000, 0x1, 0xA4 },
+ { 3000000, 0x40000000, 0x1, 0x83 },
+ { 3072000, 0x40000000, 0x3, 0x80 },
+};
+
+static int cs42l43_set_pll(struct cs42l43_codec *priv, unsigned int src,
+ unsigned int freq)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ lockdep_assert_held(&cs42l43->pll_lock);
+
+ if (priv->refclk_src == src && priv->refclk_freq == freq)
+ return 0;
+
+ if (regmap_test_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK)) {
+ dev_err(priv->dev, "PLL active, can't change configuration\n");
+ return -EBUSY;
+ }
+
+ switch (src) {
+ case CS42L43_SYSCLK_MCLK:
+ case CS42L43_SYSCLK_SDW:
+ dev_dbg(priv->dev, "Source PLL from %s at %uHz\n",
+ src ? "SoundWire" : "MCLK", freq);
+
+ priv->refclk_src = src;
+ priv->refclk_freq = freq;
+
+ return 0;
+ default:
+ dev_err(priv->dev, "Invalid PLL source: 0x%x\n", src);
+ return -EINVAL;
+ }
+}
+
+static int cs42l43_enable_pll(struct cs42l43_codec *priv)
+{
+ static const struct reg_sequence enable_seq[] = {
+ { CS42L43_OSC_DIV_SEL, 0x0, },
+ { CS42L43_MCLK_SRC_SEL, CS42L43_OSC_PLL_MCLK_SEL_MASK, 5, },
+ };
+ struct cs42l43 *cs42l43 = priv->core;
+ const struct cs42l43_pll_config *config = NULL;
+ unsigned int div = 0;
+ unsigned int freq = priv->refclk_freq;
+ unsigned long time_left;
+
+ lockdep_assert_held(&cs42l43->pll_lock);
+
+ if (priv->refclk_src == CS42L43_SYSCLK_SDW) {
+ if (!freq)
+ freq = cs42l43->sdw_freq;
+ else if (!cs42l43->sdw_freq)
+ cs42l43->sdw_freq = freq;
+ }
+
+ dev_dbg(priv->dev, "Enabling PLL at %uHz\n", freq);
+
+ while (freq > cs42l43_pll_configs[ARRAY_SIZE(cs42l43_pll_configs) - 1].freq) {
+ div++;
+ freq /= 2;
+ }
+
+ if (div <= CS42L43_PLL_REFCLK_DIV_MASK) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_pll_configs); i++) {
+ if (freq == cs42l43_pll_configs[i].freq) {
+ config = &cs42l43_pll_configs[i];
+ break;
+ }
+ }
+ }
+
+ if (!config) {
+ dev_err(priv->dev, "No suitable PLL config: 0x%x, %uHz\n", div, freq);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_DIV_MASK | CS42L43_PLL_REFCLK_SRC_MASK,
+ div << CS42L43_PLL_REFCLK_DIV_SHIFT |
+ priv->refclk_src << CS42L43_PLL_REFCLK_SRC_SHIFT);
+ regmap_write(cs42l43->regmap, CS42L43_FDIV_FRAC, config->div);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
+ CS42L43_PLL_MODE_BYPASS_500_MASK |
+ CS42L43_PLL_MODE_BYPASS_1029_MASK,
+ config->mode << CS42L43_PLL_MODE_BYPASS_1029_SHIFT);
+ regmap_update_bits(cs42l43->regmap, CS42L43_CAL_RATIO,
+ CS42L43_PLL_CAL_RATIO_MASK, config->cal);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_EN_MASK, CS42L43_PLL_REFCLK_EN_MASK);
+
+ reinit_completion(&priv->pll_ready);
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
+ CS42L43_PLL_EN_MASK, CS42L43_PLL_EN_MASK);
+
+ time_left = wait_for_completion_timeout(&priv->pll_ready,
+ msecs_to_jiffies(CS42L43_PLL_TIMEOUT_MS));
+ if (!time_left) {
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG,
+ CS42L43_PLL_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_EN_MASK, 0);
+
+ dev_err(priv->dev, "Timeout out waiting for PLL\n");
+ return -ETIMEDOUT;
+ }
+
+ if (priv->refclk_src == CS42L43_SYSCLK_SDW)
+ cs42l43->sdw_pll_active = true;
+
+ dev_dbg(priv->dev, "PLL locked in %ums\n", 200 - jiffies_to_msecs(time_left));
+
+ /*
+ * Reads are not allowed over Soundwire without OSC_DIV2_EN or the PLL,
+ * but you can not change to PLL with OSC_DIV2_EN set. So ensure the whole
+ * change over happens under the regmap lock to prevent any reads.
+ */
+ regmap_multi_reg_write(cs42l43->regmap, enable_seq, ARRAY_SIZE(enable_seq));
+
+ return 0;
+}
+
+static int cs42l43_disable_pll(struct cs42l43_codec *priv)
+{
+ static const struct reg_sequence disable_seq[] = {
+ { CS42L43_MCLK_SRC_SEL, 0x0, 5, },
+ { CS42L43_OSC_DIV_SEL, CS42L43_OSC_DIV2_EN_MASK, },
+ };
+ struct cs42l43 *cs42l43 = priv->core;
+
+ dev_dbg(priv->dev, "Disabling PLL\n");
+
+ lockdep_assert_held(&cs42l43->pll_lock);
+
+ regmap_multi_reg_write(cs42l43->regmap, disable_seq, ARRAY_SIZE(disable_seq));
+ regmap_update_bits(cs42l43->regmap, CS42L43_CTRL_REG, CS42L43_PLL_EN_MASK, 0);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PLL_CONTROL,
+ CS42L43_PLL_REFCLK_EN_MASK, 0);
+
+ cs42l43->sdw_pll_active = false;
+
+ return 0;
+}
+
+static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ mutex_lock(&cs42l43->pll_lock);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (priv->refclk_src == CS42L43_SYSCLK_MCLK) {
+ ret = clk_prepare_enable(priv->mclk);
+ if (ret) {
+ dev_err(priv->dev, "Failed to enable MCLK: %d\n", ret);
+ break;
+ }
+ }
+
+ ret = cs42l43_enable_pll(priv);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = cs42l43_disable_pll(priv);
+
+ if (priv->refclk_src == CS42L43_SYSCLK_MCLK)
+ clk_disable_unprepare(priv->mclk);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ mutex_unlock(&cs42l43->pll_lock);
+
+ return ret;
+}
+
+static int cs42l43_dapm_wait_completion(struct completion *pmu, struct completion *pmd,
+ int event, int timeout_ms)
+{
+ unsigned long time_left;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ reinit_completion(pmu);
+ return 0;
+ case SND_SOC_DAPM_PRE_PMD:
+ reinit_completion(pmd);
+ return 0;
+ case SND_SOC_DAPM_POST_PMU:
+ time_left = wait_for_completion_timeout(pmu, msecs_to_jiffies(timeout_ms));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ time_left = wait_for_completion_timeout(pmd, msecs_to_jiffies(timeout_ms));
+ break;
+ default:
+ return 0;
+ }
+
+ if (!time_left)
+ return -ETIMEDOUT;
+ else
+ return 0;
+}
+
+static int cs42l43_spkr_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ return cs42l43_dapm_wait_completion(&priv->spkr_startup,
+ &priv->spkr_shutdown, event,
+ CS42L43_SPK_TIMEOUT_MS);
+}
+
+static int cs42l43_spkl_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+
+ return cs42l43_dapm_wait_completion(&priv->spkl_startup,
+ &priv->spkl_shutdown, event,
+ CS42L43_SPK_TIMEOUT_MS);
+}
+
+static int cs42l43_hp_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int mask = 1 << w->shift;
+ unsigned int val = 0;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ val = mask;
+ fallthrough;
+ case SND_SOC_DAPM_PRE_PMD:
+ priv->hp_ena &= ~mask;
+ priv->hp_ena |= val;
+
+ ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
+ &priv->hp_shutdown, event,
+ CS42L43_HP_TIMEOUT_MS);
+ if (ret)
+ return ret;
+
+ if (!priv->load_detect_running)
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN8,
+ mask, val);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ if (priv->load_detect_running)
+ break;
+
+ ret = cs42l43_dapm_wait_completion(&priv->hp_startup,
+ &priv->hp_shutdown, event,
+ CS42L43_HP_TIMEOUT_MS);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l43_mic_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int reg, ramp, mute;
+ unsigned int *val;
+ int ret;
+
+ switch (w->shift) {
+ case CS42L43_ADC1_EN_SHIFT:
+ case CS42L43_PDM1_DIN_L_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM1_VD_RAMP_MASK;
+ mute = CS42L43_DECIM1_MUTE_MASK;
+ val = &priv->decim_cache[0];
+ break;
+ case CS42L43_ADC2_EN_SHIFT:
+ case CS42L43_PDM1_DIN_R_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH1_CH2;
+ ramp = CS42L43_DECIM2_VD_RAMP_MASK;
+ mute = CS42L43_DECIM2_MUTE_MASK;
+ val = &priv->decim_cache[1];
+ break;
+ case CS42L43_PDM2_DIN_L_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM3_VD_RAMP_MASK;
+ mute = CS42L43_DECIM3_MUTE_MASK;
+ val = &priv->decim_cache[2];
+ break;
+ case CS42L43_PDM2_DIN_R_EN_SHIFT:
+ reg = CS42L43_DECIM_VOL_CTRL_CH3_CH4;
+ ramp = CS42L43_DECIM4_VD_RAMP_MASK;
+ mute = CS42L43_DECIM4_MUTE_MASK;
+ val = &priv->decim_cache[3];
+ break;
+ default:
+ dev_err(priv->dev, "Invalid microphone shift: %d\n", w->shift);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = regmap_read(cs42l43->regmap, reg, val);
+ if (ret) {
+ dev_err(priv->dev,
+ "Failed to cache decimator settings: %d\n",
+ ret);
+ return ret;
+ }
+
+ regmap_update_bits(cs42l43->regmap, reg, mute | ramp, mute);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(cs42l43->regmap, reg, mute | ramp, *val);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cs42l43_adc_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ unsigned int mask = 1 << w->shift;
+ unsigned int val = 0;
+ int ret;
+
+ ret = cs42l43_mic_ev(w, kcontrol, event);
+ if (ret)
+ return ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ val = mask;
+ fallthrough;
+ case SND_SOC_DAPM_PRE_PMD:
+ priv->adc_ena &= ~mask;
+ priv->adc_ena |= val;
+
+ if (!priv->load_detect_running)
+ regmap_update_bits(cs42l43->regmap, CS42L43_BLOCK_EN3,
+ mask, val);
+ fallthrough;
+ default:
+ return 0;
+ }
+}
+
+static const struct snd_soc_dapm_widget cs42l43_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, cs42l43_pll_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("ADC1_IN1_P"),
+ SND_SOC_DAPM_INPUT("ADC1_IN1_N"),
+ SND_SOC_DAPM_INPUT("ADC1_IN2_P"),
+ SND_SOC_DAPM_INPUT("ADC1_IN2_N"),
+ SND_SOC_DAPM_INPUT("ADC2_IN_P"),
+ SND_SOC_DAPM_INPUT("ADC2_IN_N"),
+
+ SND_SOC_DAPM_INPUT("PDM1_DIN"),
+ SND_SOC_DAPM_INPUT("PDM2_DIN"),
+
+ SND_SOC_DAPM_MUX("ADC1 Input", SND_SOC_NOPM, 0, 0, &cs42l43_adc1_input_ctl),
+
+ SND_SOC_DAPM_PGA_E("ADC1", SND_SOC_NOPM, CS42L43_ADC1_EN_SHIFT, 0, NULL, 0,
+ cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("ADC2", SND_SOC_NOPM, CS42L43_ADC2_EN_SHIFT, 0, NULL, 0,
+ cs42l43_adc_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA_E("PDM1L", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_L_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("PDM1R", CS42L43_BLOCK_EN3, CS42L43_PDM1_DIN_R_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("PDM2L", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_L_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("PDM2R", CS42L43_BLOCK_EN3, CS42L43_PDM2_DIN_R_EN_SHIFT,
+ 0, NULL, 0, cs42l43_mic_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MUX("Decimator 1 Mode", SND_SOC_NOPM, 0, 0,
+ &cs42l43_dec_mode_ctl[0]),
+ SND_SOC_DAPM_MUX("Decimator 2 Mode", SND_SOC_NOPM, 0, 0,
+ &cs42l43_dec_mode_ctl[1]),
+
+ SND_SOC_DAPM_PGA("Decimator 1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Decimator 4", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("FSYNC", 0, CS42L43_ASP_CTRL, CS42L43_ASP_FSYNC_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("BCLK", 1, CS42L43_ASP_CTRL, CS42L43_ASP_BCLK_EN_SHIFT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH1_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 1,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH2_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 2,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH3_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 3,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH4_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX5", NULL, 4,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH5_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_OUT("ASPTX6", NULL, 5,
+ CS42L43_ASP_TX_EN, CS42L43_ASP_TX_CH6_EN_SHIFT, 0),
+
+ SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH1_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 1,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH2_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX3", NULL, 2,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH3_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX4", NULL, 3,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH4_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX5", NULL, 4,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH5_EN_SHIFT, 0),
+ SND_SOC_DAPM_AIF_IN("ASPRX6", NULL, 5,
+ CS42L43_ASP_RX_EN, CS42L43_ASP_RX_CH6_EN_SHIFT, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP1TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP1TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP1TX3", NULL, 2, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP1TX4", NULL, 3, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP2TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP2TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP3TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP3TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_OUT("DP4TX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP4TX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("DP5RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP5RX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("DP6RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP6RX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("DP7RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DP7RX2", NULL, 1, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-amp", 0, 0),
+
+ SND_SOC_DAPM_PGA_E("AMP1", CS42L43_BLOCK_EN10, CS42L43_AMP1_EN_SHIFT, 0, NULL, 0,
+ cs42l43_spkl_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("AMP2", CS42L43_BLOCK_EN10, CS42L43_AMP2_EN_SHIFT, 0, NULL, 0,
+ cs42l43_spkr_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_OUTPUT("AMP1_OUT_P"),
+ SND_SOC_DAPM_OUTPUT("AMP1_OUT_N"),
+ SND_SOC_DAPM_OUTPUT("AMP2_OUT_P"),
+ SND_SOC_DAPM_OUTPUT("AMP2_OUT_N"),
+
+ SND_SOC_DAPM_PGA("SPDIF", CS42L43_BLOCK_EN11, CS42L43_SPDIF_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("SPDIF_TX"),
+
+ SND_SOC_DAPM_PGA_E("HP", SND_SOC_NOPM, CS42L43_HP_EN_SHIFT, 0, NULL, 0,
+ cs42l43_hp_ev, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("AMP3_OUT"),
+ SND_SOC_DAPM_OUTPUT("AMP4_OUT"),
+
+ SND_SOC_DAPM_SIGGEN("Tone"),
+ SND_SOC_DAPM_SUPPLY("Tone Generator", CS42L43_BLOCK_EN9, CS42L43_TONE_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 1", CS42L43_TONE_CH1_CTRL,
+ CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Tone 2", CS42L43_TONE_CH2_CTRL,
+ CS42L43_TONE_SEL_SHIFT, CS42L43_TONE_SEL_MASK, 0xA, 0),
+
+ SND_SOC_DAPM_SUPPLY("ISRC1", CS42L43_BLOCK_EN5, CS42L43_ISRC1_BANK_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ISRC2", CS42L43_BLOCK_EN5, CS42L43_ISRC2_BANK_EN_SHIFT,
+ 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ISRC1INT2", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1INT1", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1DEC2", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC1DEC1", CS42L43_ISRC1_CTRL,
+ CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ISRC2INT2", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_INT2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2INT1", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_INT1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2DEC2", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_DEC2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ISRC2DEC1", CS42L43_ISRC2_CTRL,
+ CS42L43_ISRC_DEC1_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("ASRC_INT", CS42L43_BLOCK_EN4,
+ CS42L43_ASRC_INT_BANK_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASRC_DEC", CS42L43_BLOCK_EN4,
+ CS42L43_ASRC_DEC_BANK_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("ASRC_INT1", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_INT2", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_INT3", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT3_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_INT4", CS42L43_ASRC_INT_ENABLES,
+ CS42L43_ASRC_INT4_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC1", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC1_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC2", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC2_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC3", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC3_EN_SHIFT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASRC_DEC4", CS42L43_ASRC_DEC_ENABLES,
+ CS42L43_ASRC_DEC4_EN_SHIFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("EQ Clock", CS42L43_BLOCK_EN7, CS42L43_EQ_EN_SHIFT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("EQ", CS42L43_START_EQZ0, CS42L43_START_FILTER_SHIFT,
+ 0, NULL, 0, cs42l43_eq_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY("Mixer Core", CS42L43_BLOCK_EN6, CS42L43_MIXER_EN_SHIFT,
+ 0, NULL, 0),
+ CS42L43_DAPM_MUX("ASPTX1", asptx1),
+ CS42L43_DAPM_MUX("ASPTX2", asptx2),
+ CS42L43_DAPM_MUX("ASPTX3", asptx3),
+ CS42L43_DAPM_MUX("ASPTX4", asptx4),
+ CS42L43_DAPM_MUX("ASPTX5", asptx5),
+ CS42L43_DAPM_MUX("ASPTX6", asptx6),
+
+ CS42L43_DAPM_MUX("DP1TX1", dp1tx1),
+ CS42L43_DAPM_MUX("DP1TX2", dp1tx2),
+ CS42L43_DAPM_MUX("DP1TX3", dp1tx3),
+ CS42L43_DAPM_MUX("DP1TX4", dp1tx4),
+ CS42L43_DAPM_MUX("DP2TX1", dp2tx1),
+ CS42L43_DAPM_MUX("DP2TX2", dp2tx2),
+ CS42L43_DAPM_MUX("DP3TX1", dp3tx1),
+ CS42L43_DAPM_MUX("DP3TX2", dp3tx2),
+ CS42L43_DAPM_MUX("DP4TX1", dp4tx1),
+ CS42L43_DAPM_MUX("DP4TX2", dp4tx2),
+
+ CS42L43_DAPM_MUX("ASRC INT1", asrcint1),
+ CS42L43_DAPM_MUX("ASRC INT2", asrcint2),
+ CS42L43_DAPM_MUX("ASRC INT3", asrcint3),
+ CS42L43_DAPM_MUX("ASRC INT4", asrcint4),
+ CS42L43_DAPM_MUX("ASRC DEC1", asrcdec1),
+ CS42L43_DAPM_MUX("ASRC DEC2", asrcdec2),
+ CS42L43_DAPM_MUX("ASRC DEC3", asrcdec3),
+ CS42L43_DAPM_MUX("ASRC DEC4", asrcdec4),
+
+ CS42L43_DAPM_MUX("ISRC1INT1", isrc1int1),
+ CS42L43_DAPM_MUX("ISRC1INT2", isrc1int2),
+ CS42L43_DAPM_MUX("ISRC1DEC1", isrc1dec1),
+ CS42L43_DAPM_MUX("ISRC1DEC2", isrc1dec2),
+ CS42L43_DAPM_MUX("ISRC2INT1", isrc2int1),
+ CS42L43_DAPM_MUX("ISRC2INT2", isrc2int2),
+ CS42L43_DAPM_MUX("ISRC2DEC1", isrc2dec1),
+ CS42L43_DAPM_MUX("ISRC2DEC2", isrc2dec2),
+
+ CS42L43_DAPM_MUX("SPDIF1", spdif1),
+ CS42L43_DAPM_MUX("SPDIF2", spdif2),
+
+ CS42L43_DAPM_MIXER("EQ1", eq1),
+ CS42L43_DAPM_MIXER("EQ2", eq2),
+
+ CS42L43_DAPM_MIXER("Speaker L", amp1),
+ CS42L43_DAPM_MIXER("Speaker R", amp2),
+
+ CS42L43_DAPM_MIXER("Headphone L", amp3),
+ CS42L43_DAPM_MIXER("Headphone R", amp4),
+};
+
+static const struct snd_soc_dapm_route cs42l43_routes[] = {
+ { "ADC1_IN1_P", NULL, "PLL" },
+ { "ADC1_IN1_N", NULL, "PLL" },
+ { "ADC1_IN2_P", NULL, "PLL" },
+ { "ADC1_IN2_N", NULL, "PLL" },
+ { "ADC2_IN_P", NULL, "PLL" },
+ { "ADC2_IN_N", NULL, "PLL" },
+ { "PDM1_DIN", NULL, "PLL" },
+ { "PDM2_DIN", NULL, "PLL" },
+ { "AMP1_OUT_P", NULL, "PLL" },
+ { "AMP1_OUT_N", NULL, "PLL" },
+ { "AMP2_OUT_P", NULL, "PLL" },
+ { "AMP2_OUT_N", NULL, "PLL" },
+ { "SPDIF_TX", NULL, "PLL" },
+ { "HP", NULL, "PLL" },
+ { "AMP3_OUT", NULL, "PLL" },
+ { "AMP4_OUT", NULL, "PLL" },
+ { "Tone 1", NULL, "PLL" },
+ { "Tone 2", NULL, "PLL" },
+ { "ASP Playback", NULL, "PLL" },
+ { "ASP Capture", NULL, "PLL" },
+ { "DP1 Capture", NULL, "PLL" },
+ { "DP2 Capture", NULL, "PLL" },
+ { "DP3 Capture", NULL, "PLL" },
+ { "DP4 Capture", NULL, "PLL" },
+ { "DP5 Playback", NULL, "PLL" },
+ { "DP6 Playback", NULL, "PLL" },
+ { "DP7 Playback", NULL, "PLL" },
+
+ { "ADC1 Input", "IN1", "ADC1_IN1_P" },
+ { "ADC1 Input", "IN1", "ADC1_IN1_N" },
+ { "ADC1 Input", "IN2", "ADC1_IN2_P" },
+ { "ADC1 Input", "IN2", "ADC1_IN2_N" },
+
+ { "ADC1", NULL, "ADC1 Input" },
+ { "ADC2", NULL, "ADC2_IN_P" },
+ { "ADC2", NULL, "ADC2_IN_N" },
+
+ { "PDM1L", NULL, "PDM1_DIN" },
+ { "PDM1R", NULL, "PDM1_DIN" },
+ { "PDM2L", NULL, "PDM2_DIN" },
+ { "PDM2R", NULL, "PDM2_DIN" },
+
+ { "Decimator 1 Mode", "PDM", "PDM1L" },
+ { "Decimator 1 Mode", "ADC", "ADC1" },
+ { "Decimator 2 Mode", "PDM", "PDM1R" },
+ { "Decimator 2 Mode", "ADC", "ADC2" },
+
+ { "Decimator 1", NULL, "Decimator 1 Mode" },
+ { "Decimator 2", NULL, "Decimator 2 Mode" },
+ { "Decimator 3", NULL, "PDM2L" },
+ { "Decimator 4", NULL, "PDM2R" },
+
+ { "ASP Capture", NULL, "ASPTX1" },
+ { "ASP Capture", NULL, "ASPTX2" },
+ { "ASP Capture", NULL, "ASPTX3" },
+ { "ASP Capture", NULL, "ASPTX4" },
+ { "ASP Capture", NULL, "ASPTX5" },
+ { "ASP Capture", NULL, "ASPTX6" },
+ { "ASPTX1", NULL, "BCLK" },
+ { "ASPTX2", NULL, "BCLK" },
+ { "ASPTX3", NULL, "BCLK" },
+ { "ASPTX4", NULL, "BCLK" },
+ { "ASPTX5", NULL, "BCLK" },
+ { "ASPTX6", NULL, "BCLK" },
+
+ { "ASPRX1", NULL, "ASP Playback" },
+ { "ASPRX2", NULL, "ASP Playback" },
+ { "ASPRX3", NULL, "ASP Playback" },
+ { "ASPRX4", NULL, "ASP Playback" },
+ { "ASPRX5", NULL, "ASP Playback" },
+ { "ASPRX6", NULL, "ASP Playback" },
+ { "ASPRX1", NULL, "BCLK" },
+ { "ASPRX2", NULL, "BCLK" },
+ { "ASPRX3", NULL, "BCLK" },
+ { "ASPRX4", NULL, "BCLK" },
+ { "ASPRX5", NULL, "BCLK" },
+ { "ASPRX6", NULL, "BCLK" },
+
+ { "DP1 Capture", NULL, "DP1TX1" },
+ { "DP1 Capture", NULL, "DP1TX2" },
+ { "DP1 Capture", NULL, "DP1TX3" },
+ { "DP1 Capture", NULL, "DP1TX4" },
+
+ { "DP2 Capture", NULL, "DP2TX1" },
+ { "DP2 Capture", NULL, "DP2TX2" },
+
+ { "DP3 Capture", NULL, "DP3TX1" },
+ { "DP3 Capture", NULL, "DP3TX2" },
+
+ { "DP4 Capture", NULL, "DP4TX1" },
+ { "DP4 Capture", NULL, "DP4TX2" },
+
+ { "DP5RX1", NULL, "DP5 Playback" },
+ { "DP5RX2", NULL, "DP5 Playback" },
+
+ { "DP6RX1", NULL, "DP6 Playback" },
+ { "DP6RX2", NULL, "DP6 Playback" },
+
+ { "DP7RX1", NULL, "DP7 Playback" },
+ { "DP7RX2", NULL, "DP7 Playback" },
+
+ { "AMP1", NULL, "vdd-amp" },
+ { "AMP2", NULL, "vdd-amp" },
+
+ { "AMP1_OUT_P", NULL, "AMP1" },
+ { "AMP1_OUT_N", NULL, "AMP1" },
+ { "AMP2_OUT_P", NULL, "AMP2" },
+ { "AMP2_OUT_N", NULL, "AMP2" },
+
+ { "SPDIF_TX", NULL, "SPDIF" },
+
+ { "AMP3_OUT", NULL, "HP" },
+ { "AMP4_OUT", NULL, "HP" },
+
+ { "Tone 1", NULL, "Tone" },
+ { "Tone 1", NULL, "Tone Generator" },
+ { "Tone 2", NULL, "Tone" },
+ { "Tone 2", NULL, "Tone Generator" },
+
+ { "ISRC1INT2", NULL, "ISRC1" },
+ { "ISRC1INT1", NULL, "ISRC1" },
+ { "ISRC1DEC2", NULL, "ISRC1" },
+ { "ISRC1DEC1", NULL, "ISRC1" },
+
+ { "ISRC2INT2", NULL, "ISRC2" },
+ { "ISRC2INT1", NULL, "ISRC2" },
+ { "ISRC2DEC2", NULL, "ISRC2" },
+ { "ISRC2DEC1", NULL, "ISRC2" },
+
+ { "ASRC_INT1", NULL, "ASRC_INT" },
+ { "ASRC_INT2", NULL, "ASRC_INT" },
+ { "ASRC_INT3", NULL, "ASRC_INT" },
+ { "ASRC_INT4", NULL, "ASRC_INT" },
+ { "ASRC_DEC1", NULL, "ASRC_DEC" },
+ { "ASRC_DEC2", NULL, "ASRC_DEC" },
+ { "ASRC_DEC3", NULL, "ASRC_DEC" },
+ { "ASRC_DEC4", NULL, "ASRC_DEC" },
+
+ { "EQ", NULL, "EQ Clock" },
+
+ CS42L43_MUX_ROUTES("ASPTX1", "ASPTX1"),
+ CS42L43_MUX_ROUTES("ASPTX2", "ASPTX2"),
+ CS42L43_MUX_ROUTES("ASPTX3", "ASPTX3"),
+ CS42L43_MUX_ROUTES("ASPTX4", "ASPTX4"),
+ CS42L43_MUX_ROUTES("ASPTX5", "ASPTX5"),
+ CS42L43_MUX_ROUTES("ASPTX6", "ASPTX6"),
+
+ CS42L43_MUX_ROUTES("DP1TX1", "DP1TX1"),
+ CS42L43_MUX_ROUTES("DP1TX2", "DP1TX2"),
+ CS42L43_MUX_ROUTES("DP1TX3", "DP1TX3"),
+ CS42L43_MUX_ROUTES("DP1TX4", "DP1TX4"),
+ CS42L43_MUX_ROUTES("DP2TX1", "DP2TX1"),
+ CS42L43_MUX_ROUTES("DP2TX2", "DP2TX2"),
+ CS42L43_MUX_ROUTES("DP3TX1", "DP3TX1"),
+ CS42L43_MUX_ROUTES("DP3TX2", "DP3TX2"),
+ CS42L43_MUX_ROUTES("DP4TX1", "DP4TX1"),
+ CS42L43_MUX_ROUTES("DP4TX2", "DP4TX2"),
+
+ CS42L43_MUX_ROUTES("ASRC INT1", "ASRC_INT1"),
+ CS42L43_MUX_ROUTES("ASRC INT2", "ASRC_INT2"),
+ CS42L43_MUX_ROUTES("ASRC INT3", "ASRC_INT3"),
+ CS42L43_MUX_ROUTES("ASRC INT4", "ASRC_INT4"),
+ CS42L43_MUX_ROUTES("ASRC DEC1", "ASRC_DEC1"),
+ CS42L43_MUX_ROUTES("ASRC DEC2", "ASRC_DEC2"),
+ CS42L43_MUX_ROUTES("ASRC DEC3", "ASRC_DEC3"),
+ CS42L43_MUX_ROUTES("ASRC DEC4", "ASRC_DEC4"),
+
+ CS42L43_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+ CS42L43_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+ CS42L43_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+ CS42L43_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+ CS42L43_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+ CS42L43_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+ CS42L43_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+ CS42L43_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+ CS42L43_MUX_ROUTES("SPDIF1", "SPDIF"),
+ CS42L43_MUX_ROUTES("SPDIF2", "SPDIF"),
+
+ CS42L43_MIXER_ROUTES("EQ1", "EQ"),
+ CS42L43_MIXER_ROUTES("EQ2", "EQ"),
+
+ CS42L43_MIXER_ROUTES("Speaker L", "AMP1"),
+ CS42L43_MIXER_ROUTES("Speaker R", "AMP2"),
+
+ CS42L43_MIXER_ROUTES("Headphone L", "HP"),
+ CS42L43_MIXER_ROUTES("Headphone R", "HP"),
+};
+
+static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id,
+ int src, unsigned int freq, int dir)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+ int ret;
+
+ mutex_lock(&cs42l43->pll_lock);
+ ret = cs42l43_set_pll(priv, src, freq);
+ mutex_unlock(&cs42l43->pll_lock);
+
+ return ret;
+}
+
+static int cs42l43_component_probe(struct snd_soc_component *component)
+{
+ struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
+ struct cs42l43 *cs42l43 = priv->core;
+
+ snd_soc_component_init_regmap(component, cs42l43->regmap);
+
+ cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->tx_slots);
+ cs42l43_mask_to_slots(priv, CS42L43_DEFAULT_SLOTS, priv->rx_slots);
+
+ priv->component = component;
+ priv->constraint = cs42l43_constraint;
+
+ return 0;
+}
+
+static const struct snd_soc_component_driver cs42l43_component_drv = {
+ .name = "cs42l43-codec",
+
+ .probe = cs42l43_component_probe,
+ .set_sysclk = cs42l43_set_sysclk,
+ .set_jack = cs42l43_set_jack,
+
+ .endianness = 1,
+
+ .controls = cs42l43_controls,
+ .num_controls = ARRAY_SIZE(cs42l43_controls),
+ .dapm_widgets = cs42l43_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l43_widgets),
+ .dapm_routes = cs42l43_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs42l43_routes),
+};
+
+struct cs42l43_irq {
+ unsigned int irq;
+ const char *name;
+ irq_handler_t handler;
+};
+
+static const struct cs42l43_irq cs42l43_irqs[] = {
+ { CS42L43_PLL_LOST_LOCK, "pll lost lock", cs42l43_pll_lost_lock },
+ { CS42L43_PLL_READY, "pll ready", cs42l43_pll_ready },
+ { CS42L43_HP_STARTUP_DONE, "hp startup", cs42l43_hp_startup },
+ { CS42L43_HP_SHUTDOWN_DONE, "hp shutdown", cs42l43_hp_shutdown },
+ { CS42L43_HSDET_DONE, "type detect", cs42l43_type_detect },
+ { CS42L43_TIPSENSE_UNPLUG_PDET, "tip sense unplug", cs42l43_tip_sense },
+ { CS42L43_TIPSENSE_PLUG_PDET, "tip sense plug", cs42l43_tip_sense },
+ { CS42L43_DC_DETECT1_TRUE, "button press", cs42l43_button_press },
+ { CS42L43_DC_DETECT1_FALSE, "button release", cs42l43_button_release },
+ { CS42L43_HSBIAS_CLAMPED, "hsbias detect clamp", cs42l43_bias_detect_clamp },
+ { CS42L43_AMP2_CLK_STOP_FAULT, "spkr clock stop", cs42l43_spkr_clock_stop },
+ { CS42L43_AMP1_CLK_STOP_FAULT, "spkl clock stop", cs42l43_spkl_clock_stop },
+ { CS42L43_AMP2_VDDSPK_FAULT, "spkr brown out", cs42l43_spkr_brown_out },
+ { CS42L43_AMP1_VDDSPK_FAULT, "spkl brown out", cs42l43_spkl_brown_out },
+ { CS42L43_AMP2_SHUTDOWN_DONE, "spkr shutdown", cs42l43_spkr_shutdown },
+ { CS42L43_AMP1_SHUTDOWN_DONE, "spkl shutdown", cs42l43_spkl_shutdown },
+ { CS42L43_AMP2_STARTUP_DONE, "spkr startup", cs42l43_spkr_startup },
+ { CS42L43_AMP1_STARTUP_DONE, "spkl startup", cs42l43_spkl_startup },
+ { CS42L43_AMP2_THERM_SHDN, "spkr thermal shutdown", cs42l43_spkr_therm_shutdown },
+ { CS42L43_AMP1_THERM_SHDN, "spkl thermal shutdown", cs42l43_spkl_therm_shutdown },
+ { CS42L43_AMP2_THERM_WARN, "spkr thermal warning", cs42l43_spkr_therm_warm },
+ { CS42L43_AMP1_THERM_WARN, "spkl thermal warning", cs42l43_spkl_therm_warm },
+ { CS42L43_AMP2_SCDET, "spkr short circuit", cs42l43_spkr_sc_detect },
+ { CS42L43_AMP1_SCDET, "spkl short circuit", cs42l43_spkl_sc_detect },
+ { CS42L43_HP_ILIMIT, "hp ilimit", cs42l43_hp_ilimit },
+ { CS42L43_HP_LOADDET_DONE, "load detect done", cs42l43_load_detect },
+};
+
+static int cs42l43_request_irq(struct cs42l43_codec *priv,
+ struct irq_domain *dom, const char * const name,
+ unsigned int irq, irq_handler_t handler)
+{
+ int ret;
+
+ ret = irq_create_mapping(dom, irq);
+ if (ret < 0)
+ return dev_err_probe(priv->dev, ret, "Failed to map IRQ %s\n", name);
+
+ dev_dbg(priv->dev, "Request IRQ %d for %s\n", ret, name);
+
+ ret = devm_request_threaded_irq(priv->dev, ret, NULL, handler, IRQF_ONESHOT,
+ name, priv);
+ if (ret)
+ return dev_err_probe(priv->dev, ret, "Failed to request IRQ %s\n", name);
+
+ return 0;
+}
+
+static int cs42l43_shutter_irq(struct cs42l43_codec *priv,
+ struct irq_domain *dom, unsigned int shutter,
+ const char * const open_name,
+ const char * const close_name,
+ irq_handler_t handler)
+{
+ unsigned int open_irq, close_irq;
+ int ret;
+
+ switch (shutter) {
+ case 0x1:
+ dev_warn(priv->dev, "Manual shutters, notifications not available\n");
+ return 0;
+ case 0x2:
+ open_irq = CS42L43_GPIO1_RISE;
+ close_irq = CS42L43_GPIO1_FALL;
+ break;
+ case 0x4:
+ open_irq = CS42L43_GPIO2_RISE;
+ close_irq = CS42L43_GPIO2_FALL;
+ break;
+ case 0x8:
+ open_irq = CS42L43_GPIO3_RISE;
+ close_irq = CS42L43_GPIO3_FALL;
+ break;
+ default:
+ return 0;
+ }
+
+ ret = cs42l43_request_irq(priv, dom, close_name, close_irq, handler);
+ if (ret)
+ return ret;
+
+ return cs42l43_request_irq(priv, dom, open_name, open_irq, handler);
+}
+
+static int cs42l43_codec_probe(struct platform_device *pdev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
+ struct cs42l43_codec *priv;
+ struct irq_domain *dom;
+ unsigned int val;
+ int i, ret;
+
+ dom = irq_find_matching_fwnode(dev_fwnode(cs42l43->dev), DOMAIN_BUS_ANY);
+ if (!dom)
+ return -EPROBE_DEFER;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = &pdev->dev;
+ priv->core = cs42l43;
+
+ platform_set_drvdata(pdev, priv);
+
+ mutex_init(&priv->jack_lock);
+ mutex_init(&priv->spk_vu_lock);
+
+ init_completion(&priv->hp_startup);
+ init_completion(&priv->hp_shutdown);
+ init_completion(&priv->spkr_shutdown);
+ init_completion(&priv->spkl_shutdown);
+ init_completion(&priv->spkr_startup);
+ init_completion(&priv->spkl_startup);
+ init_completion(&priv->pll_ready);
+ init_completion(&priv->type_detect);
+ init_completion(&priv->load_detect);
+
+ INIT_DELAYED_WORK(&priv->tip_sense_work, cs42l43_tip_sense_work);
+ INIT_DELAYED_WORK(&priv->bias_sense_timeout, cs42l43_bias_sense_timeout);
+ INIT_DELAYED_WORK(&priv->button_press_work, cs42l43_button_press_work);
+ INIT_WORK(&priv->button_release_work, cs42l43_button_release_work);
+
+ pm_runtime_set_autosuspend_delay(priv->dev, 100);
+ pm_runtime_use_autosuspend(priv->dev);
+ pm_runtime_set_active(priv->dev);
+ pm_runtime_get_noresume(priv->dev);
+ devm_pm_runtime_enable(priv->dev);
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_irqs); i++) {
+ ret = cs42l43_request_irq(priv, dom, cs42l43_irqs[i].name,
+ cs42l43_irqs[i].irq, cs42l43_irqs[i].handler);
+ if (ret)
+ goto err_pm;
+ }
+
+ ret = regmap_read(cs42l43->regmap, CS42L43_SHUTTER_CONTROL, &val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to check shutter source: %d\n", ret);
+ goto err_pm;
+ }
+
+ ret = cs42l43_shutter_irq(priv, dom, val & CS42L43_MIC_SHUTTER_CFG_MASK,
+ "mic shutter open", "mic shutter close",
+ cs42l43_mic_shutter);
+ if (ret)
+ goto err_pm;
+
+ ret = cs42l43_shutter_irq(priv, dom, (val & CS42L43_SPK_SHUTTER_CFG_MASK) >>
+ CS42L43_SPK_SHUTTER_CFG_SHIFT,
+ "spk shutter open", "spk shutter close",
+ cs42l43_spk_shutter);
+ if (ret)
+ goto err_pm;
+
+ // Don't use devm as we need to get against the MFD device
+ priv->mclk = clk_get_optional(cs42l43->dev, "mclk");
+ if (IS_ERR(priv->mclk)) {
+ dev_err_probe(priv->dev, PTR_ERR(priv->mclk), "Failed to get mclk\n");
+ goto err_pm;
+ }
+
+ ret = devm_snd_soc_register_component(priv->dev, &cs42l43_component_drv,
+ cs42l43_dais, ARRAY_SIZE(cs42l43_dais));
+ if (ret) {
+ dev_err_probe(priv->dev, ret, "Failed to register component\n");
+ goto err_clk;
+ }
+
+ pm_runtime_mark_last_busy(priv->dev);
+ pm_runtime_put_autosuspend(priv->dev);
+
+ return 0;
+
+err_clk:
+ clk_put(priv->mclk);
+err_pm:
+ pm_runtime_put_sync(priv->dev);
+
+ return ret;
+}
+
+static int cs42l43_codec_remove(struct platform_device *pdev)
+{
+ struct cs42l43_codec *priv = platform_get_drvdata(pdev);
+
+ clk_put(priv->mclk);
+
+ return 0;
+}
+
+static int cs42l43_codec_runtime_resume(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "Runtime resume\n");
+
+ // Toggle the speaker volume update incase the speaker volume was synced
+ cs42l43_spk_vu_sync(priv);
+
+ return 0;
+}
+
+DEFINE_RUNTIME_DEV_PM_OPS(cs42l43_codec_pm_ops, NULL,
+ cs42l43_codec_runtime_resume, NULL);
+
+static const struct platform_device_id cs42l43_codec_id_table[] = {
+ { "cs42l43-codec", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table);
+
+static struct platform_driver cs42l43_codec_driver = {
+ .driver = {
+ .name = "cs42l43-codec",
+ .pm = &cs42l43_codec_pm_ops,
+ },
+
+ .probe = cs42l43_codec_probe,
+ .remove = cs42l43_codec_remove,
+ .id_table = cs42l43_codec_id_table,
+};
+module_platform_driver(cs42l43_codec_driver);
+
+MODULE_IMPORT_NS(SND_SOC_CS42L43);
+
+MODULE_DESCRIPTION("CS42L43 CODEC Driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h
new file mode 100644
index 000000000000..bf4f728eea3e
--- /dev/null
+++ b/sound/soc/codecs/cs42l43.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CS42L43 CODEC driver internal data
+ *
+ * Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/types.h>
+#include <sound/cs42l43.h>
+#include <sound/pcm.h>
+#include <sound/soc-jack.h>
+
+#ifndef CS42L43_ASOC_INT_H
+#define CS42L43_ASOC_INT_H
+
+#define CS42L43_INTERNAL_SYSCLK 24576000
+#define CS42L43_DEFAULT_SLOTS 0x3F
+
+#define CS42L43_PLL_TIMEOUT_MS 200
+#define CS42L43_SPK_TIMEOUT_MS 100
+#define CS42L43_HP_TIMEOUT_MS 2000
+#define CS42L43_LOAD_TIMEOUT_MS 1000
+
+#define CS42L43_ASP_MAX_CHANNELS 6
+#define CS42L43_N_EQ_COEFFS 15
+
+#define CS42L43_N_BUTTONS 6
+
+struct cs42l43_codec {
+ struct device *dev;
+ struct cs42l43 *core;
+ struct snd_soc_component *component;
+
+ struct clk *mclk;
+
+ int n_slots;
+ int slot_width;
+ int tx_slots[CS42L43_ASP_MAX_CHANNELS];
+ int rx_slots[CS42L43_ASP_MAX_CHANNELS];
+ struct snd_pcm_hw_constraint_list constraint;
+
+ u32 eq_coeffs[CS42L43_N_EQ_COEFFS];
+
+ unsigned int refclk_src;
+ unsigned int refclk_freq;
+ struct completion pll_ready;
+
+ unsigned int decim_cache[4];
+ unsigned int adc_ena;
+ unsigned int hp_ena;
+
+ struct completion hp_startup;
+ struct completion hp_shutdown;
+ struct completion spkr_shutdown;
+ struct completion spkl_shutdown;
+ struct completion spkr_startup;
+ struct completion spkl_startup;
+ // Lock to ensure speaker VU updates don't clash
+ struct mutex spk_vu_lock;
+
+ // Lock for all jack detect operations
+ struct mutex jack_lock;
+ struct snd_soc_jack *jack_hp;
+
+ bool use_ring_sense;
+ unsigned int tip_debounce_ms;
+ unsigned int bias_low;
+ unsigned int bias_sense_ua;
+ unsigned int bias_ramp_ms;
+ unsigned int detect_us;
+ unsigned int buttons[CS42L43_N_BUTTONS];
+
+ struct delayed_work tip_sense_work;
+ struct delayed_work bias_sense_timeout;
+ struct delayed_work button_press_work;
+ struct work_struct button_release_work;
+ struct completion type_detect;
+ struct completion load_detect;
+
+ bool load_detect_running;
+ bool button_detect_running;
+ bool jack_present;
+ int jack_override;
+};
+
+#if IS_REACHABLE(CONFIG_SND_SOC_CS42L43_SDW)
+
+int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai);
+int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction);
+
+#else
+
+static inline int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ return -EINVAL;
+}
+
+#define cs42l43_sdw_remove_peripheral NULL
+#define cs42l43_sdw_set_stream NULL
+
+#endif
+
+int cs42l43_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *d);
+void cs42l43_bias_sense_timeout(struct work_struct *work);
+void cs42l43_tip_sense_work(struct work_struct *work);
+void cs42l43_button_press_work(struct work_struct *work);
+void cs42l43_button_release_work(struct work_struct *work);
+irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data);
+irqreturn_t cs42l43_button_press(int irq, void *data);
+irqreturn_t cs42l43_button_release(int irq, void *data);
+irqreturn_t cs42l43_tip_sense(int irq, void *data);
+int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+
+extern const struct soc_enum cs42l43_jack_enum;
+
+#endif /* CS42L43_ASOC_INT_H */
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index e7db7bcd0296..5ed2ef83dcdb 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -19,7 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
-const struct of_device_id cs42l51_of_match[] = {
+static const struct of_device_id cs42l51_of_match[] = {
{ .compatible = "cirrus,cs42l51", },
{ }
};
diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c
index a6538dab6639..1245e1a4f2a5 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -1143,6 +1143,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l15_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l15_dai[] = {
{
.name = "cs47l15-aif1",
@@ -1219,7 +1223,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l15_dai_ops,
},
{
.name = "cs47l15-dsp-trace",
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index a07b621d463e..cfa1d34f6ebd 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id,
#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static const struct snd_soc_dai_ops cs47l24_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l24_dai[] = {
{
.name = "cs47l24-aif1",
@@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l24_dai_ops,
},
{
.name = "cs47l24-dsp-voicectrl",
@@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
.rates = CS47L24_RATES,
.formats = CS47L24_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l24_dai_ops,
},
{
.name = "cs47l24-dsp-trace",
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index c05c80c16c84..a953f2ede1ee 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l35_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l35_dai[] = {
{
.name = "cs47l35-aif1",
@@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l35_dai_ops,
},
{
.name = "cs47l35-dsp-voicectrl",
@@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l35_dai_ops,
},
{
.name = "cs47l35-dsp-trace",
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index dd7997a53e70..827685481859 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l85_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l85_dai[] = {
{
.name = "cs47l85-aif1",
@@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l85_dai_ops,
},
{
.name = "cs47l85-dsp-voicectrl",
@@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l85_dai_ops,
},
{
.name = "cs47l85-dsp-trace",
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index cdd5e7e20b5d..2c9a5372cf51 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l90_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l90_dai[] = {
{
.name = "cs47l90-aif1",
@@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l90_dai_ops,
},
{
.name = "cs47l90-dsp-voicectrl",
@@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = &snd_soc_new_compress,
+ .ops = &cs47l90_dai_ops,
},
{
.name = "cs47l90-dsp-trace",
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index bc4d311d4778..352deeaff1ca 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -1690,6 +1690,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id,
}
}
+static const struct snd_soc_dai_ops cs47l92_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver cs47l92_dai[] = {
{
.name = "cs47l92-aif1",
@@ -1823,7 +1827,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
.rates = MADERA_RATES,
.formats = MADERA_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &cs47l92_dai_ops,
},
{
.name = "cs47l92-dsp-trace",
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 082231088a26..f8b128084015 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -1546,6 +1546,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops cx2072x_dai_ops2 = {
+ .probe = cx2072x_dsp_dai_probe,
+ .set_sysclk = cx2072x_set_dai_sysclk,
+ .set_fmt = cx2072x_set_dai_fmt,
+ .hw_params = cx2072x_hw_params,
+ .set_bclk_ratio = cx2072x_set_dai_bclk_ratio,
+};
+
#define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
@@ -1572,7 +1580,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
{ /* plabayck only, return echo reference to Conexant DSP chip */
.name = "cx2072x-dsp",
.id = CX2072X_DAI_DSP,
- .probe = cx2072x_dsp_dai_probe,
.playback = {
.stream_name = "DSP Playback",
.channels_min = 2,
@@ -1580,7 +1587,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
.rates = CX2072X_RATES_DSP,
.formats = CX2072X_FORMATS,
},
- .ops = &cx2072x_dai_ops,
+ .ops = &cx2072x_dai_ops2,
},
{ /* plabayck only, return echo reference through I2S TX */
.name = "cx2072x-aec",
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index a7fbb758eeee..6c263086c44d 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -41,6 +41,8 @@ struct es8326_priv {
bool calibrated;
int version;
+ int hp;
+ int jack_remove_retry;
};
static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
@@ -158,20 +160,25 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
{"HPOR", NULL, "RHPMIX"},
};
-static const struct regmap_range es8326_volatile_ranges[] = {
- regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT),
-};
-
-static const struct regmap_access_table es8326_volatile_table = {
- .yes_ranges = es8326_volatile_ranges,
- .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
-};
+static bool es8326_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ES8326_HPL_OFFSET_INI:
+ case ES8326_HPR_OFFSET_INI:
+ case ES8326_HPDET_STA:
+ case ES8326_CTIA_OMTP_STA:
+ case ES8326_CSM_MUTE_STA:
+ return true;
+ default:
+ return false;
+ }
+}
static const struct regmap_config es8326_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xff,
- .volatile_table = &es8326_volatile_table,
+ .volatile_reg = es8326_volatile_register,
.cache_type = REGCACHE_RBTREE,
};
@@ -383,6 +390,7 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
{
struct snd_soc_component *component = dai->component;
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+ unsigned int offset_l, offset_r;
if (mute) {
regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
@@ -393,10 +401,16 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
if (!es8326->calibrated) {
regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL);
msleep(30);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+ regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l);
+ regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r);
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+ regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l);
+ regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
es8326->calibrated = true;
}
regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0);
- regmap_write(es8326->regmap, ES8326_HP_VOL, 0x00);
+ regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80);
regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON);
regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
ES8326_MUTE_MASK, ~(ES8326_MUTE));
@@ -415,15 +429,17 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
ret = clk_prepare_enable(es8326->mclk);
if (ret)
return ret;
- regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN);
- regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45);
+
+ regmap_write(es8326->regmap, ES8326_RESET, 0x9f);
+ msleep(20);
+ regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00);
+ regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
(ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
- regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
- regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
- regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02);
+ regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
- regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA);
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x20);
regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
break;
case SND_SOC_BIAS_PREPARE:
@@ -432,15 +448,10 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
break;
case SND_SOC_BIAS_OFF:
clk_disable_unprepare(es8326->mclk);
- regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11);
- regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF);
- regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8);
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
- regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08);
+ regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00);
regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
- regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
- regmap_write(es8326->regmap, ES8326_RESET,
- ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
break;
}
@@ -519,13 +530,14 @@ static void es8326_jack_button_handler(struct work_struct *work)
return;
mutex_lock(&es8326->lock);
- iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+ iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
switch (iface) {
case 0x93:
/* pause button detected */
cur_button = SND_JACK_BTN_0;
break;
case 0x6f:
+ case 0x4b:
/* button volume up */
cur_button = SND_JACK_BTN_1;
break;
@@ -534,6 +546,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
cur_button = SND_JACK_BTN_2;
break;
case 0x1e:
+ case 0xe2:
/* button released or not pressed */
cur_button = 0;
break;
@@ -543,20 +556,20 @@ static void es8326_jack_button_handler(struct work_struct *work)
if ((prev_button == cur_button) && (cur_button != 0)) {
press_count++;
- if (press_count > 10) {
- /* report a press every 500ms */
+ if (press_count > 3) {
+ /* report a press every 120ms */
snd_soc_jack_report(es8326->jack, cur_button,
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
press_count = 0;
}
button_to_report = cur_button;
queue_delayed_work(system_wq, &es8326->button_press_work,
- msecs_to_jiffies(50));
+ msecs_to_jiffies(35));
} else if (prev_button != cur_button) {
/* mismatch, detect again */
prev_button = cur_button;
queue_delayed_work(system_wq, &es8326->button_press_work,
- msecs_to_jiffies(50));
+ msecs_to_jiffies(35));
} else {
/* released or no pressed */
if (button_to_report != 0) {
@@ -578,34 +591,98 @@ static void es8326_jack_detect_handler(struct work_struct *work)
unsigned int iface;
mutex_lock(&es8326->lock);
- iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+ iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
dev_dbg(comp->dev, "gpio flag %#04x", iface);
+
+ if (es8326->jack_remove_retry == 1) {
+ if (iface & ES8326_HPINSERT_FLAG)
+ es8326->jack_remove_retry = 2;
+ else
+ es8326->jack_remove_retry = 0;
+
+ dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n",
+ es8326->jack_remove_retry);
+ /*
+ * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
+ */
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
+ ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
+ ~es8326->jack_pol : es8326->jack_pol));
+ goto exit;
+ }
+
if ((iface & ES8326_HPINSERT_FLAG) == 0) {
/* Jack unplugged or spurious IRQ */
- dev_dbg(comp->dev, "No headset detected");
+ dev_dbg(comp->dev, "No headset detected\n");
+ es8326_disable_micbias(es8326->component);
if (es8326->jack->status & SND_JACK_HEADPHONE) {
+ dev_dbg(comp->dev, "Report hp remove event\n");
snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
- snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
- es8326_disable_micbias(comp);
+ /* mute adc when mic path switch */
+ regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33);
+ regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44);
+ regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66);
+ es8326->hp = 0;
+ }
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+ /*
+ * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
+ */
+ if (es8326->jack_remove_retry == 0) {
+ es8326->jack_remove_retry = 1;
+ dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n",
+ es8326->jack_remove_retry);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
+ ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
+ es8326->jack_pol : ~es8326->jack_pol));
+
+ } else {
+ es8326->jack_remove_retry = 0;
}
} else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+ es8326->jack_remove_retry = 0;
+ if (es8326->hp == 0) {
+ dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n");
+ /*
+ * set auto-check mode, then restart jack_detect_work after 100ms.
+ * Don't report jack status.
+ */
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+ usleep_range(50000, 70000);
+ regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
+ queue_delayed_work(system_wq, &es8326->jack_detect_work,
+ msecs_to_jiffies(100));
+ es8326->hp = 1;
+ goto exit;
+ }
if (es8326->jack->status & SND_JACK_HEADSET) {
/* detect button */
+ dev_dbg(comp->dev, "button pressed\n");
queue_delayed_work(system_wq, &es8326->button_press_work, 10);
+ goto exit;
+ }
+ if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
+ dev_dbg(comp->dev, "Headphone detected\n");
+ snd_soc_jack_report(es8326->jack,
+ SND_JACK_HEADPHONE, SND_JACK_HEADSET);
} else {
- if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
- dev_dbg(comp->dev, "Headset detected");
- snd_soc_jack_report(es8326->jack,
- SND_JACK_HEADSET, SND_JACK_HEADSET);
- snd_soc_component_write(comp,
- ES8326_ADC1_SRC, es8326->mic1_src);
- } else {
- dev_dbg(comp->dev, "Headphone detected");
- snd_soc_jack_report(es8326->jack,
- SND_JACK_HEADPHONE, SND_JACK_HEADSET);
- }
+ dev_dbg(comp->dev, "Headset detected\n");
+ snd_soc_jack_report(es8326->jack,
+ SND_JACK_HEADSET, SND_JACK_HEADSET);
+
+ regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33);
+ regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+ 0x08, 0x08);
+ regmap_update_bits(es8326->regmap, ES8326_PGAGAIN,
+ 0x80, 0x80);
+ regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
+ regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
+ regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+ 0x08, 0x00);
+ usleep_range(10000, 15000);
}
}
+exit:
mutex_unlock(&es8326->lock);
}
@@ -624,51 +701,138 @@ static irqreturn_t es8326_irq(int irq, void *dev_id)
msecs_to_jiffies(10));
else
queue_delayed_work(system_wq, &es8326->jack_detect_work,
- msecs_to_jiffies(300));
+ msecs_to_jiffies(600));
out:
return IRQ_HANDLED;
}
-static int es8326_resume(struct snd_soc_component *component)
+static int es8326_calibrate(struct snd_soc_component *component)
{
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
unsigned int reg;
+ unsigned int offset_l, offset_r;
+
+ regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
+ es8326->version = reg;
+
+ if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) {
+ dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n");
+ regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0);
+ regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01);
+ regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30);
+ regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed);
+ regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1);
+ regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03);
+ regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f);
+ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33);
+ regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88);
+ regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80);
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+ regmap_write(es8326->regmap, ES8326_RESET, 0xc0);
+ usleep_range(15000, 20000);
+
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF);
+ regmap_read(es8326->regmap, ES8326_CSM_MUTE_STA, &reg);
+ if ((reg & 0xf0) != 0x40)
+ msleep(50);
+
+ regmap_write(es8326->regmap, ES8326_HP_CAL, 0xd4);
+ msleep(200);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, 0x4d);
+ msleep(200);
+ regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+ regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l);
+ regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r);
+ regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+ regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l);
+ regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
+ regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
+
+ es8326->calibrated = true;
+ }
+
+ return 0;
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+ struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
regcache_cache_only(es8326->regmap, false);
regcache_sync(es8326->regmap);
+ /* reset internal clock state */
+ regmap_write(es8326->regmap, ES8326_RESET, 0x1f);
+ regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
+ usleep_range(10000, 15000);
+ regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
+ /* set headphone default type and detect pin */
+ regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81);
+ regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
+
+ /* set internal oscillator as clock source of headpone cp */
+ regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84);
regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
- /* Two channel ADC */
- regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02);
+ /* clock manager reset release */
+ regmap_write(es8326->regmap, ES8326_RESET, 0x17);
+ /* set headphone detection as half scan mode */
+ regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08);
+ regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00);
+
+ /* enable headphone driver */
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7);
+ usleep_range(2000, 5000);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab);
+ usleep_range(2000, 5000);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb);
+ usleep_range(2000, 5000);
+ regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
+
regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
- regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F);
- regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8);
- regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88);
- regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20);
+ regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4);
+ regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81);
+ regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00);
+ /* calibrate for B version */
+ es8326_calibrate(component);
+ /* turn off headphone out */
+ regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00);
+ /* set ADC and DAC in low power mode */
+ regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
+
+ /* force micbias on */
+ regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f);
regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08);
- regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22);
- regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src);
- regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src);
- regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
- regmap_write(es8326->regmap, ES8326_HP_DET,
- ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
- regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src);
- regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
+ regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
+ /* select vdda as micbias source */
+ regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23);
+ /* set dac dsmclip = 1 */
+ regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08);
+ regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15);
+
+ regmap_write(es8326->regmap, ES8326_INT_SOURCE,
+ (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
+ regmap_write(es8326->regmap, ES8326_INTOUT_IO,
+ es8326->interrupt_clk);
+ regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
+ (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+ regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+
+ regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
- snd_soc_component_update_bits(component, ES8326_PGAGAIN,
- ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+ regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK,
+ ES8326_MIC1_SEL);
- regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
- if ((reg & ES8326_VERSION_B) == 1) {
- regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD);
- regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
- regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F);
- /* enable button detect */
- regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0);
- }
+ regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK,
+ ES8326_MUTE);
- es8326_irq(es8326->irq, es8326);
+ regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 |
+ ((es8326->version == ES8326_VERSION_B) ?
+ (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
+ (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
+
+ es8326->jack_remove_retry = 0;
+ es8326->hp = 0;
return 0;
}
@@ -683,6 +847,10 @@ static int es8326_suspend(struct snd_soc_component *component)
regcache_cache_only(es8326->regmap, true);
regcache_mark_dirty(es8326->regmap);
+ /* reset register value to default */
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+ usleep_range(1000, 3000);
+ regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
return 0;
}
@@ -712,7 +880,7 @@ static int es8326_probe(struct snd_soc_component *component)
ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
if (ret != 0) {
dev_dbg(component->dev, "jack-pol return %d", ret);
- es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+ es8326->jack_pol = ES8326_HP_TYPE_AUTO;
}
dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
@@ -743,7 +911,7 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component,
mutex_lock(&es8326->lock);
if (es8326->jd_inverted)
- snd_soc_component_update_bits(component, ES8326_HP_DET,
+ snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
es8326->jack = jack;
diff --git a/sound/soc/codecs/es8326.h b/sound/soc/codecs/es8326.h
index 3f8f7da58062..90a08351d6ac 100644
--- a/sound/soc/codecs/es8326.h
+++ b/sound/soc/codecs/es8326.h
@@ -73,15 +73,19 @@
#define ES8326_DRC_RECOVERY 0x53
#define ES8326_DRC_WINSIZE 0x54
#define ES8326_HPJACK_TIMER 0x56
-#define ES8326_HP_DET 0x57
+#define ES8326_HPDET_TYPE 0x57
#define ES8326_INT_SOURCE 0x58
#define ES8326_INTOUT_IO 0x59
#define ES8326_SDINOUT1_IO 0x5A
#define ES8326_SDINOUT23_IO 0x5B
#define ES8326_JACK_PULSE 0x5C
+#define ES8326_HP_MISC 0xF7
+#define ES8326_CTIA_OMTP_STA 0xF8
#define ES8326_PULLUP_CTL 0xF9
-#define ES8326_HP_DETECT 0xFB
+#define ES8326_CSM_I2C_STA 0xFA
+#define ES8326_HPDET_STA 0xFB
+#define ES8326_CSM_MUTE_STA 0xFC
#define ES8326_CHIP_ID1 0xFD
#define ES8326_CHIP_ID2 0xFE
#define ES8326_CHIP_VERSION 0xFF
@@ -146,7 +150,7 @@
#define ES8326_ADC3_SHIFT 0
#define ES8326_ADC4_SHIFT 3
-/* ES8326_HP_DET */
+/* ES8326_HPDET_TYPE */
#define ES8326_HP_DET_SRC_PIN27 (1 << 5)
#define ES8326_HP_DET_SRC_PIN9 (1 << 4)
#define ES8326_HP_DET_JACK_POL (1 << 3)
@@ -156,6 +160,13 @@
#define ES8326_HP_TYPE_AUTO (1 << 0)
#define ES8326_HP_TYPE_AUTO_INV (0 << 0)
+/* ES8326_INT_SOURCE */
+#define ES8326_INT_SRC_DAC_MOZ (1 << 0)
+#define ES8326_INT_SRC_ADC_MOZ (1 << 1)
+#define ES8326_INT_SRC_BUTTON (1 << 2)
+#define ES8326_INT_SRC_PIN9 (1 << 3)
+#define ES8326_INT_SRC_PIN27 (1 << 4)
+
/* ES8326_SDINOUT1_IO */
#define ES8326_IO_INPUT (0 << 0)
#define ES8326_IO_SDIN_SLOT0 (1 << 0)
@@ -174,12 +185,12 @@
#define ES8326_SDINOUT2_SHIFT 4
#define ES8326_SDINOUT3_SHIFT 0
-/* ES8326_HP_DETECT */
+/* ES8326_HPDET_STA */
#define ES8326_HPINSERT_FLAG (1 << 1)
#define ES8326_HPBUTTON_FLAG (1 << 0)
/* ES8326_CHIP_VERSION 0xFF */
-#define ES8326_VERSION_B (1 << 0)
+#define ES8326_VERSION (1 << 0)
+#define ES8326_VERSION_B (3 << 0)
#endif
-
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index d21f69f05342..13689e718d36 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -723,24 +723,6 @@ static u64 hdmi_codec_formats =
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_AC97;
-static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
- .startup = hdmi_codec_startup,
- .shutdown = hdmi_codec_shutdown,
- .hw_params = hdmi_codec_hw_params,
- .prepare = hdmi_codec_prepare,
- .set_fmt = hdmi_codec_i2s_set_fmt,
- .mute_stream = hdmi_codec_mute,
- .auto_selectable_formats = &hdmi_codec_formats,
- .num_auto_selectable_formats = 1,
-};
-
-static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
- .startup = hdmi_codec_startup,
- .shutdown = hdmi_codec_shutdown,
- .hw_params = hdmi_codec_hw_params,
- .mute_stream = hdmi_codec_mute,
-};
-
#define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
@@ -921,10 +903,31 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
+ .probe = hdmi_dai_probe,
+ .startup = hdmi_codec_startup,
+ .shutdown = hdmi_codec_shutdown,
+ .hw_params = hdmi_codec_hw_params,
+ .prepare = hdmi_codec_prepare,
+ .set_fmt = hdmi_codec_i2s_set_fmt,
+ .mute_stream = hdmi_codec_mute,
+ .pcm_new = hdmi_codec_pcm_new,
+ .auto_selectable_formats = &hdmi_codec_formats,
+ .num_auto_selectable_formats = 1,
+};
+
+static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
+ .probe = hdmi_dai_spdif_probe,
+ .startup = hdmi_codec_startup,
+ .shutdown = hdmi_codec_shutdown,
+ .hw_params = hdmi_codec_hw_params,
+ .mute_stream = hdmi_codec_mute,
+ .pcm_new = hdmi_codec_pcm_new,
+};
+
static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.name = "i2s-hifi",
.id = DAI_ID_I2S,
- .probe = hdmi_dai_probe,
.playback = {
.stream_name = "I2S Playback",
.channels_min = 2,
@@ -942,13 +945,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.sig_bits = 24,
},
.ops = &hdmi_codec_i2s_dai_ops,
- .pcm_new = hdmi_codec_pcm_new,
};
static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.name = "spdif-hifi",
.id = DAI_ID_SPDIF,
- .probe = hdmi_dai_spdif_probe,
.playback = {
.stream_name = "SPDIF Playback",
.channels_min = 2,
@@ -964,7 +965,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.formats = SPDIF_FORMATS,
},
.ops = &hdmi_codec_spdif_dai_ops,
- .pcm_new = hdmi_codec_pcm_new,
};
static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 7c25acf6ff0d..d1cea93bdb59 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -301,7 +301,7 @@ static const struct regmap_config jz4740_codec_regmap_config = {
.reg_defaults = jz4740_codec_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
static int jz4740_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c
deleted file mode 100644
index b84f6f1f6800..000000000000
--- a/sound/soc/codecs/l3.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * L3 code
- *
- * Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org>
- *
- * based on:
- *
- * L3 bus algorithm module.
- *
- * Copyright (C) 2001 Russell King, All Rights Reserved.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-
-#include <sound/l3.h>
-
-/*
- * Send one byte of data to the chip. Data is latched into the chip on
- * the rising edge of the clock.
- */
-static void sendbyte(struct l3_pins *adap, unsigned int byte)
-{
- int i;
-
- for (i = 0; i < 8; i++) {
- adap->setclk(adap, 0);
- udelay(adap->data_hold);
- adap->setdat(adap, byte & 1);
- udelay(adap->data_setup);
- adap->setclk(adap, 1);
- udelay(adap->clock_high);
- byte >>= 1;
- }
-}
-
-/*
- * Send a set of bytes to the chip. We need to pulse the MODE line
- * between each byte, but never at the start nor at the end of the
- * transfer.
- */
-static void sendbytes(struct l3_pins *adap, const u8 *buf,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- if (i) {
- udelay(adap->mode_hold);
- adap->setmode(adap, 0);
- udelay(adap->mode);
- }
- adap->setmode(adap, 1);
- udelay(adap->mode_setup);
- sendbyte(adap, buf[i]);
- }
-}
-
-int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len)
-{
- adap->setclk(adap, 1);
- adap->setdat(adap, 1);
- adap->setmode(adap, 1);
- udelay(adap->mode);
-
- adap->setmode(adap, 0);
- udelay(adap->mode_setup);
- sendbyte(adap, addr);
- udelay(adap->mode_hold);
-
- sendbytes(adap, data, len);
-
- adap->setclk(adap, 1);
- adap->setdat(adap, 1);
- adap->setmode(adap, 0);
-
- return len;
-}
-EXPORT_SYMBOL_GPL(l3_write);
-
-
-static void l3_set_clk(struct l3_pins *adap, int val)
-{
- gpio_set_value(adap->gpio_clk, val);
-}
-
-static void l3_set_data(struct l3_pins *adap, int val)
-{
- gpio_set_value(adap->gpio_data, val);
-}
-
-static void l3_set_mode(struct l3_pins *adap, int val)
-{
- gpio_set_value(adap->gpio_mode, val);
-}
-
-int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap)
-{
- int ret;
-
- if (!adap->use_gpios)
- return -EINVAL;
-
- ret = devm_gpio_request_one(dev, adap->gpio_data,
- GPIOF_OUT_INIT_LOW, "l3_data");
- if (ret < 0)
- return ret;
- adap->setdat = l3_set_data;
-
- ret = devm_gpio_request_one(dev, adap->gpio_clk,
- GPIOF_OUT_INIT_LOW, "l3_clk");
- if (ret < 0)
- return ret;
- adap->setclk = l3_set_clk;
-
- ret = devm_gpio_request_one(dev, adap->gpio_mode,
- GPIOF_OUT_INIT_LOW, "l3_mode");
- if (ret < 0)
- return ret;
- adap->setmode = l3_set_mode;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(l3_set_gpio_ops);
-
-MODULE_DESCRIPTION("L3 bit-banging driver");
-MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c
index 2dfaf4fcfbd3..a2cca3436c68 100644
--- a/sound/soc/codecs/max98363.c
+++ b/sound/soc/codecs/max98363.c
@@ -160,28 +160,17 @@ static int max98363_io_init(struct sdw_slave *slave)
struct max98363_priv *max98363 = dev_get_drvdata(dev);
int ret, reg;
- if (max98363->first_hw_init) {
- regcache_cache_only(max98363->regmap, false);
+ regcache_cache_only(max98363->regmap, false);
+ if (max98363->first_hw_init)
regcache_cache_bypass(max98363->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!max98363->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
-
+ if (!max98363->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(dev);
-
- pm_runtime_enable(dev);
- }
-
pm_runtime_get_noresume(dev);
ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, &reg);
@@ -410,6 +399,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
max98363->regmap = regmap;
max98363->slave = slave;
+ regcache_cache_only(max98363->regmap, true);
+
max98363->hw_init = false;
max98363->first_hw_init = false;
@@ -417,10 +408,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363,
max98363_dai,
ARRAY_SIZE(max98363_dai));
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+ return 0;
}
static int max98363_sdw_probe(struct sdw_slave *slave,
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index df92242af960..b5cb951af570 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -361,28 +361,17 @@ static int max98373_io_init(struct sdw_slave *slave)
struct device *dev = &slave->dev;
struct max98373_priv *max98373 = dev_get_drvdata(dev);
- if (max98373->first_hw_init) {
- regcache_cache_only(max98373->regmap, false);
+ regcache_cache_only(max98373->regmap, false);
+ if (max98373->first_hw_init)
regcache_cache_bypass(max98373->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!max98373->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
-
+ if (!max98373->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(dev);
-
- pm_runtime_enable(dev);
- }
-
pm_runtime_get_noresume(dev);
/* Software Reset */
@@ -753,6 +742,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
max98373->regmap = regmap;
max98373->slave = slave;
+ regcache_cache_only(max98373->regmap, true);
+
max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
max98373->cache = devm_kcalloc(dev, max98373->cache_num,
sizeof(*max98373->cache),
@@ -773,10 +764,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw,
max98373_sdw_dai,
ARRAY_SIZE(max98373_sdw_dai));
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ return 0;
}
static int max98373_update_status(struct sdw_slave *slave,
@@ -834,10 +842,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
static int max98373_sdw_remove(struct sdw_slave *slave)
{
- struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
-
- if (max98373->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c
index bdc508e23e59..922ce0dc4e60 100644
--- a/sound/soc/codecs/max98926.c
+++ b/sound/soc/codecs/max98926.c
@@ -528,7 +528,8 @@ static int max98926_i2c_probe(struct i2c_client *i2c)
"Failed to allocate regmap: %d\n", ret);
goto err_out;
}
- if (of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
+ if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") ||
+ of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
max98926->interleave_mode = true;
if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 0aaf2e6ae78d..776f23d38ac5 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -162,10 +162,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0021_PCM_MASTER_MODE,
- MAX98927_PCM_MASTER_MODE_MASK,
- mode);
+ regmap_update_bits(max98927->regmap, MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MASK, mode);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -178,10 +176,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
- invert);
+ regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, invert);
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -207,36 +203,31 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
if (!use_pdm) {
/* pcm channel configuration */
- regmap_update_bits(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
+ regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_FORMAT_MASK,
- format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_FORMAT_MASK,
+ format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
- regmap_update_bits(max98927->regmap,
- MAX98927_R003B_SPK_SRC_SEL,
- MAX98927_SPK_SRC_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R0035_PDM_RX_CTRL,
- MAX98927_PDM_RX_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 0);
} else {
/* pdm channel configuration */
- regmap_update_bits(max98927->regmap,
- MAX98927_R0035_PDM_RX_CTRL,
- MAX98927_PDM_RX_EN_MASK, 1);
+ regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 1);
- regmap_update_bits(max98927->regmap,
- MAX98927_R003B_SPK_SRC_SEL,
- MAX98927_SPK_SRC_MASK, 3);
+ regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 3);
- regmap_update_bits(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+ 0);
}
return 0;
}
@@ -283,9 +274,9 @@ static int max98927_set_clock(struct max98927_priv *max98927,
return -EINVAL;
}
regmap_update_bits(max98927->regmap,
- MAX98927_R0021_PCM_MASTER_MODE,
- MAX98927_PCM_MASTER_MODE_MCLK_MASK,
- i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+ i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
}
if (!max98927->tdm_mode) {
@@ -298,9 +289,8 @@ static int max98927_set_clock(struct max98927_priv *max98927,
}
regmap_update_bits(max98927->regmap,
- MAX98927_R0022_PCM_CLK_SETUP,
- MAX98927_PCM_CLK_SETUP_BSEL_MASK,
- value);
+ MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK, value);
}
return 0;
}
@@ -333,9 +323,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
max98927->ch_size = snd_pcm_format_width(params_format(params));
- regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+ regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
dev_dbg(component->dev, "format supported %d",
params_format(params));
@@ -375,27 +364,24 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
goto err;
}
/* set DAI_SR to correct LRCLK frequency */
- regmap_update_bits(max98927->regmap,
- MAX98927_R0023_PCM_SR_SETUP1,
- MAX98927_PCM_SR_SET1_SR_MASK,
- sampling_rate);
- regmap_update_bits(max98927->regmap,
- MAX98927_R0024_PCM_SR_SETUP2,
- MAX98927_PCM_SR_SET2_SR_MASK,
- sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+ regmap_update_bits(max98927->regmap, MAX98927_R0023_PCM_SR_SETUP1,
+ MAX98927_PCM_SR_SET1_SR_MASK, sampling_rate);
+ regmap_update_bits(max98927->regmap, MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_SR_MASK,
+ sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
/* set sampling rate of IV */
if (max98927->interleave_mode &&
sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
regmap_update_bits(max98927->regmap,
- MAX98927_R0024_PCM_SR_SETUP2,
- MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
- sampling_rate - 3);
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate - 3);
else
regmap_update_bits(max98927->regmap,
- MAX98927_R0024_PCM_SR_SETUP2,
- MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
- sampling_rate);
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate);
return max98927_set_clock(max98927, params);
err:
return -EINVAL;
@@ -420,10 +406,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0022_PCM_CLK_SETUP,
- MAX98927_PCM_CLK_SETUP_BSEL_MASK,
- bsel);
+ regmap_update_bits(max98927->regmap, MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK, bsel);
/* Channel size configuration */
switch (slot_width) {
@@ -442,33 +426,26 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
}
- regmap_update_bits(max98927->regmap,
- MAX98927_R0020_PCM_MODE_CFG,
- MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+ regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
/* Rx slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R0018_PCM_RX_EN_A,
- rx_mask & 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R0019_PCM_RX_EN_B,
- (rx_mask & 0xFF00) >> 8);
+ regmap_write(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+ rx_mask & 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R0019_PCM_RX_EN_B,
+ (rx_mask & 0xFF00) >> 8);
/* Tx slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001A_PCM_TX_EN_A,
- tx_mask & 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R001B_PCM_TX_EN_B,
- (tx_mask & 0xFF00) >> 8);
+ regmap_write(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+ tx_mask & 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+ (tx_mask & 0xFF00) >> 8);
/* Tx slot Hi-Z configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- ~tx_mask & 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- (~tx_mask & 0xFF00) >> 8);
+ regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ ~tx_mask & 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ (~tx_mask & 0xFF00) >> 8);
return 0;
}
@@ -506,20 +483,16 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
max98927->tdm_mode = false;
break;
case SND_SOC_DAPM_POST_PMU:
- regmap_update_bits(max98927->regmap,
- MAX98927_R003A_AMP_EN,
- MAX98927_AMP_EN_MASK, 1);
- regmap_update_bits(max98927->regmap,
- MAX98927_R00FF_GLOBAL_SHDN,
- MAX98927_GLOBAL_EN_MASK, 1);
+ regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 1);
+ regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 1);
break;
case SND_SOC_DAPM_POST_PMD:
- regmap_update_bits(max98927->regmap,
- MAX98927_R00FF_GLOBAL_SHDN,
- MAX98927_GLOBAL_EN_MASK, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R003A_AMP_EN,
- MAX98927_AMP_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 0);
break;
default:
return 0;
@@ -532,8 +505,8 @@ static const char * const max98927_switch_text[] = {
static const struct soc_enum dai_sel_enum =
SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
- MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
- 3, max98927_switch_text);
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 3,
+ max98927_switch_text);
static const struct snd_kcontrol_new max98927_dai_controls =
SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
@@ -543,17 +516,17 @@ static const struct snd_kcontrol_new max98927_vi_control =
static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
- 0, 0, max98927_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ 0, 0, max98927_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
- &max98927_dai_controls),
+ &max98927_dai_controls),
SND_SOC_DAPM_OUTPUT("BE_OUT"),
SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture", 0,
- MAX98927_R003E_MEAS_EN, 0, 0),
+ MAX98927_R003E_MEAS_EN, 0, 0),
SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture", 0,
- MAX98927_R003E_MEAS_EN, 1, 0),
+ MAX98927_R003E_MEAS_EN, 1, 0),
SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
- &max98927_vi_control),
+ &max98927_vi_control),
SND_SOC_DAPM_SIGGEN("VMON"),
SND_SOC_DAPM_SIGGEN("IMON"),
};
@@ -623,20 +596,19 @@ static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
max98927_current_limit_text);
static const struct snd_kcontrol_new max98927_snd_controls[] = {
- SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
- 0, 6, 0,
- max98927_spk_tlv),
+ SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, 0, 6, 0,
+ max98927_spk_tlv),
SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
- 0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
- max98927_digital_tlv),
+ 0, (1 << MAX98927_AMP_VOL_WIDTH) - 1, 0,
+ max98927_digital_tlv),
SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
- MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
+ MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
- MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
- SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
- MAX98927_DRE_EN_SHIFT, 1, 0),
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
+ SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL, MAX98927_DRE_EN_SHIFT,
+ 1, 0),
SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
- MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+ MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
SOC_ENUM("Current Limit", max98927_current_limit),
};
@@ -682,117 +654,82 @@ static int max98927_probe(struct snd_soc_component *component)
max98927->component = component;
/* Software Reset */
- regmap_write(max98927->regmap,
- MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+ regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
+ MAX98927_SOFT_RESET);
/* IV default slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- 0xFF);
- regmap_write(max98927->regmap,
- MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
- 0x80);
- regmap_write(max98927->regmap,
- MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
- 0x1);
+ regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0xFF);
+ regmap_write(max98927->regmap, MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ 0x80);
+ regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+ 0x1);
/* Set inital volume (+13dB) */
- regmap_write(max98927->regmap,
- MAX98927_R0036_AMP_VOL_CTRL,
- 0x38);
- regmap_write(max98927->regmap,
- MAX98927_R003C_SPK_GAIN,
- 0x05);
+ regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38);
+ regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05);
/* Enable DC blocker */
- regmap_write(max98927->regmap,
- MAX98927_R0037_AMP_DSP_CFG,
- 0x03);
+ regmap_write(max98927->regmap, MAX98927_R0037_AMP_DSP_CFG, 0x03);
/* Enable IMON VMON DC blocker */
- regmap_write(max98927->regmap,
- MAX98927_R003F_MEAS_DSP_CFG,
- 0xF7);
+ regmap_write(max98927->regmap, MAX98927_R003F_MEAS_DSP_CFG, 0xF7);
/* Boost Output Voltage & Current limit */
- regmap_write(max98927->regmap,
- MAX98927_R0040_BOOST_CTRL0,
- 0x1C);
- regmap_write(max98927->regmap,
- MAX98927_R0042_BOOST_CTRL1,
- 0x3E);
+ regmap_write(max98927->regmap, MAX98927_R0040_BOOST_CTRL0, 0x1C);
+ regmap_write(max98927->regmap, MAX98927_R0042_BOOST_CTRL1, 0x3E);
/* Measurement ADC config */
- regmap_write(max98927->regmap,
- MAX98927_R0043_MEAS_ADC_CFG,
- 0x04);
- regmap_write(max98927->regmap,
- MAX98927_R0044_MEAS_ADC_BASE_MSB,
- 0x00);
- regmap_write(max98927->regmap,
- MAX98927_R0045_MEAS_ADC_BASE_LSB,
- 0x24);
+ regmap_write(max98927->regmap, MAX98927_R0043_MEAS_ADC_CFG, 0x04);
+ regmap_write(max98927->regmap, MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00);
+ regmap_write(max98927->regmap, MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x24);
/* Brownout Level */
- regmap_write(max98927->regmap,
- MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
- 0x06);
+ regmap_write(max98927->regmap, MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+ 0x06);
/* Envelope Tracking configuration */
- regmap_write(max98927->regmap,
- MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
- 0x08);
- regmap_write(max98927->regmap,
- MAX98927_R0086_ENV_TRACK_CTRL,
- 0x01);
- regmap_write(max98927->regmap,
- MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
- 0x10);
+ regmap_write(max98927->regmap, MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+ 0x08);
+ regmap_write(max98927->regmap, MAX98927_R0086_ENV_TRACK_CTRL, 0x01);
+ regmap_write(max98927->regmap, MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+ 0x10);
/* voltage, current slot configuration */
- regmap_write(max98927->regmap,
- MAX98927_R001E_PCM_TX_CH_SRC_A,
- (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
- max98927->v_l_slot)&0xFF);
+ regmap_write(max98927->regmap, MAX98927_R001E_PCM_TX_CH_SRC_A,
+ (max98927->i_l_slot << MAX98927_PCM_TX_CH_SRC_A_I_SHIFT | max98927->v_l_slot) & 0xFF);
if (max98927->v_l_slot < 8) {
regmap_update_bits(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- 1 << max98927->v_l_slot, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001A_PCM_TX_EN_A,
- 1 << max98927->v_l_slot,
- 1 << max98927->v_l_slot);
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->v_l_slot, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->v_l_slot,
+ 1 << max98927->v_l_slot);
} else {
regmap_update_bits(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- 1 << (max98927->v_l_slot - 8), 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001B_PCM_TX_EN_B,
- 1 << (max98927->v_l_slot - 8),
- 1 << (max98927->v_l_slot - 8));
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->v_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->v_l_slot - 8),
+ 1 << (max98927->v_l_slot - 8));
}
if (max98927->i_l_slot < 8) {
regmap_update_bits(max98927->regmap,
- MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
- 1 << max98927->i_l_slot, 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001A_PCM_TX_EN_A,
- 1 << max98927->i_l_slot,
- 1 << max98927->i_l_slot);
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->i_l_slot, 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->i_l_slot,
+ 1 << max98927->i_l_slot);
} else {
regmap_update_bits(max98927->regmap,
- MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
- 1 << (max98927->i_l_slot - 8), 0);
- regmap_update_bits(max98927->regmap,
- MAX98927_R001B_PCM_TX_EN_B,
- 1 << (max98927->i_l_slot - 8),
- 1 << (max98927->i_l_slot - 8));
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->i_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->i_l_slot - 8),
+ 1 << (max98927->i_l_slot - 8));
}
/* Set interleave mode */
if (max98927->interleave_mode)
regmap_update_bits(max98927->regmap,
- MAX98927_R001F_PCM_TX_CH_SRC_B,
- MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
- MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
+ MAX98927_R001F_PCM_TX_CH_SRC_B,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
return 0;
}
@@ -809,8 +746,8 @@ static int max98927_resume(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
- regmap_write(max98927->regmap,
- MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+ regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
+ MAX98927_SOFT_RESET);
regcache_cache_only(max98927->regmap, false);
regcache_sync(max98927->regmap);
return 0;
@@ -869,9 +806,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
int reg = 0;
struct max98927_priv *max98927 = NULL;
- max98927 = devm_kzalloc(&i2c->dev,
- sizeof(*max98927), GFP_KERNEL);
-
+ max98927 = devm_kzalloc(&i2c->dev, sizeof(*max98927), GFP_KERNEL);
if (!max98927) {
ret = -ENOMEM;
return ret;
@@ -879,14 +814,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, max98927);
/* update interleave mode info */
- if (!of_property_read_u32(i2c->dev.of_node,
- "interleave_mode", &value)) {
- if (value > 0)
- max98927->interleave_mode = true;
- else
- max98927->interleave_mode = false;
- } else
- max98927->interleave_mode = false;
+ if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode")) {
+ max98927->interleave_mode = true;
+ } else {
+ if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode",
+ &value))
+ if (value > 0)
+ max98927->interleave_mode = true;
+ }
/* regmap initialization */
max98927->regmap
@@ -897,9 +832,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
"Failed to allocate regmap: %d\n", ret);
return ret;
}
-
- max98927->reset_gpio
- = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH);
+
+ max98927->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset",
+ GPIOD_OUT_HIGH);
if (IS_ERR(max98927->reset_gpio)) {
ret = PTR_ERR(max98927->reset_gpio);
return dev_err_probe(&i2c->dev, ret, "failed to request GPIO reset pin");
@@ -912,8 +847,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
}
/* Check Revision ID */
- ret = regmap_read(max98927->regmap,
- MAX98927_R01FF_REV_ID, &reg);
+ ret = regmap_read(max98927->regmap, MAX98927_R01FF_REV_ID, &reg);
if (ret < 0) {
dev_err(&i2c->dev,
"Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
@@ -938,9 +872,8 @@ static void max98927_i2c_remove(struct i2c_client *i2c)
{
struct max98927_priv *max98927 = i2c_get_clientdata(i2c);
- if (max98927->reset_gpio) {
+ if (max98927->reset_gpio)
gpiod_set_value_cansleep(max98927->reset_gpio, 1);
- }
}
static const struct i2c_device_id max98927_i2c_id[] = {
diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c
index ca6beb2d2649..f307374834b5 100644
--- a/sound/soc/codecs/nau8821.c
+++ b/sound/soc/codecs/nau8821.c
@@ -624,6 +624,36 @@ static int system_clock_control(struct snd_soc_dapm_widget *w,
return 0;
}
+static int nau8821_left_fepga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
+
+ if (!nau8821->left_input_single_end)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA,
+ NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK,
+ NAU8821_ACDC_VREF_MICN | NAU8821_FEPGA_MODEL_AAF);
+ regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST,
+ NAU8821_HP_BOOST_DISCHRG_EN, NAU8821_HP_BOOST_DISCHRG_EN);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(nau8821->regmap, NAU8821_R77_FEPGA,
+ NAU8821_ACDC_CTRL_MASK | NAU8821_FEPGA_MODEL_MASK, 0);
+ regmap_update_bits(nau8821->regmap, NAU8821_R76_BOOST,
+ NAU8821_HP_BOOST_DISCHRG_EN, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0,
system_clock_control, SND_SOC_DAPM_POST_PMD),
@@ -635,8 +665,10 @@ static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = {
NAU8821_POWERUP_ADCL_SFT, 0),
SND_SOC_DAPM_ADC("ADCR Power", NULL, NAU8821_R72_ANALOG_ADC_2,
NAU8821_POWERUP_ADCR_SFT, 0),
+ /* single-ended design only on the left */
SND_SOC_DAPM_PGA_S("Frontend PGA L", 1, NAU8821_R7F_POWER_UP_CONTROL,
- NAU8821_PUP_PGA_L_SFT, 0, NULL, 0),
+ NAU8821_PUP_PGA_L_SFT, 0, nau8821_left_fepga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_S("Frontend PGA R", 1, NAU8821_R7F_POWER_UP_CONTROL,
NAU8821_PUP_PGA_R_SFT, 0, NULL, 0),
SND_SOC_DAPM_PGA_S("ADCL Digital path", 0, NAU8821_R01_ENA_CTRL,
@@ -1677,6 +1709,8 @@ static int nau8821_read_device_properties(struct device *dev,
"nuvoton,jkdet-pull-up");
nau8821->key_enable = device_property_read_bool(dev,
"nuvoton,key-enable");
+ nau8821->left_input_single_end = device_property_read_bool(dev,
+ "nuvoton,left-input-single-end");
ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
&nau8821->jkdet_polarity);
if (ret)
@@ -1760,6 +1794,12 @@ static void nau8821_init_regs(struct nau8821 *nau8821)
NAU8821_ADC_SYNC_DOWN_MASK, NAU8821_ADC_SYNC_DOWN_64);
regmap_update_bits(regmap, NAU8821_R2C_DAC_CTRL1,
NAU8821_DAC_OVERSAMPLE_MASK, NAU8821_DAC_OVERSAMPLE_64);
+ if (nau8821->left_input_single_end) {
+ regmap_update_bits(regmap, NAU8821_R6B_PGA_MUTE,
+ NAU8821_MUTE_MICNL_EN, NAU8821_MUTE_MICNL_EN);
+ regmap_update_bits(regmap, NAU8821_R74_MIC_BIAS,
+ NAU8821_MICBIAS_LOWNOISE_EN, NAU8821_MICBIAS_LOWNOISE_EN);
+ }
}
static int nau8821_setup_irq(struct nau8821 *nau8821)
diff --git a/sound/soc/codecs/nau8821.h b/sound/soc/codecs/nau8821.h
index d962293c218e..00a888ed07ce 100644
--- a/sound/soc/codecs/nau8821.h
+++ b/sound/soc/codecs/nau8821.h
@@ -433,6 +433,14 @@
#define NAU8821_DAC_CAPACITOR_MSB (0x1 << 1)
#define NAU8821_DAC_CAPACITOR_LSB 0x1
+/* MUTE_MIC_L_N (0x6b) */
+#define NAU8821_MUTE_MICNL_SFT 5
+#define NAU8821_MUTE_MICNL_EN (0x1 << NAU8821_MUTE_MICNL_SFT)
+#define NAU8821_MUTE_MICNR_SFT 4
+#define NAU8821_MUTE_MICNR_EN (0x1 << NAU8821_MUTE_MICNR_SFT)
+#define NAU8821_MUTE_MICRP_SFT 2
+#define NAU8821_MUTE_MICRP_EN (0x1 << NAU8821_MUTE_MICRP_SFT)
+
/* ANALOG_ADC_1 (0x71) */
#define NAU8821_MICDET_EN_SFT 0
#define NAU8821_MICDET_MASK 0x1
@@ -463,23 +471,39 @@
/* MIC_BIAS (0x74) */
#define NAU8821_MICBIAS_JKR2 (0x1 << 12)
+#define NAU8821_MICBIAS_LOWNOISE_SFT 10
+#define NAU8821_MICBIAS_LOWNOISE_EN (0x1 << NAU8821_MICBIAS_LOWNOISE_SFT)
#define NAU8821_MICBIAS_POWERUP_SFT 8
+#define NAU8821_MICBIAS_POWERUP_EN (0x1 << NAU8821_MICBIAS_POWERUP_SFT)
#define NAU8821_MICBIAS_VOLTAGE_SFT 0
#define NAU8821_MICBIAS_VOLTAGE_MASK 0x7
/* BOOST (0x76) */
#define NAU8821_PRECHARGE_DIS (0x1 << 13)
#define NAU8821_GLOBAL_BIAS_EN (0x1 << 12)
+#define NAU8821_HP_BOOST_DISCHRG_SFT 11
+#define NAU8821_HP_BOOST_DISCHRG_EN (0x1 << NAU8821_HP_BOOST_DISCHRG_SFT)
#define NAU8821_HP_BOOST_DIS_SFT 9
#define NAU8821_HP_BOOST_DIS (0x1 << NAU8821_HP_BOOST_DIS_SFT)
#define NAU8821_HP_BOOST_G_DIS (0x1 << 8)
#define NAU8821_SHORT_SHUTDOWN_EN (0x1 << 6)
/* FEPGA (0x77) */
+#define NAU8821_ACDC_CTRL_SFT 14
+#define NAU8821_ACDC_CTRL_MASK (0x3 << NAU8821_ACDC_CTRL_SFT)
+#define NAU8821_ACDC_VREF_MICP (0x1 << NAU8821_ACDC_CTRL_SFT)
+#define NAU8821_ACDC_VREF_MICN (0x2 << NAU8821_ACDC_CTRL_SFT)
#define NAU8821_FEPGA_MODEL_SFT 4
#define NAU8821_FEPGA_MODEL_MASK (0xf << NAU8821_FEPGA_MODEL_SFT)
+#define NAU8821_FEPGA_MODEL_AAF (0x1 << NAU8821_FEPGA_MODEL_SFT)
+#define NAU8821_FEPGA_MODEL_DIS (0x2 << NAU8821_FEPGA_MODEL_SFT)
+#define NAU8821_FEPGA_MODEL_IMP12K (0x8 << NAU8821_FEPGA_MODEL_SFT)
#define NAU8821_FEPGA_MODER_SFT 0
#define NAU8821_FEPGA_MODER_MASK 0xf
+#define NAU8821_FEPGA_MODER_AAF 0x1
+#define NAU8821_FEPGA_MODER_DIS 0x2
+#define NAU8821_FEPGA_MODER_IMP12K 0x8
+
/* PGA_GAIN (0x7e) */
#define NAU8821_PGA_GAIN_L_SFT 8
@@ -543,6 +567,7 @@ struct nau8821 {
bool jkdet_enable;
bool jkdet_pull_enable;
bool jkdet_pull_up;
+ bool left_input_single_end;
int jkdet_polarity;
int jack_insert_debounce;
int jack_eject_debounce;
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index 42bac8150f62..d5285baad53a 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -13,11 +13,9 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <sound/core.h>
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 38d9f69b08d6..99ec0f9a8362 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/fs.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c
index 06800dad8798..44e7fe3c32da 100644
--- a/sound/soc/codecs/rt1015p.c
+++ b/sound/soc/codecs/rt1015p.c
@@ -8,7 +8,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
index b1e69fa290b2..919a1f25e584 100644
--- a/sound/soc/codecs/rt1016.c
+++ b/sound/soc/codecs/rt1016.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
new file mode 100644
index 000000000000..7295f44c77eb
--- /dev/null
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -0,0 +1,824 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1017-sdca-sdw.c -- rt1017 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt1017-sdca-sdw.h"
+
+static bool rt1017_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0x3206:
+ case 0xc000:
+ case 0xc001:
+ case 0xc022:
+ case 0xc030:
+ case 0xc104:
+ case 0xc10b:
+ case 0xc10c:
+ case 0xc110:
+ case 0xc112:
+ case 0xc300:
+ case 0xc301:
+ case 0xc318:
+ case 0xc325 ... 0xc328:
+ case 0xc331:
+ case 0xc340:
+ case 0xc350 ... 0xc351:
+ case 0xc500:
+ case 0xc502:
+ case 0xc504:
+ case 0xc507:
+ case 0xc509:
+ case 0xc510:
+ case 0xc512:
+ case 0xc518:
+ case 0xc51b:
+ case 0xc51d:
+ case 0xc520:
+ case 0xc540 ... 0xc542:
+ case 0xc550 ... 0xc552:
+ case 0xc600:
+ case 0xc602:
+ case 0xc612:
+ case 0xc622:
+ case 0xc632:
+ case 0xc642:
+ case 0xc651:
+ case 0xca00:
+ case 0xca09 ... 0xca0c:
+ case 0xca0e ... 0xca0f:
+ case 0xca10 ... 0xca11:
+ case 0xca16 ... 0xca17:
+ case 0xcb00:
+ case 0xcc00:
+ case 0xcc02:
+ case 0xd017:
+ case 0xd01a ... 0xd01c:
+ case 0xd101:
+ case 0xd20c:
+ case 0xd300:
+ case 0xd370:
+ case 0xd500:
+ case 0xd545 ... 0xd548:
+ case 0xd5a5 ... 0xd5a8:
+ case 0xd5aa ... 0xd5ad:
+ case 0xda04 ... 0xda07:
+ case 0xda09 ... 0xda0a:
+ case 0xda0c ... 0xda0f:
+ case 0xda11 ... 0xda14:
+ case 0xda16 ... 0xda19:
+ case 0xdab6 ... 0xdabb:
+ case 0xdb09 ... 0xdb0a:
+ case 0xdb14:
+
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
+ RT1017_SDCA_CTL_FU_MUTE, 0x01):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
+ RT1017_SDCA_CTL_BYPASS, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29,
+ RT1017_SDCA_CTL_PROT_STAT, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt1017_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case 0x2f55:
+ case 0xc000:
+ case 0xc022:
+ case 0xc351:
+ case 0xc518:
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29,
+ RT1017_SDCA_CTL_PROT_STAT, 0):
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct reg_sequence rt1017_blind_write[] = {
+ { 0xc001, 0x43 },
+ { 0x2f55, 0x02 },
+ { 0x3206, 0x80 },
+ { 0x005f, 0x7f },
+ { 0xd101, 0xa0 },
+ { 0xc112, 0xc0 },
+ { 0xc104, 0xaa },
+ { 0xc110, 0x59 },
+ { 0xc112, 0xc0 },
+ { 0xc340, 0x80 },
+ { 0xd017, 0x2c },
+ { 0xd01a, 0xc8 },
+ { 0xd01b, 0xcf },
+ { 0xd01c, 0x0c },
+ { 0xd20c, 0x14 },
+ { 0xdb09, 0x0f },
+ { 0xdb0a, 0x7f },
+ { 0xdb14, 0x03 },
+ { 0xcb00, 0x31 },
+ { 0xc318, 0x44 },
+ { 0xc325, 0xce },
+ { 0xc326, 0x13 },
+ { 0xc327, 0x5f },
+ { 0xc328, 0xf3 },
+ { 0xc350, 0xe1 },
+ { 0xc351, 0x88 },
+ { 0xc030, 0x14 },
+ { 0xc331, 0xf2 },
+ { 0xc551, 0x0f },
+ { 0xc552, 0xff },
+ { 0xc651, 0xc0 },
+ { 0xc550, 0xd0 },
+ { 0xc612, 0x00 },
+ { 0xc622, 0x00 },
+ { 0xc632, 0x00 },
+ { 0xc642, 0x00 },
+ { 0xc602, 0xf0 },
+ { 0xc600, 0xd0 },
+ { 0xcc02, 0x78 },
+ { 0xcc00, 0x90 },
+ { 0xc300, 0x3f },
+ { 0xc301, 0x1d },
+ { 0xc10b, 0x2e },
+ { 0xc10c, 0x36 },
+
+ { 0xd5a5, 0x00 },
+ { 0xd5a6, 0x6a },
+ { 0xd5a7, 0xaa },
+ { 0xd5a8, 0xaa },
+ { 0xd5aa, 0x00 },
+ { 0xd5ab, 0x16 },
+ { 0xd5ac, 0xdb },
+ { 0xd5ad, 0x6d },
+ { 0xd545, 0x09 },
+ { 0xd546, 0x30 },
+ { 0xd547, 0xf0 },
+ { 0xd548, 0xf0 },
+ { 0xd500, 0x20 },
+ { 0xc504, 0x3f },
+ { 0xc540, 0x00 },
+ { 0xc541, 0x0a },
+ { 0xc542, 0x1a },
+ { 0xc512, 0x00 },
+ { 0xc520, 0x40 },
+ { 0xc51b, 0x7f },
+ { 0xc51d, 0x0f },
+ { 0xc500, 0x40 },
+ { 0xc502, 0xde },
+ { 0xc507, 0x05 },
+ { 0xc509, 0x05 },
+ { 0xc510, 0x40 },
+ { 0xc518, 0xc0 },
+ { 0xc500, 0xc0 },
+
+ { 0xda0c, 0x00 },
+ { 0xda0d, 0x0b },
+ { 0xda0e, 0x55 },
+ { 0xda0f, 0x55 },
+ { 0xda04, 0x00 },
+ { 0xda05, 0x51 },
+ { 0xda06, 0xeb },
+ { 0xda07, 0x85 },
+ { 0xca16, 0x0f },
+ { 0xca17, 0x00 },
+ { 0xda09, 0x5d },
+ { 0xda0a, 0xc0 },
+ { 0xda11, 0x26 },
+ { 0xda12, 0x66 },
+ { 0xda13, 0x66 },
+ { 0xda14, 0x66 },
+ { 0xda16, 0x79 },
+ { 0xda17, 0x99 },
+ { 0xda18, 0x99 },
+ { 0xda19, 0x99 },
+ { 0xca09, 0x00 },
+ { 0xca0a, 0x07 },
+ { 0xca0b, 0x89 },
+ { 0xca0c, 0x61 },
+ { 0xca0e, 0x00 },
+ { 0xca0f, 0x03 },
+ { 0xca10, 0xc4 },
+ { 0xca11, 0xb0 },
+ { 0xdab6, 0x00 },
+ { 0xdab7, 0x01 },
+ { 0xdab8, 0x00 },
+ { 0xdab9, 0x00 },
+ { 0xdaba, 0x00 },
+ { 0xdabb, 0x00 },
+ { 0xd017, 0x0e },
+ { 0xca00, 0xcd },
+ { 0xc022, 0x84 },
+};
+
+#define RT1017_MAX_REG_NUM 0x4108ffff
+
+static const struct regmap_config rt1017_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .readable_reg = rt1017_sdca_readable_register,
+ .volatile_reg = rt1017_sdca_volatile_register,
+ .max_register = RT1017_MAX_REG_NUM,
+ .reg_defaults = rt1017_sdca_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt1017_sdca_reg_defaults),
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt1017_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int nval;
+ int i, j;
+ u32 bit;
+ unsigned long addr;
+ struct sdw_dpn_prop *dpn;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+ prop->paging_support = true;
+
+ /* first we need to allocate memory for set bits in port lists
+ * port = 1 for AMP playback
+ * port = 2 for IV capture
+ */
+ prop->source_ports = BIT(2); /* BITMAP: 00000100 */
+ prop->sink_ports = BIT(1); /* BITMAP: 00000010 */
+
+ nval = hweight32(prop->source_ports);
+ prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+ if (!prop->src_dpn_prop)
+ return -ENOMEM;
+
+ i = 0;
+ dpn = prop->src_dpn_prop;
+ addr = prop->source_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[i].num = bit;
+ dpn[i].type = SDW_DPN_FULL;
+ dpn[i].simple_ch_prep_sm = true;
+ dpn[i].ch_prep_timeout = 10;
+ i++;
+ }
+
+ /* do this again for sink now */
+ nval = hweight32(prop->sink_ports);
+ prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+ sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+ if (!prop->sink_dpn_prop)
+ return -ENOMEM;
+
+ j = 0;
+ dpn = prop->sink_dpn_prop;
+ addr = prop->sink_ports;
+ for_each_set_bit(bit, &addr, 32) {
+ dpn[j].num = bit;
+ dpn[j].type = SDW_DPN_FULL;
+ dpn[j].simple_ch_prep_sm = true;
+ dpn[j].ch_prep_timeout = 10;
+ j++;
+ }
+
+ /* set the timeout values */
+ prop->clk_stop_timeout = 64;
+
+ return 0;
+}
+
+static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+
+ if (rt1017->hw_init)
+ return 0;
+
+ if (rt1017->first_hw_init) {
+ regcache_cache_only(rt1017->regmap, false);
+ regcache_cache_bypass(rt1017->regmap, true);
+ } else {
+ /*
+ * PM runtime is only enabled when a Slave reports as Attached
+ */
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+ pm_runtime_use_autosuspend(&slave->dev);
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(&slave->dev);
+
+ pm_runtime_enable(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ /* sw reset */
+ regmap_write(rt1017->regmap, 0xc000, 0x02);
+
+ /* initial settings - blind write */
+ regmap_multi_reg_write(rt1017->regmap, rt1017_blind_write,
+ ARRAY_SIZE(rt1017_blind_write));
+
+ if (rt1017->first_hw_init) {
+ regcache_cache_bypass(rt1017->regmap, false);
+ regcache_mark_dirty(rt1017->regmap);
+ } else
+ rt1017->first_hw_init = true;
+
+ /* Mark Slave initialization complete */
+ rt1017->hw_init = true;
+
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ dev_dbg(&slave->dev, "hw_init complete\n");
+ return 0;
+}
+
+static int rt1017_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt1017->hw_init = false;
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt1017->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt1017_sdca_io_init(&slave->dev, slave);
+}
+
+static const char * const rt1017_rx_data_ch_select[] = {
+ "Bypass",
+ "CN1",
+ "CN2",
+ "CN3",
+ "CN4",
+ "(1+2)/2",
+ "(1+3)/2",
+ "(1+4)/2",
+ "(2+3)/2",
+ "(2+4)/2",
+ "(3+4)/2",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1017_rx_data_ch_enum,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0),
+ 0, rt1017_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1017_sdca_controls[] = {
+ /* UDMPU Cluster Selection */
+ SOC_ENUM("RX Channel Select", rt1017_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1017_sto_dac =
+ SOC_DAPM_SINGLE("Switch",
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x1),
+ 0, 1, 1);
+
+static int rt1017_sdca_pde23_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt1017->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps0);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt1017->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps3);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int rt1017_sdca_classd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(rt1017->regmap, RT1017_PWM_TRIM_1,
+ RT1017_PWM_FREQ_CTL_SRC_SEL_MASK, RT1017_PWM_FREQ_CTL_SRC_SEL_REG);
+ regmap_write(rt1017->regmap, RT1017_CLASSD_INT_1, 0x10);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt1017_sdca_feedback_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x08);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x09);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt1017_sdca_dapm_widgets[] = {
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT_E("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0,
+ rt1017_sdca_feedback_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1017_sto_dac),
+
+ /* Output Lines */
+ SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1017_sdca_classd_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_OUTPUT("SPO"),
+
+ SND_SOC_DAPM_SUPPLY("PDE23", SND_SOC_NOPM, 0, 0,
+ rt1017_sdca_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SIGGEN("I Gen"),
+ SND_SOC_DAPM_SIGGEN("V Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1017_sdca_dapm_routes[] = {
+
+ { "DAC", "Switch", "DP1RX" },
+ { "CLASS D", NULL, "DAC" },
+ { "CLASS D", NULL, "PDE23" },
+ { "SPO", NULL, "CLASS D" },
+
+ { "I Sense", NULL, "I Gen" },
+ { "V Sense", NULL, "V Gen" },
+ { "I Sense", NULL, "PDE23" },
+ { "V Sense", NULL, "PDE23" },
+ { "DP2TX", NULL, "I Sense" },
+ { "DP2TX", NULL, "V Sense" },
+};
+
+static struct sdw_slave_ops rt1017_sdca_slave_ops = {
+ .read_prop = rt1017_sdca_read_prop,
+ .update_status = rt1017_sdca_update_status,
+};
+
+static int rt1017_sdca_component_probe(struct snd_soc_component *component)
+{
+ int ret;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ return 0;
+}
+
+static void rt1017_sdca_component_remove(struct snd_soc_component *component)
+{
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt1017->regmap, true);
+}
+
+static const struct snd_soc_component_driver soc_sdca_component_rt1017 = {
+ .probe = rt1017_sdca_component_probe,
+ .remove = rt1017_sdca_component_remove,
+ .controls = rt1017_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt1017_sdca_controls),
+ .dapm_widgets = rt1017_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt1017_sdca_dapm_widgets),
+ .dapm_routes = rt1017_sdca_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt1017_sdca_dapm_routes),
+ .endianness = 1,
+};
+
+static int rt1017_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void rt1017_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_runtime *sdw_stream;
+ int retval, port, num_channels, ch_mask;
+ unsigned int sampling_rate;
+
+ dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt1017->sdw_slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ /* port 1 for playback */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ port = 1;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ port = 2;
+ }
+
+ num_channels = params_channels(params);
+ ch_mask = (1 << num_channels) - 1;
+
+ stream_config.frame_rate = params_rate(params);
+ stream_config.ch_count = num_channels;
+ stream_config.bps = snd_pcm_format_width(params_format(params));
+ stream_config.direction = direction;
+
+ port_config.ch_mask = ch_mask;
+ port_config.num = port;
+
+ dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n",
+ params_rate(params), num_channels, snd_pcm_format_width(params_format(params)),
+ direction, ch_mask, port);
+
+ retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "Unable to configure port\n");
+ return retval;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 44100:
+ sampling_rate = RT1017_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT1017_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT1017_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT1017_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "Rate %d is not supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ regmap_write(rt1017->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0),
+ sampling_rate);
+
+ return 0;
+}
+
+static int rt1017_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt1017->sdw_slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt1017->sdw_slave, sdw_stream);
+ return 0;
+}
+
+static const struct snd_soc_dai_ops rt1017_sdca_ops = {
+ .hw_params = rt1017_sdca_pcm_hw_params,
+ .hw_free = rt1017_sdca_pcm_hw_free,
+ .set_stream = rt1017_sdca_set_sdw_stream,
+ .shutdown = rt1017_sdca_shutdown,
+};
+
+#define RT1017_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1017_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver rt1017_sdca_dai[] = {
+ {
+ .name = "rt1017-aif",
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = RT1017_STEREO_RATES,
+ .formats = RT1017_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP2 Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = RT1017_STEREO_RATES,
+ .formats = RT1017_FORMATS,
+ },
+ .ops = &rt1017_sdca_ops,
+ },
+};
+
+static int rt1017_sdca_init(struct device *dev, struct regmap *regmap,
+ struct sdw_slave *slave)
+{
+ struct rt1017_sdca_priv *rt1017;
+ int ret;
+
+ rt1017 = devm_kzalloc(dev, sizeof(*rt1017), GFP_KERNEL);
+ if (!rt1017)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt1017);
+ rt1017->sdw_slave = slave;
+ rt1017->regmap = regmap;
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt1017->hw_init = false;
+ rt1017->first_hw_init = false;
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_component_rt1017,
+ rt1017_sdca_dai,
+ ARRAY_SIZE(rt1017_sdca_dai));
+
+ return ret;
+}
+
+static int rt1017_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw(slave, &rt1017_sdca_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt1017_sdca_init(&slave->dev, regmap, slave);
+}
+
+static int rt1017_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev);
+
+ if (rt1017->first_hw_init)
+ pm_runtime_disable(&slave->dev);
+
+ return 0;
+}
+
+static const struct sdw_device_id rt1017_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x1017, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id);
+
+static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev)
+{
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+
+ if (!rt1017->hw_init)
+ return 0;
+
+ regcache_cache_only(rt1017->regmap, true);
+
+ return 0;
+}
+
+#define RT1017_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+ unsigned long time;
+
+ if (!rt1017->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request)
+ goto regmap_sync;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(RT1017_PROBE_TIMEOUT));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete, timed out\n");
+ sdw_show_ping_status(slave->bus, true);
+
+ return -ETIMEDOUT;
+ }
+
+regmap_sync:
+ slave->unattach_request = 0;
+ regcache_cache_only(rt1017->regmap, false);
+ regcache_sync(rt1017->regmap);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt1017_sdca_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume)
+ SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1017_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt1017-sdca",
+ .owner = THIS_MODULE,
+ .pm = &rt1017_sdca_pm,
+ },
+ .probe = rt1017_sdca_sdw_probe,
+ .remove = rt1017_sdca_sdw_remove,
+ .ops = &rt1017_sdca_slave_ops,
+ .id_table = rt1017_sdca_id,
+};
+module_sdw_driver(rt1017_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1017 driver SDCA SDW");
+MODULE_AUTHOR("Derek Fang <derek.fang@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h
new file mode 100644
index 000000000000..4932b5dbe3c0
--- /dev/null
+++ b/sound/soc/codecs/rt1017-sdca-sdw.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1017-sdca-sdw.h -- RT1017 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1017_SDW_H__
+#define __RT1017_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* RT1017 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1017 SDCA entity */
+#define RT1017_SDCA_ENT_PDE23 0x31
+#define RT1017_SDCA_ENT_PDE22 0x33
+#define RT1017_SDCA_ENT_CS21 0x21
+#define RT1017_SDCA_ENT_SAPU29 0x29
+#define RT1017_SDCA_ENT_XU22 0x22
+#define RT1017_SDCA_ENT_FU 0x03
+#define RT1017_SDCA_ENT_UDMPU21 0x02
+
+/* RT1017 SDCA control */
+#define RT1017_SDCA_CTL_FS_INDEX 0x10
+#define RT1017_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1017_SDCA_CTL_PROT_STAT 0x11
+#define RT1017_SDCA_CTL_BYPASS 0x01
+#define RT1017_SDCA_CTL_FU_MUTE 0x01
+#define RT1017_SDCA_CTL_FU_VOLUME 0x02
+#define RT1017_SDCA_CTL_UDMPU_CLUSTER 0x10
+
+
+#define RT1017_CLASSD_INT_1 0xd300
+#define RT1017_PWM_TRIM_1 0xd370
+
+
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_MASK (0x3 << 2)
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_EFUSE (0x2 << 2)
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_REG (0x0 << 2)
+
+enum {
+ RT1017_SDCA_RATE_44100HZ = 0x8,
+ RT1017_SDCA_RATE_48000HZ = 0x9,
+ RT1017_SDCA_RATE_96000HZ = 0xb,
+ RT1017_SDCA_RATE_192000HZ = 0xd,
+};
+
+struct rt1017_sdca_priv {
+ struct snd_soc_component *component;
+ struct regmap *regmap;
+ struct sdw_slave *sdw_slave;
+ struct sdw_bus_params params;
+ bool hw_init;
+ bool first_hw_init;
+};
+
+static const struct reg_default rt1017_sdca_reg_defaults[] = {
+ { 0x3206, 0x00 },
+ { 0xc001, 0x43 },
+ { 0xc030, 0x54 },
+ { 0xc104, 0x8a },
+ { 0xc10b, 0x2f },
+ { 0xc10c, 0x2f },
+ { 0xc110, 0x49 },
+ { 0xc112, 0x10 },
+ { 0xc300, 0xff },
+ { 0xc301, 0xdd },
+ { 0xc318, 0x40 },
+ { 0xc325, 0x00 },
+ { 0xc326, 0x00 },
+ { 0xc327, 0x00 },
+ { 0xc328, 0x02 },
+ { 0xc331, 0xb2 },
+ { 0xc340, 0x02 },
+ { 0xc350, 0x21 },
+ { 0xc500, 0x00 },
+ { 0xc502, 0x00 },
+ { 0xc504, 0x3f },
+ { 0xc507, 0x1f },
+ { 0xc509, 0x1f },
+ { 0xc510, 0x40 },
+ { 0xc512, 0x00 },
+ { 0xc518, 0x02 },
+ { 0xc51b, 0x7f },
+ { 0xc51d, 0x0f },
+ { 0xc520, 0x00 },
+ { 0xc540, 0x80 },
+ { 0xc541, 0x00 },
+ { 0xc542, 0x0a },
+ { 0xc550, 0x80 },
+ { 0xc551, 0x0f },
+ { 0xc552, 0xff },
+ { 0xc600, 0x10 },
+ { 0xc602, 0x83 },
+ { 0xc612, 0x40 },
+ { 0xc622, 0x40 },
+ { 0xc632, 0x40 },
+ { 0xc642, 0x40 },
+ { 0xc651, 0x00 },
+ { 0xca00, 0xc1 },
+ { 0xca09, 0x00 },
+ { 0xca0a, 0x51 },
+ { 0xca0b, 0xeb },
+ { 0xca0c, 0x85 },
+ { 0xca0e, 0x00 },
+ { 0xca0f, 0x10 },
+ { 0xca10, 0x62 },
+ { 0xca11, 0x4d },
+ { 0xca16, 0x0f },
+ { 0xca17, 0x00 },
+ { 0xcb00, 0x10 },
+ { 0xcc00, 0x10 },
+ { 0xcc02, 0x0b },
+ { 0xd017, 0x09 },
+ { 0xd01a, 0x00 },
+ { 0xd01b, 0x00 },
+ { 0xd01c, 0x00 },
+ { 0xd101, 0xa0 },
+ { 0xd20c, 0x14 },
+ { 0xd300, 0x0f },
+ { 0xd370, 0x18 },
+ { 0xd500, 0x00 },
+ { 0xd545, 0x0b },
+ { 0xd546, 0xf9 },
+ { 0xd547, 0xb2 },
+ { 0xd548, 0xa9 },
+ { 0xd5a5, 0x00 },
+ { 0xd5a6, 0x00 },
+ { 0xd5a7, 0x00 },
+ { 0xd5a8, 0x00 },
+ { 0xd5aa, 0x00 },
+ { 0xd5ab, 0x00 },
+ { 0xd5ac, 0x00 },
+ { 0xd5ad, 0x00 },
+ { 0xda04, 0x03 },
+ { 0xda05, 0x33 },
+ { 0xda06, 0x33 },
+ { 0xda07, 0x33 },
+ { 0xda09, 0x5d },
+ { 0xda0a, 0xc0 },
+ { 0xda0c, 0x00 },
+ { 0xda0d, 0x01 },
+ { 0xda0e, 0x5d },
+ { 0xda0f, 0x86 },
+ { 0xda11, 0x20 },
+ { 0xda12, 0x00 },
+ { 0xda13, 0x00 },
+ { 0xda14, 0x00 },
+ { 0xda16, 0x7f },
+ { 0xda17, 0xff },
+ { 0xda18, 0xff },
+ { 0xda19, 0xff },
+ { 0xdab6, 0x00 },
+ { 0xdab7, 0x01 },
+ { 0xdab8, 0x00 },
+ { 0xdab9, 0x01 },
+ { 0xdaba, 0x00 },
+ { 0xdabb, 0x01 },
+ { 0xdb09, 0x0f },
+ { 0xdb0a, 0xff },
+ { 0xdb14, 0x00 },
+
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
+ RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
+ RT1017_SDCA_CTL_BYPASS, 0), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
+ RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+#endif /* __RT1017_SDW_H__ */
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
index fd55049920c1..ceb8baa6a20d 100644
--- a/sound/soc/codecs/rt1019.c
+++ b/sound/soc/codecs/rt1019.c
@@ -18,7 +18,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
index 59895131e6e0..80888cbcf49c 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -12,10 +12,8 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
#include <sound/core.h>
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index e566c8ddd3e9..63d4abf964d4 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -219,28 +219,17 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
if (rt1308->hw_init)
return 0;
- if (rt1308->first_hw_init) {
- regcache_cache_only(rt1308->regmap, false);
+ regcache_cache_only(rt1308->regmap, false);
+ if (rt1308->first_hw_init)
regcache_cache_bypass(rt1308->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt1308->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt1308->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag);
@@ -637,6 +626,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component)
rt1308->component = component;
rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
+ if (!rt1308->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -699,6 +691,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
rt1308->sdw_slave = slave;
rt1308->regmap = regmap;
+ regcache_cache_only(rt1308->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -710,10 +704,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
&soc_component_sdw_rt1308,
rt1308_sdw_dai,
ARRAY_SIZE(rt1308_sdw_dai));
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
static int rt1308_sdw_probe(struct sdw_slave *slave,
@@ -726,17 +737,12 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt1308_sdw_init(&slave->dev, regmap, slave);
-
- return 0;
+ return rt1308_sdw_init(&slave->dev, regmap, slave);
}
static int rt1308_sdw_remove(struct sdw_slave *slave)
{
- struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
-
- if (rt1308->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c
index 9d07756cda40..86afb429d423 100644
--- a/sound/soc/codecs/rt1308.c
+++ b/sound/soc/codecs/rt1308.c
@@ -11,10 +11,8 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
-#include <linux/of_gpio.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 721821d9e9af..47511f70119a 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -272,25 +272,16 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
if (rt1316->hw_init)
return 0;
+ regcache_cache_only(rt1316->regmap, false);
if (rt1316->first_hw_init) {
- regcache_cache_only(rt1316->regmap, false);
regcache_cache_bypass(rt1316->regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -424,6 +415,15 @@ static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum,
SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
rt1316_rx_data_ch_select);
+static const char * const rt1316_dac_output_vol_select[] = {
+ "immediately",
+ "zero crossing",
+ "zero crossing with soft ramp",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1316_dac_vol_ctl_enum,
+ 0xc010, 6, rt1316_dac_output_vol_select);
+
static const struct snd_kcontrol_new rt1316_snd_controls[] = {
/* I2S Data Channel Selection */
@@ -442,6 +442,9 @@ static const struct snd_kcontrol_new rt1316_snd_controls[] = {
/* IV mixer Control */
SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1),
SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1),
+
+ /* DAC Output Volume Control */
+ SOC_ENUM("DAC Output Vol Control", rt1316_dac_vol_ctl_enum),
};
static const struct snd_kcontrol_new rt1316_sto_dac =
@@ -595,6 +598,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component)
rt1316->component = component;
rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
+ if (!rt1316->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -662,6 +668,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
rt1316->sdw_slave = slave;
rt1316->regmap = regmap;
+ regcache_cache_only(rt1316->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -673,10 +681,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
&soc_component_sdw_rt1316,
rt1316_sdw_dai,
ARRAY_SIZE(rt1316_sdw_dai));
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
static int rt1316_sdw_probe(struct sdw_slave *slave,
@@ -694,10 +719,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
static int rt1316_sdw_remove(struct sdw_slave *slave)
{
- struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
-
- if (rt1316->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index 16d750102c8c..ff364bde4a08 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -408,25 +408,15 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
if (rt1318->hw_init)
return 0;
+ regcache_cache_only(rt1318->regmap, false);
if (rt1318->first_hw_init) {
- regcache_cache_only(rt1318->regmap, false);
regcache_cache_bypass(rt1318->regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
-
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -686,6 +676,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component)
rt1318->component = component;
+ if (!rt1318->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
if (ret < 0 && ret != -EACCES)
@@ -752,6 +745,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
rt1318->sdw_slave = slave;
rt1318->regmap = regmap;
+ regcache_cache_only(rt1318->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -763,8 +758,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
&soc_component_sdw_rt1318,
rt1318_sdw_dai,
ARRAY_SIZE(rt1318_sdw_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
- dev_dbg(&slave->dev, "%s\n", __func__);
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -784,10 +796,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave,
static int rt1318_sdw_remove(struct sdw_slave *slave)
{
- struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
-
- if (rt1318->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 362663abcb89..3ee6d85268ba 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index b3aac2373357..43fc7814fdde 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -17,7 +17,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index eceed8209787..15e1a62b9e57 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -12,11 +12,10 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
@@ -2571,7 +2570,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"rt5640", rt5640);
if (ret) {
- dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
+ dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
rt5640_disable_jack_detect(component);
return;
}
@@ -2626,7 +2625,7 @@ static void rt5640_enable_hda_jack_detect(
NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"rt5640", rt5640);
if (ret) {
- dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
+ dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
rt5640->irq = -ENXIO;
return;
}
@@ -2812,8 +2811,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
rt5640_reset(component);
regcache_cache_only(rt5640->regmap, true);
regcache_mark_dirty(rt5640->regmap);
- if (gpio_is_valid(rt5640->ldo1_en))
- gpio_set_value_cansleep(rt5640->ldo1_en, 0);
+ if (rt5640->ldo1_en)
+ gpiod_set_value_cansleep(rt5640->ldo1_en, 0);
return 0;
}
@@ -2822,8 +2821,8 @@ static int rt5640_resume(struct snd_soc_component *component)
{
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
- if (gpio_is_valid(rt5640->ldo1_en)) {
- gpio_set_value_cansleep(rt5640->ldo1_en, 1);
+ if (rt5640->ldo1_en) {
+ gpiod_set_value_cansleep(rt5640->ldo1_en, 1);
msleep(400);
}
@@ -2986,22 +2985,6 @@ static const struct acpi_device_id rt5640_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
#endif
-static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
-{
- rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
- /*
- * LDO1_EN is optional (it may be statically tied on the board).
- * -ENOENT means that the property doesn't exist, i.e. there is no
- * GPIO, so is not an error. Any other error code means the property
- * exists, but could not be parsed.
- */
- if (!gpio_is_valid(rt5640->ldo1_en) &&
- (rt5640->ldo1_en != -ENOENT))
- return rt5640->ldo1_en;
-
- return 0;
-}
-
static int rt5640_i2c_probe(struct i2c_client *i2c)
{
struct rt5640_priv *rt5640;
@@ -3015,12 +2998,16 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
return -ENOMEM;
i2c_set_clientdata(i2c, rt5640);
- if (i2c->dev.of_node) {
- ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
- if (ret)
- return ret;
- } else
- rt5640->ldo1_en = -EINVAL;
+ rt5640->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5640->ldo1_en))
+ return PTR_ERR(rt5640->ldo1_en);
+
+ if (rt5640->ldo1_en) {
+ gpiod_set_consumer_name(rt5640->ldo1_en, "RT5640 LDO1_EN");
+ msleep(400);
+ }
rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
if (IS_ERR(rt5640->regmap)) {
@@ -3030,18 +3017,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5640->ldo1_en)) {
- ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
- GPIOF_OUT_INIT_HIGH,
- "RT5640 LDO1_EN");
- if (ret < 0) {
- dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
- rt5640->ldo1_en, ret);
- return ret;
- }
- msleep(400);
- }
-
regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
if (val != RT5640_DEVICE_ID) {
dev_err(&i2c->dev,
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index 9847a1ae01f4..94b9a502f7f9 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -2138,7 +2138,7 @@ struct rt5640_priv {
struct regmap *regmap;
struct clk *mclk;
- int ldo1_en; /* GPIO for LDO1_EN */
+ struct gpio_desc *ldo1_en; /* GPIO for LDO1_EN */
int irq;
int jd_gpio_irq;
int sysclk;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 5be5ec0260e9..038d93e20883 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -14,7 +14,6 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
@@ -81,6 +80,7 @@ static const struct reg_sequence init_list[] = {
static const struct reg_sequence rt5650_init_list[] = {
{0xf6, 0x0100},
+ {RT5645_PWR_ANLG1, 0x02},
};
static const struct reg_default rt5645_reg[] = {
@@ -1697,6 +1697,9 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
regmap_write(rt5645->regmap, RT5645_PR_BASE +
RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
+ snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R);
msleep(90);
} else {
/* depop parameters */
@@ -1744,7 +1747,8 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
msleep(100);
snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001);
-
+ snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+ RT5645_PWR_HP_L | RT5645_PWR_HP_R, 0);
} else {
snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
RT5645_HP_SG_MASK |
@@ -3151,7 +3155,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
unsigned int val;
if (jack_insert) {
- regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0206);
/* for jack type detect */
snd_soc_dapm_force_enable_pin(dapm, "LDO2");
@@ -3196,6 +3200,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
if (rt5645->pdata.level_trigger_irq)
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+
+ regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
} else { /* jack out */
rt5645->jack_type = 0;
@@ -4004,13 +4010,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080);
- ret = regmap_register_patch(rt5645->regmap, init_list,
+ ret = regmap_multi_reg_write(rt5645->regmap, init_list,
ARRAY_SIZE(init_list));
if (ret != 0)
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
if (rt5645->codec_type == CODEC_TYPE_RT5650) {
- ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+ ret = regmap_multi_reg_write(rt5645->regmap, rt5650_init_list,
ARRAY_SIZE(rt5650_init_list));
if (ret != 0)
dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
@@ -4221,8 +4227,7 @@ static int __maybe_unused rt5645_sys_resume(struct device *dev)
if (rt5645->hp_jack) {
rt5645->jack_type = 0;
- queue_delayed_work(system_power_efficient_wq,
- &rt5645->jack_detect_work, msecs_to_jiffies(0));
+ rt5645_jack_detect_work(&rt5645->jack_detect_work.work);
}
return 0;
}
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index df6f0d769bbd..a061028a16d8 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index eade087b2d8b..0cecfd602415 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -11,11 +11,9 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 525713c33d71..a39de4a7df00 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
@@ -4659,9 +4658,6 @@ static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev)
of_property_read_u32(dev->of_node, "realtek,jd-src",
&rt5665->pdata.jd_src);
- rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
return 0;
}
@@ -4795,10 +4791,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5665"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+
+ rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5665->gpiod_ldo1_en)) {
+ dev_err(&i2c->dev, "Failed gpio request ldo1_en\n");
+ return PTR_ERR(rt5665->gpiod_ldo1_en);
}
/* Sleep for 300 ms miniumum */
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index f04c810fd710..4623b3e62487 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
@@ -43,6 +42,7 @@ static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = {
struct rt5668_priv {
struct snd_soc_component *component;
struct rt5668_platform_data pdata;
+ struct gpio_desc *ldo1_en;
struct regmap *regmap;
struct snd_soc_jack *hs_jack;
struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES];
@@ -2393,9 +2393,6 @@ static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev)
of_property_read_u32(dev->of_node, "realtek,jd-src",
&rt5668->pdata.jd_src);
- rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
return 0;
}
@@ -2497,10 +2494,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5668->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5668"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+ rt5668->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5668->ldo1_en)) {
+ dev_err(&i2c->dev, "Fail gpio request ldo1_en\n");
+ return PTR_ERR(rt5668->ldo1_en);
}
/* Sleep for 300 ms miniumum */
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index fb8ffb5b2ff6..b05b4f73d8aa 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -170,11 +169,9 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5682"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
- }
+ ret = rt5682_get_ldo1(rt5682, &i2c->dev);
+ if (ret)
+ return ret;
/* Sleep for 300 ms miniumum */
usleep_range(300000, 350000);
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index 4968a8c0064d..e67c2e19cb1a 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -12,8 +12,6 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
@@ -322,6 +320,14 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
return ret;
}
+
+ ret = rt5682_get_ldo1(rt5682, dev);
+ if (ret)
+ return ret;
+
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -336,7 +342,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
ret = devm_snd_soc_register_component(dev,
&rt5682_soc_component_dev,
rt5682_dai, ARRAY_SIZE(rt5682_dai));
- dev_dbg(&slave->dev, "%s\n", __func__);
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -352,30 +376,20 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
if (rt5682->hw_init)
return 0;
+ regcache_cache_only(rt5682->sdw_regmap, false);
+ regcache_cache_only(rt5682->regmap, false);
+ if (rt5682->first_hw_init)
+ regcache_cache_bypass(rt5682->regmap, true);
+
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt5682->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt5682->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
- if (rt5682->first_hw_init) {
- regcache_cache_only(rt5682->regmap, false);
- regcache_cache_bypass(rt5682->regmap, true);
- }
-
while (loop > 0) {
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
if (val == DEVICE_ID)
@@ -674,9 +688,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return -EINVAL;
- rt5682_sdw_init(&slave->dev, regmap, slave);
-
- return 0;
+ return rt5682_sdw_init(&slave->dev, regmap, slave);
}
static int rt5682_sdw_remove(struct sdw_slave *slave)
@@ -686,8 +698,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
if (rt5682->hw_init)
cancel_delayed_work_sync(&rt5682->jack_detect_work);
- if (rt5682->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
@@ -707,6 +718,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
cancel_delayed_work_sync(&rt5682->jack_detect_work);
+ regcache_cache_only(rt5682->sdw_regmap, true);
regcache_cache_only(rt5682->regmap, true);
regcache_mark_dirty(rt5682->regmap);
@@ -771,6 +783,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
regmap_sync:
slave->unattach_request = 0;
+ regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);
regcache_sync(rt5682->regmap);
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 5d992543b791..e3aca9c785a0 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -1017,6 +1016,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
rt5682->hs_jack = hs_jack;
+ if (rt5682->is_sdw && !rt5682->first_hw_init)
+ return 0;
+
if (!hs_jack) {
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
@@ -3091,9 +3093,6 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
device_property_read_u32(dev, "realtek,dmic-delay-ms",
&rt5682->pdata.dmic_delay);
- rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
if (device_property_read_string_array(dev, "clock-output-names",
rt5682->pdata.dai_clk_names,
RT5682_DAI_NUM_CLKS) < 0)
@@ -3108,6 +3107,20 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
}
EXPORT_SYMBOL_GPL(rt5682_parse_dt);
+int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev)
+{
+ rt5682->ldo1_en = devm_gpiod_get_optional(dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5682->ldo1_en)) {
+ dev_err(dev, "Fail gpio request ldo1_en\n");
+ return PTR_ERR(rt5682->ldo1_en);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5682_get_ldo1);
+
void rt5682_calibrate(struct rt5682_priv *rt5682)
{
int value, count;
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index 1a43d595f341..b2d9e87af259 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -11,6 +11,7 @@
#include <sound/rt5682.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -1430,6 +1431,7 @@ struct rt5682_priv {
struct snd_soc_component *component;
struct device *i2c_dev;
struct rt5682_platform_data pdata;
+ struct gpio_desc *ldo1_en;
struct regmap *regmap;
struct regmap *sdw_regmap;
struct snd_soc_jack *hs_jack;
@@ -1481,6 +1483,7 @@ int rt5682_register_component(struct device *dev);
void rt5682_calibrate(struct rt5682_priv *rt5682);
void rt5682_reset(struct rt5682_priv *rt5682);
int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev);
+int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev);
int rt5682_register_dai_clks(struct rt5682_priv *rt5682);
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index c77c675bd5f5..68ac5ea50396 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -15,8 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -2973,9 +2972,6 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev)
device_property_read_u32(dev, "realtek,amic-delay-ms",
&rt5682s->pdata.amic_delay);
- rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
- "realtek,ldo1-en-gpios", 0);
-
if (device_property_read_string_array(dev, "clock-output-names",
rt5682s->pdata.dai_clk_names,
RT5682S_DAI_NUM_CLKS) < 0)
@@ -3172,10 +3168,12 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (gpio_is_valid(rt5682s->pdata.ldo1_en)) {
- if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en,
- GPIOF_OUT_INIT_HIGH, "rt5682s"))
- dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+ rt5682s->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+ "realtek,ldo1-en",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(rt5682s->ldo1_en)) {
+ dev_err(&i2c->dev, "Fail gpio request ldo1_en\n");
+ return PTR_ERR(rt5682s->ldo1_en);
}
/* Sleep for 50 ms minimum */
diff --git a/sound/soc/codecs/rt5682s.h b/sound/soc/codecs/rt5682s.h
index caa7733b430f..1d79d432d0d8 100644
--- a/sound/soc/codecs/rt5682s.h
+++ b/sound/soc/codecs/rt5682s.h
@@ -11,6 +11,7 @@
#include <sound/rt5682s.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -1446,6 +1447,7 @@ enum {
struct rt5682s_priv {
struct snd_soc_component *component;
struct rt5682s_platform_data pdata;
+ struct gpio_desc *ldo1_en;
struct regmap *regmap;
struct snd_soc_jack *hs_jack;
struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES];
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 8b28e47775cc..52c33d56b143 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt700_init(&slave->dev, sdw_regmap, regmap, slave);
-
- return 0;
+ return rt700_init(&slave->dev, sdw_regmap, regmap, slave);
}
static int rt700_sdw_remove(struct sdw_slave *slave)
@@ -466,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
cancel_delayed_work_sync(&rt700->jack_btn_check_work);
}
- if (rt700->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c
index a04b9246256b..0ebf344a1b60 100644
--- a/sound/soc/codecs/rt700.c
+++ b/sound/soc/codecs/rt700.c
@@ -320,6 +320,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
rt700->hs_jack = hs_jack;
+ /* we can only resume if the device was initialized at least once */
+ if (!rt700->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -823,6 +827,9 @@ static int rt700_probe(struct snd_soc_component *component)
rt700->component = component;
+ if (!rt700->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -1099,6 +1106,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
rt700->sdw_regmap = sdw_regmap;
rt700->regmap = regmap;
+ regcache_cache_only(rt700->regmap, true);
+
mutex_init(&rt700->disable_irq_lock);
INIT_DELAYED_WORK(&rt700->jack_detect_work,
@@ -1117,10 +1126,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
&soc_codec_dev_rt700,
rt700_dai,
ARRAY_SIZE(rt700_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
dev_dbg(&slave->dev, "%s\n", __func__);
- return ret;
+ return 0;
}
int rt700_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1132,28 +1157,17 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
if (rt700->hw_init)
return 0;
- if (rt700->first_hw_init) {
- regcache_cache_only(rt700->regmap, false);
+ regcache_cache_only(rt700->regmap, false);
+ if (rt700->first_hw_init)
regcache_cache_bypass(rt700->regmap, true);
- }
/*
* PM runtime is only enabled when a Slave reports as Attached
*/
- if (!rt700->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
- /* update count of parent 'active' children */
+ if (!rt700->first_hw_init)
+ /* PM runtime status is marked as 'active' only when a Slave reports as Attached */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
/* reset */
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index 23f23f714b39..935e597022d3 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -366,8 +366,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
cancel_delayed_work_sync(&rt711->jack_btn_check_work);
}
- if (rt711->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
mutex_destroy(&rt711->calibrate_mutex);
mutex_destroy(&rt711->disable_irq_lock);
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 07640d2f6e56..447154cb6010 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -507,6 +507,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
rt711->hs_jack = hs_jack;
+ /* we can only resume if the device was initialized at least once */
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -1215,6 +1219,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
rt711_sdca_parse_dt(rt711, &rt711->slave->dev);
rt711->component = component;
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -1406,6 +1413,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
rt711->regmap = regmap;
rt711->mbq_regmap = mbq_regmap;
+ regcache_cache_only(rt711->regmap, true);
+ regcache_cache_only(rt711->mbq_regmap, true);
+
mutex_init(&rt711->calibrate_mutex);
mutex_init(&rt711->disable_irq_lock);
@@ -1431,9 +1441,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
rt711_sdca_dai,
ARRAY_SIZE(rt711_sdca_dai));
- dev_dbg(&slave->dev, "%s\n", __func__);
+ if (ret < 0)
+ return ret;
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711)
@@ -1500,27 +1528,19 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt711->hw_init)
return 0;
+ regcache_cache_only(rt711->regmap, false);
+ regcache_cache_only(rt711->mbq_regmap, false);
+
if (rt711->first_hw_init) {
- regcache_cache_only(rt711->regmap, false);
regcache_cache_bypass(rt711->regmap, true);
- regcache_cache_only(rt711->mbq_regmap, false);
regcache_cache_bypass(rt711->mbq_regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index 33dced388f9e..3f5773310ae8 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -453,9 +453,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt711_init(&slave->dev, sdw_regmap, regmap, slave);
-
- return 0;
+ return rt711_init(&slave->dev, sdw_regmap, regmap, slave);
}
static int rt711_sdw_remove(struct sdw_slave *slave)
@@ -468,8 +466,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
cancel_work_sync(&rt711->calibration_work);
}
- if (rt711->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
mutex_destroy(&rt711->calibrate_mutex);
mutex_destroy(&rt711->disable_irq_lock);
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index af53cbcc7bf2..66eaed13b0d6 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -462,6 +462,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
rt711->hs_jack = hs_jack;
+ /* we can only resume if the device was initialized at least once */
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -941,6 +945,9 @@ static int rt711_probe(struct snd_soc_component *component)
rt711_parse_dt(rt711, &rt711->slave->dev);
rt711->component = component;
+ if (!rt711->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -1183,6 +1190,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
rt711->sdw_regmap = sdw_regmap;
rt711->regmap = regmap;
+ regcache_cache_only(rt711->regmap, true);
+
mutex_init(&rt711->calibrate_mutex);
mutex_init(&rt711->disable_irq_lock);
@@ -1204,8 +1213,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
&soc_codec_dev_rt711,
rt711_dai,
ARRAY_SIZE(rt711_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -1219,28 +1245,17 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
if (rt711->hw_init)
return 0;
- if (rt711->first_hw_init) {
- regcache_cache_only(rt711->regmap, false);
+ regcache_cache_only(rt711->regmap, false);
+ if (rt711->first_hw_init)
regcache_cache_bypass(rt711->regmap, true);
- }
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt711->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt711->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
rt711_reset(rt711->regmap);
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 869cc7bfd178..ba08d03e717c 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -182,27 +182,18 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave)
if (rt712->hw_init)
return 0;
+ regcache_cache_only(rt712->regmap, false);
+ regcache_cache_only(rt712->mbq_regmap, false);
if (rt712->first_hw_init) {
- regcache_cache_only(rt712->regmap, false);
regcache_cache_bypass(rt712->regmap, true);
- regcache_cache_only(rt712->mbq_regmap, false);
regcache_cache_bypass(rt712->mbq_regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
@@ -608,6 +599,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
rt712->component = component;
+ if (!rt712->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -777,6 +771,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
rt712->regmap = regmap;
rt712->mbq_regmap = mbq_regmap;
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -791,10 +788,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
&soc_sdca_dev_rt712_dmic,
rt712_sdca_dmic_dai,
ARRAY_SIZE(rt712_sdca_dmic_dai));
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
@@ -954,10 +968,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave,
static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave)
{
- struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev);
-
- if (rt712->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 6bc50396a0f6..6b644a89c589 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -363,8 +363,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave)
cancel_delayed_work_sync(&rt712->jack_btn_check_work);
}
- if (rt712->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
mutex_destroy(&rt712->calibrate_mutex);
mutex_destroy(&rt712->disable_irq_lock);
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index 89d245655ca4..7077ff6ba1f4 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -453,6 +453,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
rt712->hs_jack = hs_jack;
+ if (!rt712->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0) {
if (ret != -EACCES) {
@@ -960,6 +963,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
rt712_sdca_parse_dt(rt712, &rt712->slave->dev);
rt712->component = component;
+ if (!rt712->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -1183,6 +1189,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
rt712->regmap = regmap;
rt712->mbq_regmap = mbq_regmap;
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+
mutex_init(&rt712->calibrate_mutex);
mutex_init(&rt712->disable_irq_lock);
@@ -1207,10 +1216,27 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
else
ret = devm_snd_soc_register_component(dev,
&soc_sdca_dev_rt712, rt712_sdca_dai, 1);
+ if (ret < 0)
+ return ret;
- dev_dbg(&slave->dev, "%s\n", __func__);
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
- return ret;
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
}
int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1224,27 +1250,18 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt712->hw_init)
return 0;
+ regcache_cache_only(rt712->regmap, false);
+ regcache_cache_only(rt712->mbq_regmap, false);
if (rt712->first_hw_init) {
- regcache_cache_only(rt712->regmap, false);
regcache_cache_bypass(rt712->regmap, true);
- regcache_cache_only(rt712->mbq_regmap, false);
regcache_cache_bypass(rt712->mbq_regmap, true);
} else {
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
-
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
}
pm_runtime_get_noresume(&slave->dev);
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index df10916bab46..ab54a67a27eb 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
{
- struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
-
- if (rt715->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
index b989f907784b..9fa96fd83d4a 100644
--- a/sound/soc/codecs/rt715-sdca.c
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -761,8 +761,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = {
static int rt715_sdca_probe(struct snd_soc_component *component)
{
+ struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
int ret;
+ if (!rt715->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -977,6 +981,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
rt715->regmap = regmap;
rt715->mbq_regmap = mbq_regmap;
rt715->hw_sdw_ver = slave->id.sdw_version;
+
+ regcache_cache_only(rt715->regmap, true);
+ regcache_cache_only(rt715->mbq_regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -988,6 +996,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
&soc_codec_dev_rt715_sdca,
rt715_sdca_dai,
ARRAY_SIZE(rt715_sdca_dai));
+ if (ret < 0)
+ return ret;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ dev_dbg(dev, "%s\n", __func__);
return ret;
}
@@ -1000,22 +1027,16 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt715->hw_init)
return 0;
+ regcache_cache_only(rt715->regmap, false);
+ regcache_cache_only(rt715->mbq_regmap, false);
+
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
if (!rt715->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
-
rt715->first_hw_init = true;
}
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 6db87442b783..21f37babd148 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -508,17 +508,12 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- rt715_init(&slave->dev, sdw_regmap, regmap, slave);
-
- return 0;
+ return rt715_init(&slave->dev, sdw_regmap, regmap, slave);
}
static int rt715_sdw_remove(struct sdw_slave *slave)
{
- struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
-
- if (rt715->first_hw_init)
- pm_runtime_disable(&slave->dev);
+ pm_runtime_disable(&slave->dev);
return 0;
}
diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c
index 6c2e165dd621..b59230c8fd32 100644
--- a/sound/soc/codecs/rt715.c
+++ b/sound/soc/codecs/rt715.c
@@ -16,14 +16,11 @@
#include <linux/pm_runtime.h>
#include <linux/pm.h>
#include <linux/soundwire/sdw.h>
-#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/gpio/consumer.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -52,6 +49,60 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg,
return ret;
}
+static int rt715_index_write_nid(struct regmap *regmap,
+ unsigned int nid, unsigned int reg, unsigned int value)
+{
+ int ret;
+ unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
+
+ ret = regmap_write(regmap, addr, value);
+ if (ret < 0)
+ pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
+ addr, value, ret);
+
+ return ret;
+}
+
+static int rt715_index_read_nid(struct regmap *regmap,
+ unsigned int nid, unsigned int reg, unsigned int *value)
+{
+ int ret;
+ unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
+
+ *value = 0;
+ ret = regmap_read(regmap, addr, value);
+ if (ret < 0)
+ pr_err("Failed to get private value: %06x => %04x ret=%d\n",
+ addr, *value, ret);
+
+ return ret;
+}
+
+static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid,
+ unsigned int reg, unsigned int mask, unsigned int val)
+{
+ unsigned int tmp, orig;
+ int ret;
+
+ ret = rt715_index_read_nid(regmap, nid, reg, &orig);
+ if (ret < 0)
+ return ret;
+
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+
+ return rt715_index_write_nid(regmap, nid, reg, tmp);
+}
+
+static void rt715_reset(struct regmap *regmap)
+{
+ regmap_write(regmap, RT715_FUNC_RESET, 0);
+ rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS,
+ RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG,
+ RT715_CLEAR_HIDDEN_REG);
+}
+
+
static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h,
unsigned int addr_l, unsigned int val_h,
unsigned int *r_val, unsigned int *l_val)
@@ -740,8 +791,12 @@ static int rt715_set_bias_level(struct snd_soc_component *component,
static int rt715_probe(struct snd_soc_component *component)
{
+ struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
int ret;
+ if (!rt715->first_hw_init)
+ return 0;
+
ret = pm_runtime_resume(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -984,6 +1039,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
rt715->regmap = regmap;
rt715->sdw_regmap = sdw_regmap;
+ regcache_cache_only(rt715->regmap, true);
+
/*
* Mark hw_init to false
* HW init will be performed when device reports present
@@ -995,8 +1052,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
&soc_codec_dev_rt715,
rt715_dai,
ARRAY_SIZE(rt715_dai));
+ if (ret < 0)
+ return ret;
- return ret;
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+
+ /* important note: the device is NOT tagged as 'active' and will remain
+ * 'suspended' until the hardware is enumerated/initialized. This is required
+ * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+ * fail with -EACCESS because of race conditions between card creation and enumeration
+ */
+
+ return 0;
}
int rt715_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1006,25 +1080,19 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave)
if (rt715->hw_init)
return 0;
+ regcache_cache_only(rt715->regmap, false);
+
/*
- * PM runtime is only enabled when a Slave reports as Attached
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
*/
- if (!rt715->first_hw_init) {
- /* set autosuspend parameters */
- pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
- pm_runtime_use_autosuspend(&slave->dev);
-
+ if (!rt715->first_hw_init)
/* update count of parent 'active' children */
pm_runtime_set_active(&slave->dev);
- /* make sure the device does not suspend immediately */
- pm_runtime_mark_last_busy(&slave->dev);
-
- pm_runtime_enable(&slave->dev);
- }
-
pm_runtime_get_noresume(&slave->dev);
+ rt715_reset(rt715->regmap);
+
/* Mute nid=08h/09h */
regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080);
regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080);
diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h
index 12a0ae656d09..6e37bf64e12f 100644
--- a/sound/soc/codecs/rt715.h
+++ b/sound/soc/codecs/rt715.h
@@ -48,6 +48,7 @@ struct rt715_priv {
#define RT715_INLINE_CMD 0x55
/* Index (NID:20h) */
+#define RT715_VD_CLEAR_CTRL 0x01
#define RT715_SDW_INPUT_SEL 0x39
#define RT715_EXT_DMIC_CLK_CTRL2 0x54
@@ -71,6 +72,8 @@ struct rt715_priv {
#define RT715_READ_HDA_0 0x2015
#define RT715_PRIV_INDEX_W_H 0x7520
#define RT715_PRIV_INDEX_W_L 0x85a0
+#define RT715_PRIV_INDEX_W_H_2 0x7500
+#define RT715_PRIV_INDEX_W_L_2 0x8580
#define RT715_PRIV_DATA_W_H 0x7420
#define RT715_PRIV_DATA_W_L 0x84a0
#define RT715_PRIV_INDEX_R_H 0x9d20
@@ -198,6 +201,10 @@ struct rt715_priv {
#define RT715_SET_DMIC4_CONFIG_DEFAULT4\
(RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4)
+/* vendor register clear ctrl-1 (0x01)(NID:20h) */
+#define RT715_CLEAR_HIDDEN_REG (0x1 << 15)
+
+
#define RT715_MUTE_SFT 7
#define RT715_DIR_IN_SFT 6
#define RT715_DIR_OUT_SFT 7
diff --git a/sound/soc/codecs/ssm3515.c b/sound/soc/codecs/ssm3515.c
index 008cb3eb5758..8c6665677a17 100644
--- a/sound/soc/codecs/ssm3515.c
+++ b/sound/soc/codecs/ssm3515.c
@@ -437,7 +437,7 @@ MODULE_DEVICE_TABLE(of, ssm3515_of_match);
static struct i2c_driver ssm3515_i2c_driver = {
.driver = {
.name = "ssm3515",
- .of_match_table = of_match_ptr(ssm3515_of_match),
+ .of_match_table = ssm3515_of_match,
},
.probe = ssm3515_i2c_probe,
};
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 4a694d0bfd68..34ffd32ab9dc 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -1022,7 +1022,7 @@ static const struct regmap_config sta32x_regmap = {
.max_register = STA32X_FDRC2,
.reg_defaults = sta32x_regs,
.num_reg_defaults = ARRAY_SIZE(sta32x_regs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.wr_table = &sta32x_write_regs,
.rd_table = &sta32x_read_regs,
.volatile_table = &sta32x_volatile_regs,
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index d05f3fd57661..e4a9e9241c60 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -1065,7 +1065,7 @@ static const struct regmap_config sta350_regmap = {
.max_register = STA350_MISC2,
.reg_defaults = sta350_regs,
.num_reg_defaults = ARRAY_SIZE(sta350_regs),
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.wr_table = &sta350_write_regs,
.rd_table = &sta350_read_regs,
.volatile_table = &sta350_volatile_regs,
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 0ac08478ddac..eedafef775e5 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -331,7 +331,7 @@ static const struct regmap_config sta529_regmap = {
.max_register = STA529_MAX_REGISTER,
.readable_reg = sta529_readable,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_defaults = sta529_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults),
};
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 1824a71fe053..2f9f10a4dfed 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -67,7 +67,7 @@ static const struct regmap_config stac9766_regmap_config = {
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x78,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = regmap_ac97_default_volatile,
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 99545bcb2ba9..c421906a0694 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -316,7 +316,7 @@ static const struct regmap_config stih407_sas_regmap = {
.reg_defaults = stih407_sas_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
.volatile_reg = sti_sas_volatile_register,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.reg_read = sti_sas_read_reg,
.reg_write = sti_sas_write_reg,
};
diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c
index aca3756ffab6..3b53eba38a0b 100644
--- a/sound/soc/codecs/tas5805m.c
+++ b/sound/soc/codecs/tas5805m.c
@@ -520,12 +520,11 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
}
tas5805m->dsp_cfg_len = fw->size;
- tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL);
+ tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL);
if (!tas5805m->dsp_cfg_data) {
release_firmware(fw);
return -ENOMEM;
}
- memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size);
release_firmware(fw);
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index c116e82f712d..5c0a76a4a106 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -321,7 +321,7 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
u8 divisor;
divisor = DIV_ROUND_UP(parent_rate, rate);
- if (divisor > 128)
+ if (divisor > AIC32X4_DIV_MAX)
return -EINVAL;
return regmap_update_bits(div->regmap, div->reg,
@@ -334,7 +334,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
unsigned long divisor;
divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
- if (divisor > 128)
+ if (divisor > AIC32X4_DIV_MAX)
return -EINVAL;
req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);
@@ -345,12 +345,18 @@ static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-
unsigned int val;
+ int err;
+
+ err = regmap_read(div->regmap, div->reg, &val);
+ if (err)
+ return 0;
- regmap_read(div->regmap, div->reg, &val);
+ val &= AIC32X4_DIV_MASK;
+ if (!val)
+ val = AIC32X4_DIV_MAX;
- return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
+ return DIV_ROUND_UP(parent_rate, val);
}
static const struct clk_ops aic32x4_div_ops = {
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index ffe1828a4b7e..6829834a412f 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -1349,7 +1349,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
return -ENOMEM;
aic32x4->dev = dev;
- aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev);
+ aic32x4->type = (uintptr_t)dev_get_drvdata(dev);
dev_set_drvdata(dev, aic32x4);
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index 4de5bd9e8cc5..d6101ce73f80 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -223,8 +223,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
#define AIC32X4_REFPOWERUP_120MS 0x07
/* Common mask and enable for all of the dividers */
-#define AIC32X4_DIVEN BIT(7)
-#define AIC32X4_DIV_MASK GENMASK(6, 0)
+#define AIC32X4_DIVEN BIT(7)
+#define AIC32X4_DIV_MASK GENMASK(6, 0)
+#define AIC32X4_DIV_MAX 128
/* Clock Limits */
#define AIC32X4_MAX_DOSR_FREQ 6200000
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
deleted file mode 100644
index 1a62bec94005..000000000000
--- a/sound/soc/codecs/uda134x.c
+++ /dev/null
@@ -1,587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * uda134x.c -- UDA134X ALSA SoC Codec driver
- *
- * Modifications by Christian Pellegrin <chripell@evolware.org>
- *
- * Copyright 2007 Dension Audio Systems Ltd.
- * Author: Zoltan Devai
- *
- * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
-
-#include <sound/uda134x.h>
-#include <sound/l3.h>
-
-#include "uda134x.h"
-
-
-#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
-#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
-
-struct uda134x_priv {
- int sysclk;
- int dai_fmt;
-
- struct snd_pcm_substream *master_substream;
- struct snd_pcm_substream *slave_substream;
-
- struct regmap *regmap;
- struct uda134x_platform_data *pd;
-};
-
-static const struct reg_default uda134x_reg_defaults[] = {
- { UDA134X_EA000, 0x04 },
- { UDA134X_EA001, 0x04 },
- { UDA134X_EA010, 0x04 },
- { UDA134X_EA011, 0x00 },
- { UDA134X_EA100, 0x00 },
- { UDA134X_EA101, 0x00 },
- { UDA134X_EA110, 0x00 },
- { UDA134X_EA111, 0x00 },
- { UDA134X_STATUS0, 0x00 },
- { UDA134X_STATUS1, 0x03 },
- { UDA134X_DATA000, 0x00 },
- { UDA134X_DATA001, 0x00 },
- { UDA134X_DATA010, 0x00 },
- { UDA134X_DATA011, 0x00 },
- { UDA134X_DATA1, 0x00 },
-};
-
-/*
- * Write to the uda134x registers
- *
- */
-static int uda134x_regmap_write(void *context, unsigned int reg,
- unsigned int value)
-{
- struct uda134x_platform_data *pd = context;
- int ret;
- u8 addr;
- u8 data = value;
-
- switch (reg) {
- case UDA134X_STATUS0:
- case UDA134X_STATUS1:
- addr = UDA134X_STATUS_ADDR;
- data |= (reg - UDA134X_STATUS0) << 7;
- break;
- case UDA134X_DATA000:
- case UDA134X_DATA001:
- case UDA134X_DATA010:
- case UDA134X_DATA011:
- addr = UDA134X_DATA0_ADDR;
- data |= (reg - UDA134X_DATA000) << 6;
- break;
- case UDA134X_DATA1:
- addr = UDA134X_DATA1_ADDR;
- break;
- default:
- /* It's an extended address register */
- addr = (reg | UDA134X_EXTADDR_PREFIX);
-
- ret = l3_write(&pd->l3,
- UDA134X_DATA0_ADDR, &addr, 1);
- if (ret != 1)
- return -EIO;
-
- addr = UDA134X_DATA0_ADDR;
- data = (value | UDA134X_EXTDATA_PREFIX);
- break;
- }
-
- ret = l3_write(&pd->l3,
- addr, &data, 1);
- if (ret != 1)
- return -EIO;
-
- return 0;
-}
-
-static inline void uda134x_reset(struct snd_soc_component *component)
-{
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- unsigned int mask = 1<<6;
-
- regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask);
- msleep(1);
- regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0);
-}
-
-static int uda134x_mute(struct snd_soc_dai *dai, int mute, int direction)
-{
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(dai->component);
- unsigned int mask = 1<<2;
- unsigned int val;
-
- pr_debug("%s mute: %d\n", __func__, mute);
-
- if (mute)
- val = mask;
- else
- val = 0;
-
- return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val);
-}
-
-static int uda134x_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- struct snd_pcm_runtime *master_runtime;
-
- if (uda134x->master_substream) {
- master_runtime = uda134x->master_substream->runtime;
-
- pr_debug("%s constraining to %d bits at %d\n", __func__,
- master_runtime->sample_bits,
- master_runtime->rate);
-
- snd_pcm_hw_constraint_single(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- master_runtime->rate);
-
- snd_pcm_hw_constraint_single(substream->runtime,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- master_runtime->sample_bits);
-
- uda134x->slave_substream = substream;
- } else
- uda134x->master_substream = substream;
-
- return 0;
-}
-
-static void uda134x_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
-
- if (uda134x->master_substream == substream)
- uda134x->master_substream = uda134x->slave_substream;
-
- uda134x->slave_substream = NULL;
-}
-
-static int uda134x_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_component *component = dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- unsigned int hw_params = 0;
-
- if (substream == uda134x->slave_substream) {
- pr_debug("%s ignoring hw_params for slave substream\n",
- __func__);
- return 0;
- }
-
- pr_debug("%s sysclk: %d, rate:%d\n", __func__,
- uda134x->sysclk, params_rate(params));
-
- /* set SYSCLK / fs ratio */
- switch (uda134x->sysclk / params_rate(params)) {
- case 512:
- break;
- case 384:
- hw_params |= (1<<4);
- break;
- case 256:
- hw_params |= (1<<5);
- break;
- default:
- printk(KERN_ERR "%s unsupported fs\n", __func__);
- return -EINVAL;
- }
-
- pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
- uda134x->dai_fmt, params_format(params));
-
- /* set DAI format and word length */
- switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- break;
- case SND_SOC_DAIFMT_RIGHT_J:
- switch (params_width(params)) {
- case 16:
- hw_params |= (1<<1);
- break;
- case 18:
- hw_params |= (1<<2);
- break;
- case 20:
- hw_params |= ((1<<2) | (1<<1));
- break;
- default:
- printk(KERN_ERR "%s unsupported format (right)\n",
- __func__);
- return -EINVAL;
- }
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- hw_params |= (1<<3);
- break;
- default:
- printk(KERN_ERR "%s unsupported format\n", __func__);
- return -EINVAL;
- }
-
- return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
- STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
-}
-
-static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct snd_soc_component *component = codec_dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
-
- pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
- clk_id, freq, dir);
-
- /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
- because the codec is slave. Of course limitations of the clock
- master (the IIS controller) apply.
- We'll error out on set_hw_params if it's not OK */
- if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
- uda134x->sysclk = freq;
- return 0;
- }
-
- printk(KERN_ERR "%s unsupported sysclk\n", __func__);
- return -EINVAL;
-}
-
-static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
-{
- struct snd_soc_component *component = codec_dai->component;
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
-
- pr_debug("%s fmt: %08X\n", __func__, fmt);
-
- /* codec supports only full consumer mode */
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
- printk(KERN_ERR "%s unsupported clocking mode\n", __func__);
- return -EINVAL;
- }
-
- /* no support for clock inversion */
- if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
- printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
- return -EINVAL;
- }
-
- /* We can't setup DAI format here as it depends on the word bit num */
- /* so let's just store the value for later */
- uda134x->dai_fmt = fmt;
-
- return 0;
-}
-
-static int uda134x_set_bias_level(struct snd_soc_component *component,
- enum snd_soc_bias_level level)
-{
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- struct uda134x_platform_data *pd = uda134x->pd;
- pr_debug("%s bias level %d\n", __func__, level);
-
- switch (level) {
- case SND_SOC_BIAS_ON:
- break;
- case SND_SOC_BIAS_PREPARE:
- /* power on */
- if (pd->power) {
- pd->power(1);
- regcache_sync(uda134x->regmap);
- }
- break;
- case SND_SOC_BIAS_STANDBY:
- break;
- case SND_SOC_BIAS_OFF:
- /* power off */
- if (pd->power) {
- pd->power(0);
- regcache_mark_dirty(uda134x->regmap);
- }
- break;
- }
- return 0;
-}
-
-static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
- "Minimum2", "Maximum"};
-static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
-static const char *uda134x_mixmode[] = {"Differential", "Analog1",
- "Analog2", "Both"};
-
-static const struct soc_enum uda134x_mixer_enum[] = {
-SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
-SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
-SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
-};
-
-static const struct snd_kcontrol_new uda1341_snd_controls[] = {
-SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
-SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
-SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
-SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
-
-SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
-SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
-
-SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
-SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
-
-SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
-SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
-SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
-
-SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
-SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
-SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
-
-SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
-SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
-SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
-SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
-SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
-SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new uda1340_snd_controls[] = {
-SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
-
-SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
-SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
-
-SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
-SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
-
-SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new uda1345_snd_controls[] = {
-SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
-
-SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
-
-SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
-};
-
-/* UDA1341 has the DAC/ADC power down in STATUS1 */
-static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
- SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
-};
-
-/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
-static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
- SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
-};
-
-/* Common DAPM widgets */
-static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
- SND_SOC_DAPM_INPUT("VINL1"),
- SND_SOC_DAPM_INPUT("VINR1"),
- SND_SOC_DAPM_INPUT("VINL2"),
- SND_SOC_DAPM_INPUT("VINR2"),
- SND_SOC_DAPM_OUTPUT("VOUTL"),
- SND_SOC_DAPM_OUTPUT("VOUTR"),
-};
-
-static const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
- { "ADC", NULL, "VINL1" },
- { "ADC", NULL, "VINR1" },
- { "ADC", NULL, "VINL2" },
- { "ADC", NULL, "VINR2" },
- { "VOUTL", NULL, "DAC" },
- { "VOUTR", NULL, "DAC" },
-};
-
-static const struct snd_soc_dai_ops uda134x_dai_ops = {
- .startup = uda134x_startup,
- .shutdown = uda134x_shutdown,
- .hw_params = uda134x_hw_params,
- .mute_stream = uda134x_mute,
- .set_sysclk = uda134x_set_dai_sysclk,
- .set_fmt = uda134x_set_dai_fmt,
- .no_capture_mute = 1,
-};
-
-static struct snd_soc_dai_driver uda134x_dai = {
- .name = "uda134x-hifi",
- /* playback capabilities */
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = UDA134X_RATES,
- .formats = UDA134X_FORMATS,
- },
- /* capture capabilities */
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = UDA134X_RATES,
- .formats = UDA134X_FORMATS,
- },
- /* pcm operations */
- .ops = &uda134x_dai_ops,
-};
-
-static int uda134x_soc_probe(struct snd_soc_component *component)
-{
- struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
- struct uda134x_priv *uda134x = snd_soc_component_get_drvdata(component);
- struct uda134x_platform_data *pd = uda134x->pd;
- const struct snd_soc_dapm_widget *widgets;
- unsigned int num_widgets;
- int ret;
-
- printk(KERN_INFO "UDA134X SoC Audio Codec\n");
-
- switch (pd->model) {
- case UDA134X_UDA1340:
- case UDA134X_UDA1341:
- case UDA134X_UDA1344:
- case UDA134X_UDA1345:
- break;
- default:
- printk(KERN_ERR "UDA134X SoC codec: "
- "unsupported model %d\n",
- pd->model);
- return -EINVAL;
- }
-
- if (pd->power)
- pd->power(1);
-
- uda134x_reset(component);
-
- if (pd->model == UDA134X_UDA1341) {
- widgets = uda1341_dapm_widgets;
- num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
- } else {
- widgets = uda1340_dapm_widgets;
- num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
- }
-
- ret = snd_soc_dapm_new_controls(dapm, widgets, num_widgets);
- if (ret) {
- printk(KERN_ERR "%s failed to register dapm controls: %d",
- __func__, ret);
- return ret;
- }
-
- switch (pd->model) {
- case UDA134X_UDA1340:
- case UDA134X_UDA1344:
- ret = snd_soc_add_component_controls(component, uda1340_snd_controls,
- ARRAY_SIZE(uda1340_snd_controls));
- break;
- case UDA134X_UDA1341:
- ret = snd_soc_add_component_controls(component, uda1341_snd_controls,
- ARRAY_SIZE(uda1341_snd_controls));
- break;
- case UDA134X_UDA1345:
- ret = snd_soc_add_component_controls(component, uda1345_snd_controls,
- ARRAY_SIZE(uda1345_snd_controls));
- break;
- default:
- printk(KERN_ERR "%s unknown codec type: %d",
- __func__, pd->model);
- return -EINVAL;
- }
-
- if (ret < 0) {
- printk(KERN_ERR "UDA134X: failed to register controls\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct snd_soc_component_driver soc_component_dev_uda134x = {
- .probe = uda134x_soc_probe,
- .set_bias_level = uda134x_set_bias_level,
- .dapm_widgets = uda134x_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
- .dapm_routes = uda134x_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
- .suspend_bias_off = 1,
- .idle_bias_on = 1,
- .use_pmdown_time = 1,
- .endianness = 1,
-};
-
-static const struct regmap_config uda134x_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = UDA134X_DATA1,
- .reg_defaults = uda134x_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
-
- .reg_write = uda134x_regmap_write,
-};
-
-static int uda134x_codec_probe(struct platform_device *pdev)
-{
- struct uda134x_platform_data *pd = pdev->dev.platform_data;
- struct uda134x_priv *uda134x;
- int ret;
-
- if (!pd) {
- dev_err(&pdev->dev, "Missing L3 bitbang function\n");
- return -ENODEV;
- }
-
- uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL);
- if (!uda134x)
- return -ENOMEM;
-
- uda134x->pd = pd;
- platform_set_drvdata(pdev, uda134x);
-
- if (pd->l3.use_gpios) {
- ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3);
- if (ret < 0)
- return ret;
- }
-
- uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd,
- &uda134x_regmap_config);
- if (IS_ERR(uda134x->regmap))
- return PTR_ERR(uda134x->regmap);
-
- return devm_snd_soc_register_component(&pdev->dev,
- &soc_component_dev_uda134x, &uda134x_dai, 1);
-}
-
-static struct platform_driver uda134x_codec_driver = {
- .driver = {
- .name = "uda134x-codec",
- },
- .probe = uda134x_codec_probe,
-};
-
-module_platform_driver(uda134x_codec_driver);
-
-MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
-MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
deleted file mode 100644
index 664618c2571c..000000000000
--- a/sound/soc/codecs/uda134x.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _UDA134X_CODEC_H
-#define _UDA134X_CODEC_H
-
-#define UDA134X_L3ADDR 5
-#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0)
-#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1)
-#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2)
-
-#define UDA134X_EXTADDR_PREFIX 0xC0
-#define UDA134X_EXTDATA_PREFIX 0xE0
-
-/* UDA134X registers */
-#define UDA134X_EA000 0
-#define UDA134X_EA001 1
-#define UDA134X_EA010 2
-#define UDA134X_EA011 3
-#define UDA134X_EA100 4
-#define UDA134X_EA101 5
-#define UDA134X_EA110 6
-#define UDA134X_EA111 7
-#define UDA134X_STATUS0 8
-#define UDA134X_STATUS1 9
-#define UDA134X_DATA000 10
-#define UDA134X_DATA001 11
-#define UDA134X_DATA010 12
-#define UDA134X_DATA011 13
-#define UDA134X_DATA1 14
-
-#define STATUS0_DAIFMT_MASK (~(7<<1))
-#define STATUS0_SYSCLK_MASK (~(3<<4))
-
-#endif
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 36cdf97993a5..9679906c6bd5 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1770,11 +1770,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops wm2200_dai_ops = {
- .set_fmt = wm2200_set_fmt,
- .hw_params = wm2200_hw_params,
-};
-
static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id,
int source, unsigned int freq, int dir)
{
@@ -2068,6 +2063,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops wm2200_dai_ops = {
+ .probe = wm2200_dai_probe,
+ .set_fmt = wm2200_set_fmt,
+ .hw_params = wm2200_hw_params,
+};
+
#define WM2200_RATES SNDRV_PCM_RATE_8000_48000
#define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
@@ -2075,7 +2076,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver wm2200_dai = {
.name = "wm2200",
- .probe = wm2200_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 3bdbdf3770b5..4ecf07c7448c 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id,
#define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static const struct snd_soc_dai_ops wm5102_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver wm5102_dai[] = {
{
.name = "wm5102-aif1",
@@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
.rates = WM5102_RATES,
.formats = WM5102_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &wm5102_dai_ops,
},
{
.name = "wm5102-dsp-trace",
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index ad670300de8d..ac1f2c850346 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id,
#define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static const struct snd_soc_dai_ops wm5110_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver wm5110_dai[] = {
{
.name = "wm5110-aif1",
@@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &wm5110_dai_ops,
},
{
.name = "wm5110-dsp-voicectrl",
@@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
- .compress_new = snd_soc_new_compress,
+ .ops = &wm5110_dai_ops,
},
{
.name = "wm5110-dsp-trace",
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 60319b468fb2..829bf055622a 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -2202,7 +2202,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c)
match = of_match_node(wm8904_of_match, i2c->dev.of_node);
if (match == NULL)
return -EINVAL;
- wm8904->devtype = (enum wm8904_type)match->data;
+ wm8904->devtype = (uintptr_t)match->data;
} else {
const struct i2c_device_id *id =
i2c_match_id(wm8904_i2c_id, i2c);
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index c2bd9ef41ebb..0a50180750e8 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -120,6 +120,15 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
}
}
+#define WM8960_NUM_SUPPLIES 5
+static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD",
+ "AVDD",
+ "SPKVDD1",
+ "SPKVDD2",
+};
+
struct wm8960_priv {
struct clk *mclk;
struct regmap *regmap;
@@ -137,6 +146,7 @@ struct wm8960_priv {
bool is_stream_in_use[2];
struct wm8960_data pdata;
ktime_t dsch_start;
+ struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES];
};
#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0)
@@ -1417,6 +1427,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
{
struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
struct wm8960_priv *wm8960;
+ unsigned int i;
int ret;
u8 val;
@@ -1429,6 +1440,31 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
if (IS_ERR(wm8960->mclk)) {
if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
+ } else {
+ ret = clk_get_rate(wm8960->mclk);
+ if (ret >= 0) {
+ wm8960->freq_in = ret;
+ } else {
+ dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n",
+ ret);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++)
+ wm8960->supplies[i].supply = wm8960_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8960->supplies),
+ wm8960->supplies);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies),
+ wm8960->supplies);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
}
wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
@@ -1497,7 +1533,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
}
static void wm8960_i2c_remove(struct i2c_client *client)
-{}
+{
+ struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
+
+ regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies);
+}
static const struct i2c_device_id wm8960_i2c_id[] = {
{ "wm8960", 0 },
diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
index 63ba6c03c488..e8ff33b188e9 100644
--- a/sound/soc/codecs/wm8960.h
+++ b/sound/soc/codecs/wm8960.h
@@ -77,9 +77,9 @@
#define WM8960_SYSCLK_DIV_1 (0 << 1)
#define WM8960_SYSCLK_DIV_2 (2 << 1)
-#define WM8960_SYSCLK_MCLK (0 << 0)
+#define WM8960_SYSCLK_AUTO (0 << 0)
#define WM8960_SYSCLK_PLL (1 << 0)
-#define WM8960_SYSCLK_AUTO (2 << 0)
+#define WM8960_SYSCLK_MCLK (2 << 0)
#define WM8960_DAC_DIV_1 (0 << 3)
#define WM8960_DAC_DIV_1_5 (1 << 3)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index bca3ebe0dac4..a48e904a9740 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -3215,6 +3215,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
};
static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
+ .probe = wm8994_aif2_probe,
.set_sysclk = wm8994_set_dai_sysclk,
.set_fmt = wm8994_set_dai_fmt,
.hw_params = wm8994_hw_params,
@@ -3269,7 +3270,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
.formats = WM8994_FORMATS,
.sig_bits = 24,
},
- .probe = wm8994_aif2_probe,
.ops = &wm8994_aif2_dai_ops,
},
{
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 5a89abfe8784..6fc34f41b175 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -998,7 +998,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
-int wm_adsp_power_up(struct wm_adsp *dsp)
+int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware)
{
int ret = 0;
char *wmfw_filename = NULL;
@@ -1006,11 +1006,13 @@ int wm_adsp_power_up(struct wm_adsp *dsp)
char *coeff_filename = NULL;
const struct firmware *coeff_firmware = NULL;
- ret = wm_adsp_request_firmware_files(dsp,
- &wmfw_firmware, &wmfw_filename,
- &coeff_firmware, &coeff_filename);
- if (ret)
- return ret;
+ if (load_firmware) {
+ ret = wm_adsp_request_firmware_files(dsp,
+ &wmfw_firmware, &wmfw_filename,
+ &coeff_firmware, &coeff_filename);
+ if (ret)
+ return ret;
+ }
ret = cs_dsp_power_up(&dsp->cs_dsp,
wmfw_firmware, wmfw_filename,
@@ -1025,13 +1027,19 @@ int wm_adsp_power_up(struct wm_adsp *dsp)
}
EXPORT_SYMBOL_GPL(wm_adsp_power_up);
+void wm_adsp_power_down(struct wm_adsp *dsp)
+{
+ cs_dsp_power_down(&dsp->cs_dsp);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_power_down);
+
static void wm_adsp_boot_work(struct work_struct *work)
{
struct wm_adsp *dsp = container_of(work,
struct wm_adsp,
boot_work);
- wm_adsp_power_up(dsp);
+ wm_adsp_power_up(dsp, true);
}
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
@@ -1046,7 +1054,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
queue_work(system_unbound_wq, &dsp->boot_work);
break;
case SND_SOC_DAPM_PRE_PMD:
- cs_dsp_power_down(&dsp->cs_dsp);
+ wm_adsp_power_down(dsp);
break;
default:
break;
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 769904d34a87..067d807a7ca8 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -91,7 +91,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
-int wm_adsp_power_up(struct wm_adsp *dsp);
+int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware);
+void wm_adsp_power_down(struct wm_adsp *dsp);
irqreturn_t wm_adsp2_bus_error(int irq, void *data);
irqreturn_t wm_halo_bus_error(int irq, void *data);
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 1f1ee14b04e6..5ab1b3eb2d28 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -198,7 +199,8 @@ static void i2s_start(struct dw_i2s_dev *dev,
else
i2s_write_reg(dev->i2s_base, IRER, 1);
- if (dev->use_pio)
+ /* I2S needs to enable IRQ to make a handshake with DMAC on the JH7110 SoC */
+ if (dev->use_pio || dev->is_jh7110)
i2s_enable_irqs(dev, substream->stream, config->chan_nr);
else
i2s_enable_dma(dev, substream->stream);
@@ -216,7 +218,7 @@ static void i2s_stop(struct dw_i2s_dev *dev,
else
i2s_write_reg(dev->i2s_base, IRER, 0);
- if (dev->use_pio)
+ if (dev->use_pio || dev->is_jh7110)
i2s_disable_irqs(dev, substream->stream, 8);
else
i2s_disable_dma(dev, substream->stream);
@@ -227,6 +229,21 @@ static void i2s_stop(struct dw_i2s_dev *dev,
}
}
+static int dw_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if (dev->is_jh7110) {
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+
+ dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC;
+ }
+
+ return 0;
+}
+
static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
{
u32 ch_reg;
@@ -443,7 +460,17 @@ static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask
return 0;
}
+static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
+ return 0;
+}
+
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
+ .probe = dw_i2s_dai_probe,
+ .startup = dw_i2s_startup,
.hw_params = dw_i2s_hw_params,
.prepare = dw_i2s_prepare,
.trigger = dw_i2s_trigger,
@@ -628,17 +655,39 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
if (dev->quirks & DW_I2S_QUIRK_16BIT_IDX_OVERRIDE)
idx = 1;
- /* Set DMA slaves info */
- dev->play_dma_data.pd.data = pdata->play_dma_data;
- dev->capture_dma_data.pd.data = pdata->capture_dma_data;
- dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
- dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
- dev->play_dma_data.pd.max_burst = 16;
- dev->capture_dma_data.pd.max_burst = 16;
- dev->play_dma_data.pd.addr_width = bus_widths[idx];
- dev->capture_dma_data.pd.addr_width = bus_widths[idx];
- dev->play_dma_data.pd.filter = pdata->filter;
- dev->capture_dma_data.pd.filter = pdata->filter;
+
+ if (dev->is_jh7110) {
+ /* Use platform data and snd_dmaengine_dai_dma_data struct at the same time */
+ u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+ u32 idx2;
+
+ if (COMP1_TX_ENABLED(comp1)) {
+ idx2 = COMP1_TX_WORDSIZE_0(comp1);
+ dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
+ dev->play_dma_data.dt.fifo_size = dev->fifo_th * 2 *
+ (fifo_width[idx2]) >> 8;
+ dev->play_dma_data.dt.maxburst = 16;
+ }
+ if (COMP1_RX_ENABLED(comp1)) {
+ idx2 = COMP2_RX_WORDSIZE_0(comp2);
+ dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
+ dev->capture_dma_data.dt.fifo_size = dev->fifo_th * 2 *
+ (fifo_width[idx2] >> 8);
+ dev->capture_dma_data.dt.maxburst = 16;
+ }
+ } else {
+ /* Set DMA slaves info */
+ dev->play_dma_data.pd.data = pdata->play_dma_data;
+ dev->capture_dma_data.pd.data = pdata->capture_dma_data;
+ dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
+ dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
+ dev->play_dma_data.pd.max_burst = 16;
+ dev->capture_dma_data.pd.max_burst = 16;
+ dev->play_dma_data.pd.addr_width = bus_widths[idx];
+ dev->capture_dma_data.pd.addr_width = bus_widths[idx];
+ dev->play_dma_data.pd.filter = pdata->filter;
+ dev->capture_dma_data.pd.filter = pdata->filter;
+ }
return 0;
}
@@ -680,17 +729,193 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
}
-static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
+/* clocks initialization with master mode on JH7110 SoC */
+static int jh7110_i2s_crg_master_init(struct dw_i2s_dev *dev)
{
- struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ static struct clk_bulk_data clks[] = {
+ { .id = "mclk" },
+ { .id = "mclk_ext" },
+ { .id = "mclk_inner" },
+ { .id = "apb" },
+ { .id = "i2sclk" },
+ };
+ struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev);
+ int ret;
+ struct clk *pclk;
+ struct clk *bclk_mst;
+ struct clk *mclk;
+ struct clk *mclk_ext;
+ struct clk *mclk_inner;
+
+ if (IS_ERR(resets))
+ return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n");
+
+ ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks);
+ if (ret)
+ return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n");
+
+ mclk = clks[0].clk;
+ mclk_ext = clks[1].clk;
+ mclk_inner = clks[2].clk;
+ pclk = clks[3].clk;
+ bclk_mst = clks[4].clk;
+
+ ret = clk_prepare_enable(pclk);
+ if (ret)
+ goto exit;
+
+ /* Use inner mclk first and avoid uninitialized gpio for external mclk */
+ ret = clk_set_parent(mclk, mclk_inner);
+ if (ret)
+ goto err_dis_pclk;
+
+ ret = clk_prepare_enable(bclk_mst);
+ if (ret)
+ goto err_dis_pclk;
+
+ /* deassert resets before set clock parent */
+ ret = reset_control_deassert(resets);
+ if (ret)
+ goto err_dis_all;
+
+ /* external clock (12.288MHz) for Audio */
+ ret = clk_set_parent(mclk, mclk_ext);
+ if (ret)
+ goto err_dis_all;
+
+ /* i2sclk will be got and enabled repeatedly later and should be disabled now. */
+ clk_disable_unprepare(bclk_mst);
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ dev->is_jh7110 = true;
- snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
return 0;
+
+err_dis_all:
+ clk_disable_unprepare(bclk_mst);
+err_dis_pclk:
+ clk_disable_unprepare(pclk);
+exit:
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ return ret;
+}
+
+/* clocks initialization with slave mode on JH7110 SoC */
+static int jh7110_i2s_crg_slave_init(struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data clks[] = {
+ { .id = "mclk" },
+ { .id = "mclk_ext" },
+ { .id = "apb" },
+ { .id = "bclk_ext" },
+ { .id = "lrck_ext" },
+ { .id = "bclk" },
+ { .id = "lrck" },
+ { .id = "mclk_inner" },
+ { .id = "i2sclk" },
+ };
+ struct reset_control *resets = devm_reset_control_array_get_exclusive(dev->dev);
+ int ret;
+ struct clk *pclk;
+ struct clk *bclk_mst;
+ struct clk *bclk_ext;
+ struct clk *lrck_ext;
+ struct clk *bclk;
+ struct clk *lrck;
+ struct clk *mclk;
+ struct clk *mclk_ext;
+ struct clk *mclk_inner;
+
+ if (IS_ERR(resets))
+ return dev_err_probe(dev->dev, PTR_ERR(resets), "failed to get i2s resets\n");
+
+ ret = clk_bulk_get(dev->dev, ARRAY_SIZE(clks), clks);
+ if (ret)
+ return dev_err_probe(dev->dev, ret, "failed to get i2s clocks\n");
+
+ mclk = clks[0].clk;
+ mclk_ext = clks[1].clk;
+ pclk = clks[2].clk;
+ bclk_ext = clks[3].clk;
+ lrck_ext = clks[4].clk;
+ bclk = clks[5].clk;
+ lrck = clks[6].clk;
+ mclk_inner = clks[7].clk;
+ bclk_mst = clks[8].clk;
+
+ ret = clk_prepare_enable(pclk);
+ if (ret)
+ goto exit;
+
+ ret = clk_set_parent(mclk, mclk_inner);
+ if (ret)
+ goto err_dis_pclk;
+
+ ret = clk_prepare_enable(bclk_mst);
+ if (ret)
+ goto err_dis_pclk;
+
+ ret = reset_control_deassert(resets);
+ if (ret)
+ goto err_dis_all;
+
+ /* The sources of BCLK and LRCK are the external codec. */
+ ret = clk_set_parent(bclk, bclk_ext);
+ if (ret)
+ goto err_dis_all;
+
+ ret = clk_set_parent(lrck, lrck_ext);
+ if (ret)
+ goto err_dis_all;
+
+ ret = clk_set_parent(mclk, mclk_ext);
+ if (ret)
+ goto err_dis_all;
+
+ /* The i2sclk will be got and enabled repeatedly later and should be disabled now. */
+ clk_disable_unprepare(bclk_mst);
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ dev->is_jh7110 = true;
+
+ return 0;
+
+err_dis_all:
+ clk_disable_unprepare(bclk_mst);
+err_dis_pclk:
+ clk_disable_unprepare(pclk);
+exit:
+ clk_bulk_put(ARRAY_SIZE(clks), clks);
+ return ret;
+}
+
+/* Special syscon initialization about RX channel with slave mode on JH7110 SoC */
+static int jh7110_i2srx_crg_init(struct dw_i2s_dev *dev)
+{
+ struct regmap *regmap;
+ unsigned int args[2];
+
+ regmap = syscon_regmap_lookup_by_phandle_args(dev->dev->of_node,
+ "starfive,syscon",
+ 2, args);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev->dev, PTR_ERR(regmap), "getting the regmap failed\n");
+
+ /* Enable I2Srx with syscon register, args[0]: offset, args[1]: mask */
+ regmap_update_bits(regmap, args[0], args[1], args[1]);
+
+ return jh7110_i2s_crg_slave_init(dev);
+}
+
+static int jh7110_i2stx0_clk_cfg(struct i2s_clk_config_data *config)
+{
+ struct dw_i2s_dev *dev = container_of(config, struct dw_i2s_dev, config);
+ u32 bclk_rate = config->sample_rate * 64;
+
+ return clk_set_rate(dev->clk, bclk_rate);
}
static int dw_i2s_probe(struct platform_device *pdev)
{
- const struct i2s_platform_data *pdata = pdev->dev.platform_data;
+ const struct i2s_platform_data *pdata = of_device_get_match_data(&pdev->dev);
struct dw_i2s_dev *dev;
struct resource *res;
int ret, irq;
@@ -706,21 +931,30 @@ static int dw_i2s_probe(struct platform_device *pdev)
return -ENOMEM;
dw_i2s_dai->ops = &dw_i2s_dai_ops;
- dw_i2s_dai->probe = dw_i2s_dai_probe;
dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(dev->i2s_base))
return PTR_ERR(dev->i2s_base);
- dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
- if (IS_ERR(dev->reset))
- return PTR_ERR(dev->reset);
+ dev->dev = &pdev->dev;
+ dev->is_jh7110 = false;
+ if (pdata) {
+ if (pdata->i2s_pd_init) {
+ ret = pdata->i2s_pd_init(dev);
+ if (ret)
+ return ret;
+ }
+ }
- ret = reset_control_deassert(dev->reset);
- if (ret)
- return ret;
+ if (!dev->is_jh7110) {
+ dev->reset = devm_reset_control_array_get_optional_shared(&pdev->dev);
+ if (IS_ERR(dev->reset))
+ return PTR_ERR(dev->reset);
- dev->dev = &pdev->dev;
+ ret = reset_control_deassert(dev->reset);
+ if (ret)
+ return ret;
+ }
irq = platform_get_irq_optional(pdev, 0);
if (irq >= 0) {
@@ -779,7 +1013,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
goto err_clk_disable;
}
- if (!pdata) {
+ if (!pdata || dev->is_jh7110) {
if (irq >= 0) {
ret = dw_pcm_register(pdev);
dev->use_pio = true;
@@ -821,8 +1055,36 @@ static void dw_i2s_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF
+static const struct i2s_platform_data jh7110_i2stx0_data = {
+ .cap = DWC_I2S_PLAY | DW_I2S_MASTER,
+ .channel = TWO_CHANNEL_SUPPORT,
+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .snd_rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .i2s_clk_cfg = jh7110_i2stx0_clk_cfg,
+ .i2s_pd_init = jh7110_i2s_crg_master_init,
+};
+
+static const struct i2s_platform_data jh7110_i2stx1_data = {
+ .cap = DWC_I2S_PLAY | DW_I2S_SLAVE,
+ .channel = TWO_CHANNEL_SUPPORT,
+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .snd_rates = SNDRV_PCM_RATE_8000_192000,
+ .i2s_pd_init = jh7110_i2s_crg_slave_init,
+};
+
+static const struct i2s_platform_data jh7110_i2srx_data = {
+ .cap = DWC_I2S_RECORD | DW_I2S_SLAVE,
+ .channel = TWO_CHANNEL_SUPPORT,
+ .snd_fmts = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .snd_rates = SNDRV_PCM_RATE_8000_192000,
+ .i2s_pd_init = jh7110_i2srx_crg_init,
+};
+
static const struct of_device_id dw_i2s_of_match[] = {
{ .compatible = "snps,designware-i2s", },
+ { .compatible = "starfive,jh7110-i2stx0", .data = &jh7110_i2stx0_data, },
+ { .compatible = "starfive,jh7110-i2stx1", .data = &jh7110_i2stx1_data,},
+ { .compatible = "starfive,jh7110-i2srx", .data = &jh7110_i2srx_data,},
{},
};
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h
index 4ce96bac2f39..dce88c9ad5f3 100644
--- a/sound/soc/dwc/local.h
+++ b/sound/soc/dwc/local.h
@@ -123,6 +123,7 @@ struct dw_i2s_dev {
u32 fifo_th;
u32 l_reg;
u32 r_reg;
+ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
/* data related to DMA transfers b/w i2s and DMAC */
union dw_i2s_snd_dma_data play_dma_data;
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index adb8a59de2bd..b793263291dc 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -780,13 +780,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
- .startup = fsl_asrc_dai_startup,
- .hw_params = fsl_asrc_dai_hw_params,
- .hw_free = fsl_asrc_dai_hw_free,
- .trigger = fsl_asrc_dai_trigger,
-};
-
static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
@@ -797,12 +790,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
+ .probe = fsl_asrc_dai_probe,
+ .startup = fsl_asrc_dai_startup,
+ .hw_params = fsl_asrc_dai_hw_params,
+ .hw_free = fsl_asrc_dai_hw_free,
+ .trigger = fsl_asrc_dai_trigger,
+};
+
#define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_3LE)
static struct snd_soc_dai_driver fsl_asrc_dai = {
- .probe = fsl_asrc_dai_probe,
.playback = {
.stream_name = "ASRC-Playback",
.channels_min = 1,
diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c
index 46b0c5dcc4a5..fc56f6ade368 100644
--- a/sound/soc/fsl/fsl_aud2htx.c
+++ b/sound/soc/fsl/fsl_aud2htx.c
@@ -49,10 +49,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
- .trigger = fsl_aud2htx_trigger,
-};
-
static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
@@ -84,8 +80,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+ .probe = fsl_aud2htx_dai_probe,
+ .trigger = fsl_aud2htx_trigger,
+};
+
static struct snd_soc_dai_driver fsl_aud2htx_dai = {
- .probe = fsl_aud2htx_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 670cbdb361b6..ba62995c909a 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
- .startup = fsl_easrc_startup,
- .trigger = fsl_easrc_trigger,
- .hw_params = fsl_easrc_hw_params,
- .hw_free = fsl_easrc_hw_free,
-};
-
static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev);
@@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+ .probe = fsl_easrc_dai_probe,
+ .startup = fsl_easrc_startup,
+ .trigger = fsl_easrc_trigger,
+ .hw_params = fsl_easrc_hw_params,
+ .hw_free = fsl_easrc_hw_free,
+};
+
static struct snd_soc_dai_driver fsl_easrc_dai = {
- .probe = fsl_easrc_dai_probe,
.playback = {
.stream_name = "ASRC-Playback",
.channels_min = 1,
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 936f0cd4b06d..d0d8a01da9bd 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
- .startup = fsl_esai_startup,
- .trigger = fsl_esai_trigger,
- .hw_params = fsl_esai_hw_params,
- .set_sysclk = fsl_esai_set_dai_sysclk,
- .set_fmt = fsl_esai_set_dai_fmt,
- .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
-};
-
static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
@@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
+ .probe = fsl_esai_dai_probe,
+ .startup = fsl_esai_startup,
+ .trigger = fsl_esai_trigger,
+ .hw_params = fsl_esai_hw_params,
+ .set_sysclk = fsl_esai_set_dai_sysclk,
+ .set_fmt = fsl_esai_set_dai_fmt,
+ .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
static struct snd_soc_dai_driver fsl_esai_dai = {
- .probe = fsl_esai_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 9d01225dedd9..0d37edb70261 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -56,6 +56,8 @@ struct fsl_micfil {
int vad_init_mode;
int vad_enabled;
int vad_detected;
+ struct fsl_micfil_verid verid;
+ struct fsl_micfil_param param;
};
struct fsl_micfil_soc_data {
@@ -64,6 +66,7 @@ struct fsl_micfil_soc_data {
unsigned int dataline;
bool imx;
bool use_edma;
+ bool use_verid;
u64 formats;
};
@@ -90,6 +93,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.use_edma = true,
+ .use_verid = true,
};
static const struct of_device_id fsl_micfil_dt_ids[] = {
@@ -356,6 +360,49 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
};
+static int fsl_micfil_use_verid(struct device *dev)
+{
+ struct fsl_micfil *micfil = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ if (!micfil->soc->use_verid)
+ return 0;
+
+ ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "VERID: 0x%016X\n", val);
+
+ micfil->verid.version = val &
+ (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK);
+ micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT;
+ micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK;
+
+ ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "PARAM: 0x%016X\n", val);
+
+ micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >>
+ MICFIL_PARAM_NUM_HWVAD_SHIFT;
+ micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD;
+ micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE;
+ micfil->param.hwvad = val & MICFIL_PARAM_HWVAD;
+ micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS;
+ micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS;
+ micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER;
+ micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH;
+ micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >>
+ MICFIL_PARAM_FIFO_PTRWID_SHIFT;
+ micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >>
+ MICFIL_PARAM_NPAIR_SHIFT;
+
+ return 0;
+}
+
/* The SRES is a self-negated bit which provides the CPU with the
* capability to initialize the PDM Interface module through the
* slave-bus interface. This bit always reads as zero, and this
@@ -717,12 +764,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
- .startup = fsl_micfil_startup,
- .trigger = fsl_micfil_trigger,
- .hw_params = fsl_micfil_hw_params,
-};
-
static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev);
@@ -760,8 +801,14 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
+ .probe = fsl_micfil_dai_probe,
+ .startup = fsl_micfil_startup,
+ .trigger = fsl_micfil_trigger,
+ .hw_params = fsl_micfil_hw_params,
+};
+
static struct snd_soc_dai_driver fsl_micfil_dai = {
- .probe = fsl_micfil_dai_probe,
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
@@ -825,6 +872,9 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg)
case REG_MICFIL_DC_CTRL:
case REG_MICFIL_OUT_CTRL:
case REG_MICFIL_OUT_STAT:
+ case REG_MICFIL_FSYNC_CTRL:
+ case REG_MICFIL_VERID:
+ case REG_MICFIL_PARAM:
case REG_MICFIL_VAD0_CTRL1:
case REG_MICFIL_VAD0_CTRL2:
case REG_MICFIL_VAD0_STAT:
@@ -849,6 +899,7 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg)
case REG_MICFIL_DC_CTRL:
case REG_MICFIL_OUT_CTRL:
case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */
+ case REG_MICFIL_FSYNC_CTRL:
case REG_MICFIL_VAD0_CTRL1:
case REG_MICFIL_VAD0_CTRL2:
case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */
@@ -873,6 +924,8 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg)
case REG_MICFIL_DATACH5:
case REG_MICFIL_DATACH6:
case REG_MICFIL_DATACH7:
+ case REG_MICFIL_VERID:
+ case REG_MICFIL_PARAM:
case REG_MICFIL_VAD0_STAT:
case REG_MICFIL_VAD0_NDATA:
return true;
@@ -1031,6 +1084,9 @@ static irqreturn_t hwvad_err_isr(int irq, void *devid)
return IRQ_HANDLED;
}
+static int fsl_micfil_runtime_suspend(struct device *dev);
+static int fsl_micfil_runtime_resume(struct device *dev);
+
static int fsl_micfil_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1044,7 +1100,7 @@ static int fsl_micfil_probe(struct platform_device *pdev)
return -ENOMEM;
micfil->pdev = pdev;
- strncpy(micfil->name, np->name, sizeof(micfil->name) - 1);
+ strscpy(micfil->name, np->name, sizeof(micfil->name));
micfil->soc = of_device_get_match_data(&pdev->dev);
@@ -1150,6 +1206,25 @@ static int fsl_micfil_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, micfil);
pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = fsl_micfil_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret < 0)
+ goto err_pm_get_sync;
+
+ /* Get micfil version */
+ ret = fsl_micfil_use_verid(&pdev->dev);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret);
+
+ ret = pm_runtime_put_sync(&pdev->dev);
+ if (ret < 0 && ret != -ENOSYS)
+ goto err_pm_get_sync;
+
regcache_cache_only(micfil->regmap, true);
/*
@@ -1174,6 +1249,9 @@ static int fsl_micfil_probe(struct platform_device *pdev)
return ret;
+err_pm_get_sync:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ fsl_micfil_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
@@ -1185,7 +1263,7 @@ static void fsl_micfil_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev)
+static int fsl_micfil_runtime_suspend(struct device *dev)
{
struct fsl_micfil *micfil = dev_get_drvdata(dev);
@@ -1197,7 +1275,7 @@ static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
+static int fsl_micfil_runtime_resume(struct device *dev)
{
struct fsl_micfil *micfil = dev_get_drvdata(dev);
int ret;
@@ -1219,26 +1297,12 @@ static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused fsl_micfil_suspend(struct device *dev)
-{
- pm_runtime_force_suspend(dev);
-
- return 0;
-}
-
-static int __maybe_unused fsl_micfil_resume(struct device *dev)
-{
- pm_runtime_force_resume(dev);
-
- return 0;
-}
-
static const struct dev_pm_ops fsl_micfil_pm_ops = {
SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend,
fsl_micfil_runtime_resume,
NULL)
- SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend,
- fsl_micfil_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
};
static struct platform_driver fsl_micfil_driver = {
diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h
index fee9fe3d9119..c6b902ba0a53 100644
--- a/sound/soc/fsl/fsl_micfil.h
+++ b/sound/soc/fsl/fsl_micfil.h
@@ -24,6 +24,9 @@
#define REG_MICFIL_DC_CTRL 0x64
#define REG_MICFIL_OUT_CTRL 0x74
#define REG_MICFIL_OUT_STAT 0x7C
+#define REG_MICFIL_FSYNC_CTRL 0x80
+#define REG_MICFIL_VERID 0x84
+#define REG_MICFIL_PARAM 0x88
#define REG_MICFIL_VAD0_CTRL1 0x90
#define REG_MICFIL_VAD0_CTRL2 0x94
#define REG_MICFIL_VAD0_STAT 0x98
@@ -39,6 +42,8 @@
#define MICFIL_CTRL1_DBG BIT(28)
#define MICFIL_CTRL1_SRES BIT(27)
#define MICFIL_CTRL1_DBGE BIT(26)
+#define MICFIL_CTRL1_DECFILS BIT(20)
+#define MICFIL_CTRL1_FSYNCEN BIT(16)
#define MICFIL_CTRL1_DISEL_DISABLE 0
#define MICFIL_CTRL1_DISEL_DMA 1
@@ -82,6 +87,29 @@
#define MICFIL_DC_CUTOFF_152Hz 2
#define MICFIL_DC_BYPASS 3
+/* MICFIL VERID Register -- REG_MICFIL_VERID */
+#define MICFIL_VERID_MAJOR_SHIFT 24
+#define MICFIL_VERID_MAJOR_MASK GENMASK(31, 24)
+#define MICFIL_VERID_MINOR_SHIFT 16
+#define MICFIL_VERID_MINOR_MASK GENMASK(23, 16)
+#define MICFIL_VERID_FEATURE_SHIFT 0
+#define MICFIL_VERID_FEATURE_MASK GENMASK(15, 0)
+
+/* MICFIL PARAM Register -- REG_MICFIL_PARAM */
+#define MICFIL_PARAM_NUM_HWVAD_SHIFT 24
+#define MICFIL_PARAM_NUM_HWVAD_MASK GENMASK(27, 24)
+#define MICFIL_PARAM_HWVAD_ZCD BIT(19)
+#define MICFIL_PARAM_HWVAD_ENERGY_MODE BIT(17)
+#define MICFIL_PARAM_HWVAD BIT(16)
+#define MICFIL_PARAM_DC_OUT_BYPASS BIT(11)
+#define MICFIL_PARAM_DC_IN_BYPASS BIT(10)
+#define MICFIL_PARAM_LOW_POWER BIT(9)
+#define MICFIL_PARAM_FIL_OUT_WIDTH BIT(8)
+#define MICFIL_PARAM_FIFO_PTRWID_SHIFT 4
+#define MICFIL_PARAM_FIFO_PTRWID_MASK GENMASK(7, 4)
+#define MICFIL_PARAM_NPAIR_SHIFT 0
+#define MICFIL_PARAM_NPAIR_MASK GENMASK(3, 0)
+
/* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/
#define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24)
#define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16)
@@ -146,4 +174,40 @@
#define MICFIL_HWVAD_ENVELOPE_MODE 0
#define MICFIL_HWVAD_ENERGY_MODE 1
+/**
+ * struct fsl_micfil_verid - version id data
+ * @version: version number
+ * @feature: feature specification number
+ */
+struct fsl_micfil_verid {
+ u32 version;
+ u32 feature;
+};
+
+/**
+ * struct fsl_micfil_param - parameter data
+ * @hwvad_num: the number of HWVADs
+ * @hwvad_zcd: HWVAD zero-cross detector is active
+ * @hwvad_energy_mode: HWVAD energy mode is active
+ * @hwvad: HWVAD is active
+ * @dc_out_bypass: points out if the output DC remover is disabled
+ * @dc_in_bypass: points out if the input DC remover is disabled
+ * @low_power: low power decimation filter
+ * @fil_out_width: filter output width
+ * @fifo_ptrwid: FIFO pointer width
+ * @npair: number of microphone pairs
+ */
+struct fsl_micfil_param {
+ u32 hwvad_num;
+ bool hwvad_zcd;
+ bool hwvad_energy_mode;
+ bool hwvad;
+ bool dc_out_bypass;
+ bool dc_in_bypass;
+ bool low_power;
+ bool fil_out_width;
+ u32 fifo_ptrwid;
+ u32 npair;
+};
+
#endif /* _FSL_MICFIL_H */
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index 7cbb8e4758cc..56d6b0b039a2 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -372,8 +372,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
unsigned int channels = params_channels(params);
unsigned int slot_width;
+ snd_pcm_format_t format;
struct snd_mask f_new;
- unsigned int i;
if (!channels || channels > nb_ts) {
dev_err(qmc_dai->dev, "channels %u not supported\n",
@@ -384,10 +384,10 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
slot_width = (nb_ts / channels) * 8;
snd_mask_none(&f_new);
- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
- if (snd_mask_test(f_old, i)) {
- if (snd_pcm_format_physical_width(i) <= slot_width)
- snd_mask_set(&f_new, i);
+ pcm_for_each_format(format) {
+ if (snd_mask_test_format(f_old, format)) {
+ if (snd_pcm_format_physical_width(format) <= slot_width)
+ snd_mask_set_format(&f_new, format);
}
}
@@ -551,26 +551,26 @@ static const struct snd_soc_dai_ops qmc_dai_ops = {
static u64 qmc_audio_formats(u8 nb_ts)
{
- u64 formats;
- unsigned int chan_width;
unsigned int format_width;
- int i;
+ unsigned int chan_width;
+ snd_pcm_format_t format;
+ u64 formats_mask;
if (!nb_ts)
return 0;
- formats = 0;
+ formats_mask = 0;
chan_width = nb_ts * 8;
- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+ pcm_for_each_format(format) {
/*
* Support format other than little-endian (ie big-endian or
* without endianness such as 8bit formats)
*/
- if (snd_pcm_format_little_endian(i) == 1)
+ if (snd_pcm_format_little_endian(format) == 1)
continue;
/* Support physical width multiple of 8bit */
- format_width = snd_pcm_format_physical_width(i);
+ format_width = snd_pcm_format_physical_width(format);
if (format_width == 0 || format_width % 8)
continue;
@@ -581,9 +581,9 @@ static u64 qmc_audio_formats(u8 nb_ts)
if (format_width > chan_width || chan_width % format_width)
continue;
- formats |= (1ULL << i);
+ formats_mask |= pcm_format_to_bits(format);
}
- return formats;
+ return formats_mask;
}
static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index f7676d30c82f..1e4020fae05a 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -849,17 +849,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
return ret;
}
-static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
- .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
- .set_sysclk = fsl_sai_set_dai_sysclk,
- .set_fmt = fsl_sai_set_dai_fmt,
- .set_tdm_slot = fsl_sai_set_dai_tdm_slot,
- .hw_params = fsl_sai_hw_params,
- .hw_free = fsl_sai_hw_free,
- .trigger = fsl_sai_trigger,
- .startup = fsl_sai_startup,
-};
-
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
@@ -885,6 +874,18 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+ .probe = fsl_sai_dai_probe,
+ .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+ .set_sysclk = fsl_sai_set_dai_sysclk,
+ .set_fmt = fsl_sai_set_dai_fmt,
+ .set_tdm_slot = fsl_sai_set_dai_tdm_slot,
+ .hw_params = fsl_sai_hw_params,
+ .hw_free = fsl_sai_hw_free,
+ .trigger = fsl_sai_trigger,
+ .startup = fsl_sai_startup,
+};
+
static int fsl_sai_dai_resume(struct snd_soc_component *component)
{
struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
@@ -903,7 +904,6 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
}
static struct snd_soc_dai_driver fsl_sai_dai_template = {
- .probe = fsl_sai_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 95bb8b10494a..78d9dfbe6548 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -765,14 +765,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
- .startup = fsl_spdif_startup,
- .hw_params = fsl_spdif_hw_params,
- .trigger = fsl_spdif_trigger,
- .shutdown = fsl_spdif_shutdown,
-};
-
-
/*
* FSL SPDIF IEC958 controller(mixer) functions
*
@@ -1283,8 +1275,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+ .probe = fsl_spdif_dai_probe,
+ .startup = fsl_spdif_startup,
+ .hw_params = fsl_spdif_hw_params,
+ .trigger = fsl_spdif_trigger,
+ .shutdown = fsl_spdif_shutdown,
+};
+
static struct snd_soc_dai_driver fsl_spdif_dai = {
- .probe = &fsl_spdif_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 2,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 53ed3701b0b0..079ac04272b8 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+ .probe = fsl_ssi_dai_probe,
.startup = fsl_ssi_startup,
.shutdown = fsl_ssi_shutdown,
.hw_params = fsl_ssi_hw_params,
@@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
};
static struct snd_soc_dai_driver fsl_ssi_dai_template = {
- .probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
@@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.symmetric_channels = 1,
- .probe = fsl_ssi_dai_probe,
.playback = {
.stream_name = "CPU AC97 Playback",
.channels_min = 2,
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 318fe77683f5..fa0a15263c66 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -888,13 +888,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
},
};
-static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
- .prepare = fsl_xcvr_prepare,
- .startup = fsl_xcvr_startup,
- .shutdown = fsl_xcvr_shutdown,
- .trigger = fsl_xcvr_trigger,
-};
-
static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
@@ -915,8 +908,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+ .probe = fsl_xcvr_dai_probe,
+ .prepare = fsl_xcvr_prepare,
+ .startup = fsl_xcvr_startup,
+ .shutdown = fsl_xcvr_shutdown,
+ .trigger = fsl_xcvr_trigger,
+};
+
static struct snd_soc_dai_driver fsl_xcvr_dai = {
- .probe = fsl_xcvr_dai_probe,
.ops = &fsl_xcvr_dai_ops,
.playback = {
.stream_name = "CPU-Playback",
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index d5234ac4b09b..289e47c03d40 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -116,7 +116,6 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
static struct rpmsg_driver imx_audio_rpmsg_driver = {
.drv.name = "imx_audio_rpmsg",
- .drv.owner = THIS_MODULE,
.id_table = imx_audio_rpmsg_id_table,
.probe = imx_audio_rpmsg_probe,
.callback = imx_audio_rpmsg_cb,
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 85bd36fb68a2..6f0d031c1d5f 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -37,6 +37,16 @@ static struct snd_soc_jack_gpio headset_jack_gpios[] = {
};
static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
{
@@ -46,9 +56,11 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
/* Headphone jack detection */
if (gpio_is_valid(data->jack_gpio)) {
- ret = snd_soc_card_jack_new(rtd->card, "Headphone",
- SND_JACK_HEADPHONE | SND_JACK_BTN_0,
- &headset_jack);
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
if (ret)
return ret;
@@ -68,6 +80,11 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
};
+static const struct snd_kcontrol_new imx_es8328_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
static int imx_es8328_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -183,6 +200,8 @@ static int imx_es8328_probe(struct platform_device *pdev)
data->card.dev = dev;
data->card.dapm_widgets = imx_es8328_dapm_widgets;
data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
+ data->card.controls = imx_es8328_controls;
+ data->card.num_controls = ARRAY_SIZE(imx_es8328_controls);
ret = snd_soc_of_parse_card_name(&data->card, "model");
if (ret) {
dev_err(dev, "Unable to parse card name\n");
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 40a4a2667394..1671bcd4ee3d 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -222,6 +222,7 @@ static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
* psc_ac97_dai_template: template CPU Digital Audio Interface
*/
static const struct snd_soc_dai_ops psc_ac97_analog_ops = {
+ .probe = psc_ac97_probe,
.hw_params = psc_ac97_hw_analog_params,
.trigger = psc_ac97_trigger,
};
@@ -233,7 +234,6 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = {
static struct snd_soc_dai_driver psc_ac97_dai[] = {
{
.name = "mpc5200-psc-ac97.0",
- .probe = psc_ac97_probe,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 1,
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 0b8258b6bd8e..844a2ef15948 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -60,7 +60,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
if (dai && (dai->component->driver->pcm_construct ||
- dai->driver->pcm_new))
+ (dai->driver->ops && dai->driver->ops->pcm_new)))
return true;
return false;
@@ -425,77 +425,6 @@ static int graph_for_each_link(struct asoc_simple_priv *priv,
return ret;
}
-static int graph_get_dais_count(struct asoc_simple_priv *priv,
- struct link_info *li);
-
-int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
-{
- struct snd_soc_card *card = simple_priv_to_card(priv);
- struct link_info *li;
- int ret;
-
- li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
- if (!li)
- return -ENOMEM;
-
- card->owner = THIS_MODULE;
- card->dev = dev;
-
- ret = graph_get_dais_count(priv, li);
- if (ret < 0)
- return ret;
-
- if (!li->link)
- return -EINVAL;
-
- ret = asoc_simple_init_priv(priv, li);
- if (ret < 0)
- return ret;
-
- priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
- if (IS_ERR(priv->pa_gpio)) {
- ret = PTR_ERR(priv->pa_gpio);
- dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
- return ret;
- }
-
- ret = asoc_simple_parse_widgets(card, NULL);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_parse_routing(card, NULL);
- if (ret < 0)
- return ret;
-
- memset(li, 0, sizeof(*li));
- ret = graph_for_each_link(priv, li,
- graph_dai_link_of,
- graph_dai_link_of_dpcm);
- if (ret < 0)
- goto err;
-
- ret = asoc_simple_parse_card_name(card, NULL);
- if (ret < 0)
- goto err;
-
- snd_soc_card_set_drvdata(card, priv);
-
- asoc_simple_debug_info(priv);
-
- ret = devm_snd_soc_register_card(dev, card);
- if (ret < 0)
- goto err;
-
- devm_kfree(dev, li);
- return 0;
-
-err:
- asoc_simple_clean_reference(card);
-
- return dev_err_probe(dev, ret, "parse error\n");
-}
-EXPORT_SYMBOL_GPL(audio_graph_parse_of);
-
static int graph_count_noml(struct asoc_simple_priv *priv,
struct device_node *cpu_ep,
struct device_node *codec_ep,
@@ -612,6 +541,74 @@ static int graph_get_dais_count(struct asoc_simple_priv *priv,
graph_count_dpcm);
}
+int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
+{
+ struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct link_info *li;
+ int ret;
+
+ li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
+ if (!li)
+ return -ENOMEM;
+
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+
+ ret = graph_get_dais_count(priv, li);
+ if (ret < 0)
+ return ret;
+
+ if (!li->link)
+ return -EINVAL;
+
+ ret = asoc_simple_init_priv(priv, li);
+ if (ret < 0)
+ return ret;
+
+ priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->pa_gpio)) {
+ ret = PTR_ERR(priv->pa_gpio);
+ dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
+ return ret;
+ }
+
+ ret = asoc_simple_parse_widgets(card, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_parse_routing(card, NULL);
+ if (ret < 0)
+ return ret;
+
+ memset(li, 0, sizeof(*li));
+ ret = graph_for_each_link(priv, li,
+ graph_dai_link_of,
+ graph_dai_link_of_dpcm);
+ if (ret < 0)
+ goto err;
+
+ ret = asoc_simple_parse_card_name(card, NULL);
+ if (ret < 0)
+ goto err;
+
+ snd_soc_card_set_drvdata(card, priv);
+
+ asoc_simple_debug_info(priv);
+
+ ret = devm_snd_soc_register_card(dev, card);
+ if (ret < 0)
+ goto err;
+
+ devm_kfree(dev, li);
+ return 0;
+
+err:
+ asoc_simple_clean_reference(card);
+
+ return dev_err_probe(dev, ret, "parse error\n");
+}
+EXPORT_SYMBOL_GPL(audio_graph_parse_of);
+
static int graph_probe(struct platform_device *pdev)
{
struct asoc_simple_priv *priv;
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
index 2ac0de3c21da..8acaa2ddb335 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
@@ -34,6 +34,13 @@
* ...
* };
*
+ *
+ * Below sample doesn't use "format" property,
+ * because test-component driver (test-cpu/test-codec) is supporting
+ * snd_soc_dai_ops :: .auto_selectable_formats.
+ * see
+ * snd_soc_runtime_get_dai_fmt()
+ * linux/sound/soc/generic/test-component.c :: test_dai_formats
*/
/ {
/*
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 98732468a992..b1c675c6b6db 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -47,6 +47,18 @@
see
graph_parse_daifmt().
+ "format" property is no longer needed on DT if both CPU/Codec drivers are
+ supporting snd_soc_dai_ops :: .auto_selectable_formats.
+ see
+ snd_soc_runtime_get_dai_fmt()
+
+ sample driver
+ linux/sound/soc/sh/rcar/core.c
+ linux/sound/soc/codecs/ak4613.c
+ linux/sound/soc/codecs/pcm3168a.c
+ linux/sound/soc/soc-utils.c
+ linux/sound/soc/generic/test-component.c
+
************************************
Normal Audio-Graph
************************************
diff --git a/sound/soc/hisilicon/hi6210-i2s.c b/sound/soc/hisilicon/hi6210-i2s.c
index 27219a9e7d0d..dd7d2a077248 100644
--- a/sound/soc/hisilicon/hi6210-i2s.c
+++ b/sound/soc/hisilicon/hi6210-i2s.c
@@ -511,6 +511,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
+ .probe = hi6210_i2s_dai_probe,
.trigger = hi6210_i2s_trigger,
.hw_params = hi6210_i2s_hw_params,
.set_fmt = hi6210_i2s_set_fmt,
@@ -519,7 +520,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
};
static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
- .probe = hi6210_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index b7ab8467b5cf..b6b6339c164b 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
- .trigger = img_i2s_in_trigger,
- .hw_params = img_i2s_in_hw_params,
- .set_fmt = img_i2s_in_set_fmt
-};
-
static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
{
struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
@@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
+ .probe = img_i2s_in_dai_probe,
+ .trigger = img_i2s_in_trigger,
+ .hw_params = img_i2s_in_hw_params,
+ .set_fmt = img_i2s_in_set_fmt
+};
+
static const struct snd_soc_component_driver img_i2s_in_component = {
.name = "img-i2s-in",
.legacy_dai_naming = 1,
@@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev)
i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
i2s->dma_data.addr_width = 4;
- i2s->dai_driver.probe = img_i2s_in_dai_probe;
i2s->dai_driver.capture.channels_min = 2;
i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index fe95ddfb8407..41ea5ba52181 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
- .trigger = img_i2s_out_trigger,
- .hw_params = img_i2s_out_hw_params,
- .set_fmt = img_i2s_out_set_fmt
-};
-
static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
{
struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
@@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
+ .probe = img_i2s_out_dai_probe,
+ .trigger = img_i2s_out_trigger,
+ .hw_params = img_i2s_out_hw_params,
+ .set_fmt = img_i2s_out_set_fmt
+};
+
static const struct snd_soc_component_driver img_i2s_out_component = {
.name = "img-i2s-out",
.legacy_dai_naming = 1,
@@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev)
i2s->dma_data.addr_width = 4;
i2s->dma_data.maxburst = 4;
- i2s->dai_driver.probe = img_i2s_out_dai_probe;
i2s->dai_driver.playback.channels_min = 2;
i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2;
i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000;
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index df1291ee2b3b..815e68a7048c 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
- .trigger = img_prl_out_trigger,
- .hw_params = img_prl_out_hw_params,
- .set_fmt = img_prl_out_set_fmt
-};
-
static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
{
struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
@@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
+ .probe = img_prl_out_dai_probe,
+ .trigger = img_prl_out_trigger,
+ .hw_params = img_prl_out_hw_params,
+ .set_fmt = img_prl_out_set_fmt
+};
+
static struct snd_soc_dai_driver img_prl_out_dai = {
- .probe = img_prl_out_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
index 558062a1804a..9646e9d3f0bc 100644
--- a/sound/soc/img/img-spdif-in.c
+++ b/sound/soc/img/img-spdif-in.c
@@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
return img_spdif_in_do_clkgen_single(spdif, rate);
}
-static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
- .trigger = img_spdif_in_trigger,
- .hw_params = img_spdif_in_hw_params
-};
-
static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
{
struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
@@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
+ .probe = img_spdif_in_dai_probe,
+ .trigger = img_spdif_in_trigger,
+ .hw_params = img_spdif_in_hw_params
+};
+
static struct snd_soc_dai_driver img_spdif_in_dai = {
- .probe = img_spdif_in_dai_probe,
.capture = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
index b13e128e50d6..dfa72afa946e 100644
--- a/sound/soc/img/img-spdif-out.c
+++ b/sound/soc/img/img-spdif-out.c
@@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
- .trigger = img_spdif_out_trigger,
- .hw_params = img_spdif_out_hw_params
-};
-
static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
{
struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
@@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
+ .probe = img_spdif_out_dai_probe,
+ .trigger = img_spdif_out_trigger,
+ .hw_params = img_spdif_out_hw_params
+};
+
static struct snd_soc_dai_driver img_spdif_out_dai = {
- .probe = img_spdif_out_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index ba4597bdf32e..6f986c7bbc8b 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = {
};
static const struct snd_soc_dai_ops sst_compr_dai_ops = {
+ .compress_new = snd_soc_new_compress,
.mute_stream = sst_media_digital_mute,
};
@@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
},
{
.name = "compress-cpu-dai",
- .compress_new = snd_soc_new_compress,
.ops = &sst_compr_dai_ops,
.playback = {
.stream_name = "Compress Playback",
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index 862a19ae5429..288221db7323 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -173,10 +173,11 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
u32 length;
int pvt_id, ret = 0;
struct sst_block *block = NULL;
+ u8 bytes_block = bytes->block;
dev_dbg(sst_drv_ctx->dev,
"type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
- bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
+ bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id,
bytes->pipe_id, bytes->len);
if (sst_create_ipc_msg(&msg, true))
@@ -185,12 +186,12 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
pvt_id = sst_assign_pvt_id(sst_drv_ctx);
sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
bytes->task_id, 1, pvt_id);
- msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
+ msg->mrfld_header.p.header_high.part.res_rqd = bytes_block;
length = bytes->len;
msg->mrfld_header.p.header_low_payload = length;
dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
- if (bytes->block) {
+ if (bytes_block) {
block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
if (block == NULL) {
kfree(msg);
@@ -203,7 +204,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
msg->mrfld_header.p.header_low_payload);
- if (bytes->block) {
+ if (bytes_block) {
ret = sst_wait_timeout(sst_drv_ctx, block);
if (ret) {
dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
@@ -216,7 +217,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
* copy the reply and send back
* we need to update only sz and payload
*/
- if (bytes->block) {
+ if (bytes_block) {
unsigned char *r = block->data;
dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
@@ -224,7 +225,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
memcpy(bytes->bytes, r, bytes->len);
}
}
- if (bytes->block)
+ if (bytes_block)
sst_free_block(sst_drv_ctx, block);
out:
test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 964a763732ab..85014d98f7e8 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -22,6 +22,7 @@
static const struct snd_kcontrol_new card_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static int platform_clock_control(struct snd_soc_dapm_widget *w,
@@ -55,6 +56,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget card_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
};
@@ -68,6 +70,22 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
+};
+
+static const struct snd_soc_jack_pin card_headset_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
@@ -75,7 +93,9 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
struct snd_soc_component *component = codec_dai->component;
struct snd_soc_card *card = runtime->card;
+ struct snd_soc_jack_pin *pins;
struct snd_soc_jack *jack;
+ int num_pins;
int clk_freq;
int ret;
@@ -91,14 +111,20 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
return ret;
}
+ num_pins = ARRAY_SIZE(card_headset_pins);
+ pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
/*
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_BTN_0 |
- SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+ jack, pins, num_pins);
if (ret) {
dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
index 275928281c6c..4cab8c6c4576 100644
--- a/sound/soc/intel/avs/probes.c
+++ b/sound/soc/intel/avs/probes.c
@@ -249,7 +249,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr
return count;
}
-static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
+static const struct snd_soc_cdai_ops avs_probe_cdai_ops = {
.startup = avs_probe_compr_open,
.shutdown = avs_probe_compr_free,
.set_params = avs_probe_compr_set_params,
@@ -257,6 +257,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
.pointer = avs_probe_compr_pointer,
};
+static const struct snd_soc_dai_ops avs_probe_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static const struct snd_compress_ops avs_probe_compress_ops = {
.copy = avs_probe_compr_copy,
};
@@ -264,8 +268,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = {
static struct snd_soc_dai_driver probe_cpu_dais[] = {
{
.name = "Probe Extraction CPU DAI",
- .compress_new = snd_soc_new_compress,
- .cops = &avs_probe_dai_ops,
+ .cops = &avs_probe_cdai_ops,
+ .ops = &avs_probe_dai_ops,
.capture = {
.stream_name = "Probe Extraction",
.channels_min = 1,
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index cdb4ec500261..45d0eb2a8e71 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -1388,12 +1388,12 @@ static int avs_route_load(struct snd_soc_component *comp, int index,
port = __ffs(mach->mach_params.i2s_link_mask);
snprintf(buf, len, route->source, port);
- strncpy((char *)route->source, buf, len);
+ strscpy((char *)route->source, buf, len);
snprintf(buf, len, route->sink, port);
- strncpy((char *)route->sink, buf, len);
+ strscpy((char *)route->sink, buf, len);
if (route->control) {
snprintf(buf, len, route->control, port);
- strncpy((char *)route->control, buf, len);
+ strscpy((char *)route->control, buf, len);
}
}
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 1fe830af2b84..0ae6eecc8851 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -671,14 +671,15 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
select SND_SOC_RT711_SDCA_SDW
select SND_SOC_RT712_SDCA_SDW
select SND_SOC_RT712_SDCA_DMIC_SDW
+ select SND_SOC_RT715_SDW
+ select SND_SOC_RT715_SDCA_SDW
select SND_SOC_RT1308_SDW
select SND_SOC_RT1308
select SND_SOC_RT1316_SDW
select SND_SOC_RT1318_SDW
- select SND_SOC_RT715_SDW
- select SND_SOC_RT715_SDCA_SDW
select SND_SOC_RT5682_SDW
select SND_SOC_CS42L42_SDW
+ select SND_SOC_CS35L56_SDW
select SND_SOC_DMIC
select SND_SOC_INTEL_HDA_DSP_COMMON
select SND_SOC_INTEL_SOF_MAXIM_COMMON
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 931415d9cf6f..a570b5b40f22 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -42,7 +42,7 @@ snd-soc-sof-sdw-objs += sof_sdw.o \
sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \
sof_sdw_rt712_sdca.o sof_sdw_rt715.o \
sof_sdw_rt715_sdca.o sof_sdw_dmic.o \
- sof_sdw_cs42l42.o \
+ sof_sdw_cs42l42.o sof_sdw_cs_amp.o \
sof_sdw_hdmi.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o
obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o
diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c
index b7687a93a923..036579331d8f 100644
--- a/sound/soc/intel/boards/bdw_rt286.c
+++ b/sound/soc/intel/boards/bdw_rt286.c
@@ -187,6 +187,9 @@ static int card_suspend_pre(struct snd_soc_card *card)
{
struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
+ if (!codec_dai)
+ return 0;
+
return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
}
@@ -194,6 +197,9 @@ static int card_resume_post(struct snd_soc_card *card)
{
struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
+ if (!codec_dai)
+ return 0;
+
return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
}
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index c593995facaa..cbfff466c5c8 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -90,6 +90,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
static const struct snd_kcontrol_new broxton_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const struct snd_kcontrol_new max98357a_controls[] = {
@@ -104,6 +105,7 @@ static const struct snd_kcontrol_new max98390_controls[] = {
static const struct snd_soc_dapm_widget broxton_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -150,6 +152,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
};
static const struct snd_soc_dapm_route max98357a_routes[] = {
@@ -194,6 +197,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c
index f2382d4cb76f..5c9e06ed1a53 100644
--- a/sound/soc/intel/boards/bytcr_wm5102.c
+++ b/sound/soc/intel/boards/bytcr_wm5102.c
@@ -131,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Internal Mic", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
@@ -144,6 +145,7 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
{"Headset Mic", NULL, "Platform Clock"},
{"Internal Mic", NULL, "Platform Clock"},
{"Speaker", NULL, "Platform Clock"},
+ {"Line Out", NULL, "Platform Clock"},
{"Speaker", NULL, "SPKOUTLP"},
{"Speaker", NULL, "SPKOUTLN"},
@@ -177,6 +179,7 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Internal Mic"),
SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static struct snd_soc_jack_pin byt_wm5102_pins[] = {
@@ -188,6 +191,10 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 18365ce6bcba..97149513076f 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -83,12 +83,14 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Spk"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Spk", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -107,6 +109,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static const struct snd_soc_dapm_route kabylake_map[] = {
@@ -147,6 +153,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
};
static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index ad4223fee0c5..a1f8234c77bd 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -102,6 +102,7 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const struct snd_soc_dapm_widget kabylake_widgets[] = {
@@ -109,6 +110,7 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -127,6 +129,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_MICROPHONE,
+ },
};
static const struct snd_soc_dapm_route kabylake_map[] = {
@@ -182,6 +188,7 @@ static const struct snd_soc_dapm_route kabylake_ssp1_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
};
static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c
index 740aa11cb019..bbd47e7e4343 100644
--- a/sound/soc/intel/boards/sof_da7219_max98373.c
+++ b/sound/soc/intel/boards/sof_da7219_max98373.c
@@ -65,6 +65,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
};
@@ -72,6 +73,7 @@ static const struct snd_kcontrol_new controls[] = {
static const struct snd_kcontrol_new m98360a_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("Spk"),
};
@@ -79,6 +81,7 @@ static const struct snd_kcontrol_new m98360a_controls[] = {
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
@@ -98,6 +101,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
{ "Left Spk", NULL, "Left BE_OUT" },
{ "Right Spk", NULL, "Right BE_OUT" },
@@ -110,6 +114,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
static const struct snd_soc_dapm_widget max98360a_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SPK("Spk", NULL),
@@ -128,6 +133,7 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
{ "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" },
+ { "Line Out", NULL, "Platform Clock" },
{"Spk", NULL, "Speaker"},
@@ -144,6 +150,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static struct snd_soc_jack headset;
diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c
index d6c38d8ea2ff..f8a3e8a91761 100644
--- a/sound/soc/intel/boards/sof_es8336.c
+++ b/sound/soc/intel/boards/sof_es8336.c
@@ -798,6 +798,16 @@ static const struct platform_device_id board_ids[] = {
SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
SOF_ES8336_JD_INVERTED),
},
+ {
+ .name = "rpl_es83x6_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+ SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+ SOF_ES8336_JD_INVERTED),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c
index 112e89951da0..628b6d5d3ee4 100644
--- a/sound/soc/intel/boards/sof_maxim_common.c
+++ b/sound/soc/intel/boards/sof_maxim_common.c
@@ -4,6 +4,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dai.h>
@@ -11,6 +12,18 @@
#include <uapi/sound/asound.h>
#include "sof_maxim_common.h"
+/* helper function to get the number of specific codec */
+static unsigned int get_num_codecs(const char *hid)
+{
+ struct acpi_device *adev;
+ unsigned int dev_num = 0;
+
+ for_each_acpi_dev_match(adev, hid, NULL, -1)
+ dev_num++;
+
+ return dev_num;
+}
+
#define MAX_98373_PIN_NAME 16
const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
@@ -168,17 +181,6 @@ static struct snd_soc_codec_conf max_98390_codec_conf[] = {
.dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
.name_prefix = "Left",
},
-};
-
-static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = {
- {
- .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
- .name_prefix = "Right",
- },
- {
- .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
- .name_prefix = "Left",
- },
{
.dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME),
.name_prefix = "Tweeter Right",
@@ -189,19 +191,7 @@ static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = {
},
};
-struct snd_soc_dai_link_component max_98390_components[] = {
- {
- .name = MAX_98390_DEV0_NAME,
- .dai_name = MAX_98390_CODEC_DAI,
- },
- {
- .name = MAX_98390_DEV1_NAME,
- .dai_name = MAX_98390_CODEC_DAI,
- },
-};
-EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-
-struct snd_soc_dai_link_component max_98390_4spk_components[] = {
+static struct snd_soc_dai_link_component max_98390_components[] = {
{
.name = MAX_98390_DEV0_NAME,
.dai_name = MAX_98390_CODEC_DAI,
@@ -219,62 +209,56 @@ struct snd_soc_dai_link_component max_98390_4spk_components[] = {
.dai_name = MAX_98390_CODEC_DAI,
},
};
-EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+static const struct {
+ unsigned int tx;
+ unsigned int rx;
+} max_98390_tdm_mask[] = {
+ {.tx = 0x01, .rx = 0x3},
+ {.tx = 0x02, .rx = 0x3},
+ {.tx = 0x04, .rx = 0x3},
+ {.tx = 0x08, .rx = 0x3},
+};
static int max_98390_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
- int i;
+ int i, ret;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- if (i >= ARRAY_SIZE(max_98390_4spk_components)) {
+ if (i >= ARRAY_SIZE(max_98390_tdm_mask)) {
dev_err(codec_dai->dev, "invalid codec index %d\n", i);
return -ENODEV;
}
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) {
- /* DEV0 tdm slot configuration Right */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32);
- }
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) {
- /* DEV1 tdm slot configuration Left */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32);
- }
-
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) {
- /* DEVi2 tdm slot configuration Tweeter Right */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32);
- }
- if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) {
- /* DEV3 tdm slot configuration Tweeter Left */
- snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32);
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx,
+ max_98390_tdm_mask[i].rx, 4,
+ params_width(params));
+ if (ret < 0) {
+ dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+ ret);
+ return ret;
}
}
return 0;
}
-int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
+static int max_98390_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
+ unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
int ret;
- /* add regular speakers dapm route */
- ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
- ARRAY_SIZE(max_98390_dapm_routes));
- if (ret) {
- dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret);
- return ret;
- }
-
- /* add widgets/controls/dapm for tweeter speakers */
- if (acpi_dev_present("MX98390", "3", -1)) {
+ switch (num_codecs) {
+ case 4:
+ /* add widgets/controls/dapm for tweeter speakers */
ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets,
ARRAY_SIZE(max_98390_tt_dapm_widgets));
-
if (ret) {
- dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret);
+ dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n",
+ ret);
/* Don't need to add routes if widget addition failed */
return ret;
}
@@ -282,33 +266,79 @@ int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols,
ARRAY_SIZE(max_98390_tt_kcontrols));
if (ret) {
- dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret);
+ dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n",
+ ret);
return ret;
}
ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes,
ARRAY_SIZE(max_98390_tt_dapm_routes));
- if (ret)
- dev_err(rtd->dev,
- "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret);
+ if (ret) {
+ dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n",
+ ret);
+ return ret;
+ }
+
+ fallthrough;
+ case 2:
+ /* add regular speakers dapm route */
+ ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
+ ARRAY_SIZE(max_98390_dapm_routes));
+ if (ret) {
+ dev_err(rtd->dev, "unable to add dapm routes, ret %d\n",
+ ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(rtd->dev, "invalid codec number %d\n", num_codecs);
+ return -EINVAL;
}
+
return ret;
}
-EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-const struct snd_soc_ops max_98390_ops = {
+static const struct snd_soc_ops max_98390_ops = {
.hw_params = max_98390_hw_params,
};
-EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-void max_98390_set_codec_conf(struct snd_soc_card *card, int ch)
+void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link)
+{
+ unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
+
+ link->codecs = max_98390_components;
+
+ switch (num_codecs) {
+ case 2:
+ case 4:
+ link->num_codecs = num_codecs;
+ break;
+ default:
+ dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
+ MAX_98390_ACPI_HID);
+ break;
+ }
+
+ link->init = max_98390_init;
+ link->ops = &max_98390_ops;
+}
+EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card)
{
- if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) {
- card->codec_conf = max_98390_4spk_codec_conf;
- card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf);
- } else {
- card->codec_conf = max_98390_codec_conf;
- card->num_configs = ARRAY_SIZE(max_98390_codec_conf);
+ unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
+
+ card->codec_conf = max_98390_codec_conf;
+
+ switch (num_codecs) {
+ case 2:
+ case 4:
+ card->num_configs = num_codecs;
+ break;
+ default:
+ dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
+ MAX_98390_ACPI_HID);
+ break;
}
}
EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h
index 7a8c53049e4d..a095b47b856b 100644
--- a/sound/soc/intel/boards/sof_maxim_common.h
+++ b/sound/soc/intel/boards/sof_maxim_common.h
@@ -27,18 +27,15 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd);
/*
* Maxim MAX98390
*/
-#define MAX_98390_CODEC_DAI "max98390-aif1"
-#define MAX_98390_DEV0_NAME "i2c-MX98390:00"
-#define MAX_98390_DEV1_NAME "i2c-MX98390:01"
-#define MAX_98390_DEV2_NAME "i2c-MX98390:02"
-#define MAX_98390_DEV3_NAME "i2c-MX98390:03"
-
-extern struct snd_soc_dai_link_component max_98390_components[2];
-extern struct snd_soc_dai_link_component max_98390_4spk_components[4];
-extern const struct snd_soc_ops max_98390_ops;
-
-void max_98390_set_codec_conf(struct snd_soc_card *card, int ch);
-int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd);
+#define MAX_98390_ACPI_HID "MX98390"
+#define MAX_98390_CODEC_DAI "max98390-aif1"
+#define MAX_98390_DEV0_NAME "i2c-" MAX_98390_ACPI_HID ":00"
+#define MAX_98390_DEV1_NAME "i2c-" MAX_98390_ACPI_HID ":01"
+#define MAX_98390_DEV2_NAME "i2c-" MAX_98390_ACPI_HID ":02"
+#define MAX_98390_DEV3_NAME "i2c-" MAX_98390_ACPI_HID ":03"
+
+void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link);
+void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card);
/*
* Maxim MAX98357A/MAX98360A
diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c
index 4fc6e1c6aef3..46b7ecf6f9f1 100644
--- a/sound/soc/intel/boards/sof_nau8825.c
+++ b/sound/soc/intel/boards/sof_nau8825.c
@@ -684,6 +684,16 @@ static const struct platform_device_id board_ids[] = {
SOF_BT_OFFLOAD_SSP(2) |
SOF_SSP_BT_OFFLOAD_PRESENT),
},
+ {
+ .name = "rpl_nau8318_8825",
+ .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_NAU8318_SPEAKER_AMP_PRESENT |
+ SOF_NAU8825_SSP_AMP(1) |
+ SOF_NAU8825_NUM_HDMIDEV(4) |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
index b4f07bdcf8b4..fae091b9b55c 100644
--- a/sound/soc/intel/boards/sof_rt5682.c
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -59,10 +59,14 @@
#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22)
#define SOF_RT5682S_HEADPHONE_CODEC_PRESENT BIT(23)
#define SOF_MAX98390_SPEAKER_AMP_PRESENT BIT(24)
-#define SOF_MAX98390_TWEETER_SPEAKER_PRESENT BIT(25)
#define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26)
#define SOF_RT5650_HEADPHONE_CODEC_PRESENT BIT(27)
+/* HDMI capture*/
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27
+#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27))
+#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \
+ (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK)
/* Default: MCLK on, MCLK 19.2M, SSP0 */
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
@@ -199,23 +203,6 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
.callback = sof_rt5682_quirk_cb,
.matches = {
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
- DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"),
- },
- .driver_data = (void *)(SOF_RT5682_MCLK_EN |
- SOF_RT5682_SSP_CODEC(0) |
- SOF_SPEAKER_AMP_PRESENT |
- SOF_MAX98390_SPEAKER_AMP_PRESENT |
- SOF_MAX98390_TWEETER_SPEAKER_PRESENT |
- SOF_RT5682_SSP_AMP(1) |
- SOF_RT5682_NUM_HDMIDEV(4) |
- SOF_BT_OFFLOAD_SSP(2) |
- SOF_SSP_BT_OFFLOAD_PRESENT),
-
- },
- {
- .callback = sof_rt5682_quirk_cb,
- .matches = {
- DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"),
},
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
@@ -688,6 +675,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
struct snd_soc_dai_link_component *cpus;
struct snd_soc_dai_link *links;
int i, id = 0;
+ int hdmi_id_offset = 0;
links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links,
sizeof(struct snd_soc_dai_link), GFP_KERNEL);
@@ -850,17 +838,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
sof_rt1011_dai_link(&links[id]);
} else if (sof_rt5682_quirk &
SOF_MAX98390_SPEAKER_AMP_PRESENT) {
- if (sof_rt5682_quirk &
- SOF_MAX98390_TWEETER_SPEAKER_PRESENT) {
- links[id].codecs = max_98390_4spk_components;
- links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components);
- } else {
- links[id].codecs = max_98390_components;
- links[id].num_codecs = ARRAY_SIZE(max_98390_components);
- }
- links[id].init = max_98390_spk_codec_init;
- links[id].ops = &max_98390_ops;
-
+ max_98390_dai_link(dev, &links[id]);
} else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) {
links[id].codecs = &rt5650_components[1];
links[id].num_codecs = 1;
@@ -919,6 +897,34 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
links[id].num_cpus = 1;
}
+ /* HDMI-In SSP */
+ if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) {
+ unsigned long hdmi_in_ssp = (sof_rt5682_quirk &
+ SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >>
+ SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+ int port = 0;
+
+ for_each_set_bit(port, &hdmi_in_ssp, 32) {
+ links[id].cpus = &cpus[id];
+ links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+ "SSP%d Pin", port);
+ if (!links[id].cpus->dai_name)
+ return NULL;
+ links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
+ if (!links[id].name)
+ return NULL;
+ links[id].id = id + hdmi_id_offset;
+ links[id].codecs = &asoc_dummy_dlc;
+ links[id].num_codecs = 1;
+ links[id].platforms = platform_component;
+ links[id].num_platforms = ARRAY_SIZE(platform_component);
+ links[id].dpcm_capture = 1;
+ links[id].no_pcm = 1;
+ links[id].num_cpus = 1;
+ id++;
+ }
+ }
+
return links;
devm_err:
return NULL;
@@ -1019,17 +1025,17 @@ static int sof_audio_probe(struct platform_device *pdev)
else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
sof_rt1015p_codec_conf(&sof_audio_card_rt5682);
else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) {
- if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT)
- max_98390_set_codec_conf(&sof_audio_card_rt5682,
- ARRAY_SIZE(max_98390_4spk_components));
- else
- max_98390_set_codec_conf(&sof_audio_card_rt5682,
- ARRAY_SIZE(max_98390_components));
+ max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682);
}
if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
sof_audio_card_rt5682.num_links++;
+ if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK)
+ sof_audio_card_rt5682.num_links +=
+ hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >>
+ SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT);
+
dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
dmic_be_num, hdmi_num, ctx->idisp_codec);
if (!dai_links)
@@ -1197,6 +1203,22 @@ static const struct platform_device_id board_ids[] = {
SOF_SSP_BT_OFFLOAD_PRESENT),
},
{
+ .name = "adl_rt5682_c1_h02",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_RT5682_SSP_CODEC(1) |
+ SOF_RT5682_NUM_HDMIDEV(3) |
+ /* SSP 0 and SSP 2 are used for HDMI IN */
+ SOF_HDMI_CAPTURE_SSP_MASK(0x5)),
+ },
+ {
+ .name = "rpl_mx98357_rt5682",
+ .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+ SOF_RT5682_SSP_CODEC(0) |
+ SOF_SPEAKER_AMP_PRESENT |
+ SOF_RT5682_SSP_AMP(2) |
+ SOF_RT5682_NUM_HDMIDEV(4)),
+ },
+ {
.name = "rpl_mx98360_rt5682",
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
SOF_RT5682_SSP_CODEC(0) |
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 0201029899ca..5a1c750e6ae6 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -311,6 +311,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+ },
+ .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+ RT711_JD2 |
+ SOF_SDW_FOUR_SPK),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
},
.driver_data = (void *)(SOF_SDW_TGL_HDMI |
@@ -467,7 +477,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
},
- .driver_data = (void *)(SOF_SDW_PCH_DMIC),
+ .driver_data = (void *)(SOF_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(1) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
},
/* LunarLake devices */
{
@@ -511,9 +523,8 @@ int sdw_prepare(struct snd_pcm_substream *substream)
dai = asoc_rtd_to_cpu(rtd, 0);
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
if (IS_ERR(sdw_stream)) {
- dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
+ dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
return PTR_ERR(sdw_stream);
}
@@ -531,9 +542,8 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
dai = asoc_rtd_to_cpu(rtd, 0);
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
if (IS_ERR(sdw_stream)) {
- dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
+ dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
return PTR_ERR(sdw_stream);
}
@@ -555,7 +565,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
}
if (ret)
- dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
+ dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
return ret;
}
@@ -619,9 +629,8 @@ int sdw_hw_free(struct snd_pcm_substream *substream)
dai = asoc_rtd_to_cpu(rtd, 0);
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
if (IS_ERR(sdw_stream)) {
- dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
+ dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
return PTR_ERR(sdw_stream);
}
@@ -895,6 +904,19 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.dai_num = 1,
},
{
+ .part_id = 0x3556,
+ .dais = {
+ {
+ .direction = {true, true},
+ .dai_name = "cs35l56-sdw1",
+ .dai_type = SOF_SDW_DAI_TYPE_AMP,
+ .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
+ .init = sof_sdw_cs_amp_init,
+ },
+ },
+ .dai_num = 1,
+ },
+ {
.part_id = 0x4242,
.dais = {
{
@@ -940,10 +962,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {
.version_id = 0,
.dais = {
{
- .direction = {true, false},
+ .direction = {true, true},
.dai_name = "sdw-mockup-aif1",
.dai_type = SOF_SDW_DAI_TYPE_AMP,
- .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
+ .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
.init = NULL,
},
},
@@ -965,7 +987,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
},
};
-static inline int find_codec_info_part(u64 adr)
+static inline int find_codec_info_part(const u64 adr)
{
unsigned int part_id, sdw_version;
int i;
@@ -994,14 +1016,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
- if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
- ACPI_ID_LEN))
- break;
-
- if (i == ARRAY_SIZE(codec_info_list))
- return -EINVAL;
+ if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
+ return i;
- return i;
+ return -EINVAL;
}
/*
@@ -1009,10 +1027,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id)
* Since some sdw slaves may be aggregated, the CPU DAI number
* may be larger than the number of BE dailinks.
*/
-static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
- int *sdw_be_num, int *sdw_cpu_dai_num)
+static int get_dailink_info(struct device *dev,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num)
{
- const struct snd_soc_acpi_link_adr *link;
bool group_visited[SDW_MAX_GROUPS];
bool no_aggregation;
int i;
@@ -1022,27 +1040,45 @@ static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_li
*sdw_cpu_dai_num = 0;
*sdw_be_num = 0;
- if (!links)
+ if (!adr_link)
return -EINVAL;
for (i = 0; i < SDW_MAX_GROUPS; i++)
group_visited[i] = false;
- for (link = links; link->num_adr; link++) {
+ for (; adr_link->num_adr; adr_link++) {
const struct snd_soc_acpi_endpoint *endpoint;
struct sof_sdw_codec_info *codec_info;
int codec_index;
int stream;
u64 adr;
- for (i = 0; i < link->num_adr; i++) {
- adr = link->adr_d[i].adr;
+ /* make sure the link mask has a single bit set */
+ if (!is_power_of_2(adr_link->mask))
+ return -EINVAL;
+
+ for (i = 0; i < adr_link->num_adr; i++) {
+ adr = adr_link->adr_d[i].adr;
codec_index = find_codec_info_part(adr);
if (codec_index < 0)
return codec_index;
+
codec_info = &codec_info_list[codec_index];
- endpoint = link->adr_d[i].endpoints;
+ *codecs_num += codec_info->dai_num;
+
+ if (!adr_link->adr_d[i].name_prefix) {
+ dev_err(dev, "codec 0x%llx does not have a name prefix\n",
+ adr_link->adr_d[i].adr);
+ return -EINVAL;
+ }
+
+ endpoint = adr_link->adr_d[i].endpoints;
+ if (endpoint->aggregated && !endpoint->group_id) {
+ dev_err(dev, "invalid group id on link %x\n",
+ adr_link->mask);
+ return -EINVAL;
+ }
for (j = 0; j < codec_info->dai_num; j++) {
/* count DAI number for playback and capture */
@@ -1090,17 +1126,16 @@ static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links
dai_links->ops = ops;
}
-static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
+static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
unsigned int sdw_version,
unsigned int mfg_id,
unsigned int part_id,
unsigned int class_id,
- int index_in_link
- )
+ int index_in_link)
{
int i;
- for (i = 0; i < link->num_adr; i++) {
+ for (i = 0; i < adr_link->num_adr; i++) {
unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
u64 adr;
@@ -1108,7 +1143,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
if (i == index_in_link)
continue;
- adr = link->adr_d[i].adr;
+ adr = adr_link->adr_d[i].adr;
sdw1_version = SDW_VERSION(adr);
mfg1_id = SDW_MFG_ID(adr);
@@ -1125,83 +1160,50 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
return true;
}
-static int create_codec_dai_name(struct device *dev,
- const struct snd_soc_acpi_link_adr *link,
- struct snd_soc_dai_link_component *codec,
- int offset,
- struct snd_soc_codec_conf *codec_conf,
- int codec_count,
- int *codec_conf_index,
- int adr_index,
- int dai_index)
+static int fill_sdw_codec_dlc(struct device *dev,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ struct snd_soc_dai_link_component *codec,
+ int adr_index, int dai_index)
{
- int _codec_index = -1;
- int i;
-
- /* sanity check */
- if (*codec_conf_index + link->num_adr - adr_index > codec_count) {
- dev_err(dev, "codec_conf: out-of-bounds access requested\n");
- return -EINVAL;
- }
-
- for (i = adr_index; i < link->num_adr; i++) {
- unsigned int sdw_version, unique_id, mfg_id;
- unsigned int link_id, part_id, class_id;
- int codec_index, comp_index;
- char *codec_str;
- u64 adr;
-
- adr = link->adr_d[i].adr;
-
- sdw_version = SDW_VERSION(adr);
- link_id = SDW_DISCO_LINK_ID(adr);
- unique_id = SDW_UNIQUE_ID(adr);
- mfg_id = SDW_MFG_ID(adr);
- part_id = SDW_PART_ID(adr);
- class_id = SDW_CLASS_ID(adr);
-
- comp_index = i - adr_index + offset;
- if (is_unique_device(link, sdw_version, mfg_id, part_id,
- class_id, i)) {
- codec_str = "sdw:%01x:%04x:%04x:%02x";
- codec[comp_index].name =
- devm_kasprintf(dev, GFP_KERNEL, codec_str,
- link_id, mfg_id, part_id,
- class_id);
- } else {
- codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
- codec[comp_index].name =
- devm_kasprintf(dev, GFP_KERNEL, codec_str,
- link_id, mfg_id, part_id,
- class_id, unique_id);
- }
-
- if (!codec[comp_index].name)
- return -ENOMEM;
-
- codec_index = find_codec_info_part(adr);
- if (codec_index < 0)
- return codec_index;
- if (_codec_index != -1 && codec_index != _codec_index) {
- dev_dbg(dev, "Different devices on the same sdw link\n");
- break;
- }
- _codec_index = codec_index;
+ unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id;
+ u64 adr = adr_link->adr_d[adr_index].adr;
+ int codec_index;
- codec[comp_index].dai_name =
- codec_info_list[codec_index].dais[dai_index].dai_name;
+ codec_index = find_codec_info_part(adr);
+ if (codec_index < 0)
+ return codec_index;
- codec_conf[*codec_conf_index].dlc = codec[comp_index];
- codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
+ sdw_version = SDW_VERSION(adr);
+ link_id = SDW_DISCO_LINK_ID(adr);
+ unique_id = SDW_UNIQUE_ID(adr);
+ mfg_id = SDW_MFG_ID(adr);
+ part_id = SDW_PART_ID(adr);
+ class_id = SDW_CLASS_ID(adr);
+
+ if (codec_info_list[codec_index].codec_name)
+ codec->name = devm_kstrdup(dev,
+ codec_info_list[codec_index].codec_name,
+ GFP_KERNEL);
+ else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
+ class_id, adr_index))
+ codec->name = devm_kasprintf(dev, GFP_KERNEL,
+ "sdw:%01x:%04x:%04x:%02x", link_id,
+ mfg_id, part_id, class_id);
+ else
+ codec->name = devm_kasprintf(dev, GFP_KERNEL,
+ "sdw:%01x:%04x:%04x:%02x:%01x", link_id,
+ mfg_id, part_id, class_id, unique_id);
+
+ if (!codec->name)
+ return -ENOMEM;
- ++*codec_conf_index;
- }
+ codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name;
return 0;
}
static int set_codec_init_func(struct snd_soc_card *card,
- const struct snd_soc_acpi_link_adr *link,
+ const struct snd_soc_acpi_link_adr *adr_link,
struct snd_soc_dai_link *dai_links,
bool playback, int group_id, int adr_index, int dai_index)
{
@@ -1212,34 +1214,34 @@ static int set_codec_init_func(struct snd_soc_card *card,
* Initialize the codec. If codec is part of an aggregated
* group (group_id>0), initialize all codecs belonging to
* same group.
- * The first link should start with link->adr_d[adr_index]
+ * The first link should start with adr_link->adr_d[adr_index]
* because that is the device that we want to initialize and
* we should end immediately if it is not aggregated (group_id=0)
*/
- for ( ; i < link->num_adr; i++) {
+ for ( ; i < adr_link->num_adr; i++) {
int codec_index;
- codec_index = find_codec_info_part(link->adr_d[i].adr);
-
+ codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
if (codec_index < 0)
return codec_index;
/* The group_id is > 0 iff the codec is aggregated */
- if (link->adr_d[i].endpoints->group_id != group_id)
+ if (adr_link->adr_d[i].endpoints->group_id != group_id)
continue;
if (codec_info_list[codec_index].dais[dai_index].init)
codec_info_list[codec_index].dais[dai_index].init(card,
- link,
+ adr_link,
dai_links,
&codec_info_list[codec_index],
playback);
if (!group_id)
return 0;
}
+
i = 0;
- link++;
- } while (link->mask);
+ adr_link++;
+ } while (adr_link->mask);
return 0;
}
@@ -1261,73 +1263,45 @@ static int set_codec_init_func(struct snd_soc_card *card,
static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
int *codec_num, unsigned int *group_id,
- bool *group_generated, int adr_index)
+ int adr_index)
{
- const struct snd_soc_acpi_adr_device *adr_d;
- const struct snd_soc_acpi_link_adr *adr_next;
- bool no_aggregation;
- int index = 0;
+ bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
int i;
- no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
- adr_d = &adr_link->adr_d[adr_index];
-
- /* make sure the link mask has a single bit set */
- if (!is_power_of_2(adr_link->mask))
- return -EINVAL;
-
- cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
- if (!adr_d->endpoints->aggregated || no_aggregation) {
+ if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) {
+ cpu_dai_id[0] = ffs(adr_link->mask) - 1;
*cpu_dai_num = 1;
*codec_num = 1;
*group_id = 0;
return 0;
}
- *group_id = adr_d->endpoints->group_id;
-
- /* Count endpoints with the same group_id in the adr_link */
*codec_num = 0;
- for (i = 0; i < adr_link->num_adr; i++) {
- if (adr_link->adr_d[i].endpoints->aggregated &&
- adr_link->adr_d[i].endpoints->group_id == *group_id)
- (*codec_num)++;
- }
+ *cpu_dai_num = 0;
+ *group_id = adr_link->adr_d[adr_index].endpoints->group_id;
- /* gather other link ID of slaves in the same group */
- for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
- adr_next++) {
- const struct snd_soc_acpi_endpoint *endpoint;
+ /* Count endpoints with the same group_id in the adr_link */
+ for (; adr_link && adr_link->num_adr; adr_link++) {
+ unsigned int link_codecs = 0;
- endpoint = adr_next->adr_d->endpoints;
- if (!endpoint->aggregated ||
- endpoint->group_id != *group_id)
- continue;
+ for (i = 0; i < adr_link->num_adr; i++) {
+ if (adr_link->adr_d[i].endpoints->aggregated &&
+ adr_link->adr_d[i].endpoints->group_id == *group_id)
+ link_codecs++;
+ }
- /* make sure the link mask has a single bit set */
- if (!is_power_of_2(adr_next->mask))
- return -EINVAL;
+ if (link_codecs) {
+ *codec_num += link_codecs;
- if (index >= SDW_MAX_CPU_DAIS) {
- dev_err(dev, " cpu_dai_id array overflows");
- return -EINVAL;
- }
+ if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) {
+ dev_err(dev, "cpu_dai_id array overflowed\n");
+ return -EINVAL;
+ }
- cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
- for (i = 0; i < adr_next->num_adr; i++) {
- if (adr_next->adr_d[i].endpoints->aggregated &&
- adr_next->adr_d[i].endpoints->group_id == *group_id)
- (*codec_num)++;
+ cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1;
}
}
- /*
- * indicate CPU DAIs for this group have been generated
- * to avoid generating CPU DAIs for this group again.
- */
- group_generated[*group_id] = true;
- *cpu_dai_num = index;
-
return 0;
}
@@ -1344,37 +1318,36 @@ static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_m
static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
-static int create_sdw_dailink(struct snd_soc_card *card,
- struct device *dev, int *link_index,
+static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
struct snd_soc_dai_link *dai_links,
int sdw_be_num, int sdw_cpu_dai_num,
struct snd_soc_dai_link_component *cpus,
- const struct snd_soc_acpi_link_adr *link,
- int *cpu_id, bool *group_generated,
- struct snd_soc_codec_conf *codec_conf,
- int codec_count, int *link_id,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int *cpu_id, struct snd_soc_codec_conf *codec_conf,
+ int codec_count, int *be_id,
int *codec_conf_index,
bool *ignore_pch_dmic,
bool append_dai_type,
int adr_index,
int dai_index)
{
- const struct snd_soc_acpi_link_adr *link_next;
+ struct device *dev = card->dev;
+ const struct snd_soc_acpi_link_adr *adr_link_next;
struct snd_soc_dai_link_component *codecs;
struct sof_sdw_codec_info *codec_info;
int cpu_dai_id[SDW_MAX_CPU_DAIS];
int cpu_dai_num, cpu_dai_index;
unsigned int group_id;
- int codec_idx = 0;
+ int codec_dlc_index = 0;
int codec_index;
int codec_num;
int stream;
int i = 0;
+ int j, k;
int ret;
- int k;
- ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
- &group_id, group_generated, adr_index);
+ ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
+ &group_id, adr_index);
if (ret)
return ret;
@@ -1383,32 +1356,50 @@ static int create_sdw_dailink(struct snd_soc_card *card,
return -ENOMEM;
/* generate codec name on different links in the same group */
- for (link_next = link; link_next && link_next->num_adr &&
- i < cpu_dai_num; link_next++) {
- const struct snd_soc_acpi_endpoint *endpoints;
-
- endpoints = link_next->adr_d->endpoints;
- if (group_id && (!endpoints->aggregated ||
- endpoints->group_id != group_id))
- continue;
-
+ j = adr_index;
+ for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr &&
+ i < cpu_dai_num; adr_link_next++) {
/* skip the link excluded by this processed group */
- if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
+ if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1)
continue;
- ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
- codec_conf, codec_count, codec_conf_index,
- adr_index, dai_index);
- if (ret < 0)
- return ret;
+ /* j reset after loop, adr_index only applies to first link */
+ for (; j < adr_link_next->num_adr; j++) {
+ const struct snd_soc_acpi_endpoint *endpoints;
+
+ endpoints = adr_link_next->adr_d[j].endpoints;
+
+ if (group_id && (!endpoints->aggregated ||
+ endpoints->group_id != group_id))
+ continue;
+
+ /* sanity check */
+ if (*codec_conf_index >= codec_count) {
+ dev_err(dev, "codec_conf array overflowed\n");
+ return -EINVAL;
+ }
+
+ ret = fill_sdw_codec_dlc(dev, adr_link_next,
+ &codecs[codec_dlc_index],
+ j, dai_index);
+ if (ret)
+ return ret;
+
+ codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index];
+ codec_conf[*codec_conf_index].name_prefix =
+ adr_link_next->adr_d[j].name_prefix;
+
+ codec_dlc_index++;
+ (*codec_conf_index)++;
+ }
+ j = 0;
/* check next link to create codec dai in the processed group */
i++;
- codec_idx += link_next->num_adr;
}
/* find codec info to create BE DAI */
- codec_index = find_codec_info_part(link->adr_d[adr_index].adr);
+ codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr);
if (codec_index < 0)
return codec_index;
codec_info = &codec_info_list[codec_index];
@@ -1431,9 +1422,9 @@ static int create_sdw_dailink(struct snd_soc_card *card,
if (!codec_info->dais[dai_index].direction[stream])
continue;
- *link_id = codec_info->dais[dai_index].dailink[stream];
- if (*link_id < 0) {
- dev_err(dev, "Invalid dailink id %d\n", *link_id);
+ *be_id = codec_info->dais[dai_index].dailink[stream];
+ if (*be_id < 0) {
+ dev_err(dev, "Invalid dailink id %d\n", *be_id);
return -EINVAL;
}
@@ -1466,7 +1457,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
return -ENOMEM;
if (cpu_dai_index >= sdw_cpu_dai_num) {
- dev_err(dev, "invalid cpu dai index %d",
+ dev_err(dev, "invalid cpu dai index %d\n",
cpu_dai_index);
return -EINVAL;
}
@@ -1479,18 +1470,18 @@ static int create_sdw_dailink(struct snd_soc_card *card,
* not be larger than sdw_be_num
*/
if (*link_index >= sdw_be_num) {
- dev_err(dev, "invalid dai link index %d", *link_index);
+ dev_err(dev, "invalid dai link index %d\n", *link_index);
return -EINVAL;
}
if (*cpu_id >= sdw_cpu_dai_num) {
- dev_err(dev, " invalid cpu dai index %d", *cpu_id);
+ dev_err(dev, "invalid cpu dai index %d\n", *cpu_id);
return -EINVAL;
}
playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
- init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
+ init_dai_link(dev, dai_links + *link_index, (*be_id)++, name,
playback, capture,
cpus + *cpu_id, cpu_dai_num,
codecs, codec_num,
@@ -1504,10 +1495,10 @@ static int create_sdw_dailink(struct snd_soc_card *card,
set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps;
- ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
+ ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
playback, group_id, adr_index, dai_index);
if (ret < 0) {
- dev_err(dev, "failed to init codec %d", codec_index);
+ dev_err(dev, "failed to init codec %d\n", codec_index);
return ret;
}
@@ -1519,65 +1510,26 @@ static int create_sdw_dailink(struct snd_soc_card *card,
#define IDISP_CODEC_MASK 0x4
-static int sof_card_codec_conf_alloc(struct device *dev,
- struct snd_soc_acpi_mach_params *mach_params,
- struct snd_soc_codec_conf **codec_conf,
- int *codec_conf_count)
+static int sof_card_dai_links_create(struct snd_soc_card *card)
{
- const struct snd_soc_acpi_link_adr *adr_link;
- struct snd_soc_codec_conf *c_conf;
- int num_codecs = 0;
- int codec_index;
- int i;
-
- adr_link = mach_params->links;
- if (!adr_link)
- return -EINVAL;
-
- /* generate DAI links by each sdw link */
- for (; adr_link->num_adr; adr_link++) {
- for (i = 0; i < adr_link->num_adr; i++) {
- if (!adr_link->adr_d[i].name_prefix) {
- dev_err(dev, "codec 0x%llx does not have a name prefix\n",
- adr_link->adr_d[i].adr);
- return -EINVAL;
- }
- codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
- if (codec_index < 0)
- return codec_index;
- num_codecs += codec_info_list[codec_index].dai_num;
- }
- }
-
- c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
- if (!c_conf)
- return -ENOMEM;
-
- *codec_conf = c_conf;
- *codec_conf_count = num_codecs;
-
- return 0;
-}
-
-static int sof_card_dai_links_create(struct device *dev,
- struct snd_soc_acpi_mach *mach,
- struct snd_soc_card *card)
-{
- int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
+ struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+ int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link_component *idisp_components;
struct snd_soc_dai_link_component *ssp_components;
- struct snd_soc_acpi_mach_params *mach_params;
- const struct snd_soc_acpi_link_adr *adr_link;
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+ const struct snd_soc_acpi_link_adr *adr_link = mach_params->links;
+ bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION);
struct snd_soc_dai_link_component *cpus;
struct snd_soc_codec_conf *codec_conf;
bool append_dai_type = false;
bool ignore_pch_dmic = false;
- int codec_conf_count;
+ int codec_conf_num = 0;
int codec_conf_index = 0;
- bool group_generated[SDW_MAX_GROUPS];
+ bool group_generated[SDW_MAX_GROUPS] = { };
int ssp_codec_index, ssp_mask;
- struct snd_soc_dai_link *links;
+ struct snd_soc_dai_link *dai_links;
int num_links, link_index = 0;
char *name, *cpu_name;
int total_cpu_dai_num;
@@ -1585,30 +1537,15 @@ static int sof_card_dai_links_create(struct device *dev,
int i, j, be_id = 0;
int codec_index;
int cpu_id = 0;
- int comp_num;
int ret;
- mach_params = &mach->mach_params;
-
- /* allocate codec conf, will be populated when dailinks are created */
- ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
- if (ret < 0)
+ ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num,
+ &codec_conf_num);
+ if (ret < 0) {
+ dev_err(dev, "failed to get sdw link info %d\n", ret);
return ret;
-
- /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
- for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
- codec_info_list[i].amp_num = 0;
-
- if (mach_params->codec_mask & IDISP_CODEC_MASK) {
- ctx->idisp_codec = true;
-
- if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
- hdmi_num = SOF_TGL_HDMI_COUNT;
- else
- hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
}
- ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
/*
* on generic tgl platform, I2S or sdw mode is supported
* based on board rework. A ACPI device is registered in
@@ -1616,54 +1553,52 @@ static int sof_card_dai_links_create(struct device *dev,
* Here check ACPI ID to confirm I2S is supported.
*/
ssp_codec_index = find_codec_info_acpi(mach->id);
- ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
- comp_num = hdmi_num + ssp_num;
+ if (ssp_codec_index >= 0) {
+ ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
+ ssp_num = hweight_long(ssp_mask);
+ }
- ret = get_sdw_dailink_info(dev, mach_params->links,
- &sdw_be_num, &sdw_cpu_dai_num);
- if (ret < 0) {
- dev_err(dev, "failed to get sdw link info %d", ret);
- return ret;
+ if (mach_params->codec_mask & IDISP_CODEC_MASK) {
+ ctx->idisp_codec = true;
+
+ if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
+ hdmi_num = SOF_TGL_HDMI_COUNT;
+ else
+ hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
}
/* enable dmic01 & dmic16k */
- dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
- comp_num += dmic_num;
+ if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num)
+ dmic_num = 2;
if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
- comp_num++;
+ bt_num = 1;
- dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
- dmic_num, ctx->idisp_codec ? hdmi_num : 0);
+ dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
+ sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num);
/* allocate BE dailinks */
- num_links = comp_num + sdw_be_num;
- links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
+ num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
+ dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
+ if (!dai_links)
+ return -ENOMEM;
/* allocated CPU DAIs */
- total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
- cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
- GFP_KERNEL);
+ total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num;
+ cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL);
+ if (!cpus)
+ return -ENOMEM;
- if (!links || !cpus)
+ /* allocate codec conf, will be populated when dailinks are created */
+ codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf),
+ GFP_KERNEL);
+ if (!codec_conf)
return -ENOMEM;
/* SDW */
if (!sdw_be_num)
goto SSP;
- adr_link = mach_params->links;
- if (!adr_link)
- return -EINVAL;
-
- /*
- * SoundWire Slaves aggregated in the same group may be
- * located on different hardware links. Clear array to indicate
- * CPU DAIs for this group have not been generated.
- */
- for (i = 0; i < SDW_MAX_GROUPS; i++)
- group_generated[i] = false;
-
for (i = 0; i < SDW_MAX_LINKS; i++)
sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
@@ -1702,11 +1637,6 @@ out:
const struct snd_soc_acpi_endpoint *endpoint;
endpoint = adr_link->adr_d[i].endpoints;
- if (endpoint->aggregated && !endpoint->group_id) {
- dev_err(dev, "invalid group id on link %x",
- adr_link->mask);
- continue;
- }
/* this group has been generated */
if (endpoint->aggregated &&
@@ -1719,17 +1649,20 @@ out:
return codec_index;
for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) {
- ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
- sdw_cpu_dai_num, cpus, adr_link,
- &cpu_id, group_generated,
- codec_conf, codec_conf_count,
+ ret = create_sdw_dailink(card, &link_index, dai_links,
+ sdw_be_num, sdw_cpu_dai_num, cpus,
+ adr_link, &cpu_id,
+ codec_conf, codec_conf_num,
&be_id, &codec_conf_index,
&ignore_pch_dmic, append_dai_type, i, j);
if (ret < 0) {
- dev_err(dev, "failed to create dai link %d", link_index);
+ dev_err(dev, "failed to create dai link %d\n", link_index);
return ret;
}
}
+
+ if (aggregation && endpoint->aggregated)
+ group_generated[endpoint->group_id] = true;
}
}
@@ -1773,13 +1706,13 @@ SSP:
playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
- init_dai_link(dev, links + link_index, be_id, name,
+ init_dai_link(dev, dai_links + link_index, be_id, name,
playback, capture,
cpus + cpu_id, 1,
ssp_components, 1,
NULL, info->ops);
- ret = info->dais[0].init(card, NULL, links + link_index, info, 0);
+ ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0);
if (ret < 0)
return ret;
@@ -1794,7 +1727,7 @@ DMIC:
goto HDMI;
}
cpus[cpu_id].dai_name = "DMIC01 Pin";
- init_dai_link(dev, links + link_index, be_id, "dmic01",
+ init_dai_link(dev, dai_links + link_index, be_id, "dmic01",
0, 1, // DMIC only supports capture
cpus + cpu_id, 1,
dmic_component, 1,
@@ -1802,7 +1735,7 @@ DMIC:
INC_ID(be_id, cpu_id, link_index);
cpus[cpu_id].dai_name = "DMIC16k Pin";
- init_dai_link(dev, links + link_index, be_id, "dmic16k",
+ init_dai_link(dev, dai_links + link_index, be_id, "dmic16k",
0, 1, // DMIC only supports capture
cpus + cpu_id, 1,
dmic_component, 1,
@@ -1845,7 +1778,7 @@ HDMI:
return -ENOMEM;
cpus[cpu_id].dai_name = cpu_name;
- init_dai_link(dev, links + link_index, be_id, name,
+ init_dai_link(dev, dai_links + link_index, be_id, name,
1, 0, // HDMI only supports playback
cpus + cpu_id, 1,
idisp_components + i, 1,
@@ -1866,15 +1799,15 @@ HDMI:
return -ENOMEM;
cpus[cpu_id].dai_name = cpu_name;
- init_dai_link(dev, links + link_index, be_id, name, 1, 1,
- cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
+ init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1,
+ cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
}
- card->dai_link = links;
+ card->dai_link = dai_links;
card->num_links = num_links;
card->codec_conf = codec_conf;
- card->num_configs = codec_conf_count;
+ card->num_configs = codec_conf_num;
return 0;
}
@@ -1913,15 +1846,15 @@ static struct snd_soc_card card_sof_sdw = {
static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
const char *dai_name)
{
- struct snd_soc_dai_link *link;
+ struct snd_soc_dai_link *dai_link;
int i;
int j;
- for_each_card_prelinks(card, i, link) {
- for (j = 0; j < link->num_codecs; j++) {
+ for_each_card_prelinks(card, i, dai_link) {
+ for (j = 0; j < dai_link->num_codecs; j++) {
/* Check each codec in a link */
- if (!strcmp(link->codecs[j].dai_name, dai_name))
- return link;
+ if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
+ return dai_link;
}
}
return NULL;
@@ -1929,7 +1862,7 @@ static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card
static void mc_dailink_exit_loop(struct snd_soc_card *card)
{
- struct snd_soc_dai_link *link;
+ struct snd_soc_dai_link *dai_link;
int ret;
int i, j;
@@ -1942,10 +1875,11 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card)
* We don't need to call .exit function if there is no matched
* dai link found.
*/
- link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name);
- if (link) {
+ dai_link = mc_find_codec_dai_used(card,
+ codec_info_list[i].dais[j].dai_name);
+ if (dai_link) {
/* Do the .exit function if the codec dai is used in the link */
- ret = codec_info_list[i].dais[j].exit(card, link);
+ ret = codec_info_list[i].dais[j].exit(card, dai_link);
if (ret)
dev_warn(card->dev,
"codec exit failed %d\n",
@@ -1959,34 +1893,38 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card)
static int mc_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &card_sof_sdw;
- struct snd_soc_acpi_mach *mach;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
struct mc_private *ctx;
int amp_num = 0, i;
int ret;
- dev_dbg(&pdev->dev, "Entry\n");
+ card->dev = &pdev->dev;
+
+ dev_dbg(card->dev, "Entry\n");
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+ snd_soc_card_set_drvdata(card, ctx);
+
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
sof_sdw_quirk, quirk_override);
sof_sdw_quirk = quirk_override;
}
- log_quirks(&pdev->dev);
- INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+ log_quirks(card->dev);
- card->dev = &pdev->dev;
- snd_soc_card_set_drvdata(card, ctx);
+ /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
+ for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
+ codec_info_list[i].amp_num = 0;
- mach = pdev->dev.platform_data;
- ret = sof_card_dai_links_create(&pdev->dev, mach,
- card);
+ ret = sof_card_dai_links_create(card);
if (ret < 0)
return ret;
@@ -2017,7 +1955,7 @@ static int mc_probe(struct platform_device *pdev)
card->long_name = sdw_card_long_name;
/* Register the card */
- ret = devm_snd_soc_register_card(&pdev->dev, card);
+ ret = devm_snd_soc_register_card(card->dev, card);
if (ret) {
dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
mc_dailink_exit_loop(card);
@@ -2036,6 +1974,12 @@ static void mc_remove(struct platform_device *pdev)
mc_dailink_exit_loop(card);
}
+static const struct platform_device_id mc_id_table[] = {
+ { "sof_sdw", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, mc_id_table);
+
static struct platform_driver sof_sdw_driver = {
.driver = {
.name = "sof_sdw",
@@ -2043,6 +1987,7 @@ static struct platform_driver sof_sdw_driver = {
},
.probe = mc_probe,
.remove_new = mc_remove,
+ .id_table = mc_id_table,
};
module_platform_driver(sof_sdw_driver);
@@ -2052,6 +1997,5 @@ MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sof_sdw");
MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h
index 37402170d5f9..2f4fe6bc3d5d 100644
--- a/sound/soc/intel/boards/sof_sdw_common.h
+++ b/sound/soc/intel/boards/sof_sdw_common.h
@@ -80,6 +80,7 @@ struct sof_sdw_dai_info {
struct sof_sdw_codec_info {
const int part_id;
const int version_id;
+ const char *codec_name;
int amp_num;
const u8 acpi_id[ACPI_ID_LEN];
const bool ignore_pch_dmic;
@@ -205,4 +206,10 @@ int sof_sdw_cs42l42_init(struct snd_soc_card *card,
struct sof_sdw_codec_info *info,
bool playback);
+/* CS AMP support */
+int sof_sdw_cs_amp_init(struct snd_soc_card *card,
+ const struct snd_soc_acpi_link_adr *link,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback);
#endif
diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c
new file mode 100644
index 000000000000..98f6546f484b
--- /dev/null
+++ b/sound/soc/intel/boards/sof_sdw_cs_amp.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023 Intel Corporation
+
+/*
+ * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "sof_sdw_common.h"
+
+#define CODEC_NAME_SIZE 8
+
+static int cs_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *dai_name = rtd->dai_link->codecs->dai_name;
+ struct snd_soc_card *card = rtd->card;
+ char codec_name[CODEC_NAME_SIZE];
+
+ snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name);
+ card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ "%s spk:%s",
+ card->components, codec_name);
+ if (!card->components)
+ return -ENOMEM;
+
+ return 0;
+}
+
+
+int sof_sdw_cs_amp_init(struct snd_soc_card *card,
+ const struct snd_soc_acpi_link_adr *link,
+ struct snd_soc_dai_link *dai_links,
+ struct sof_sdw_codec_info *info,
+ bool playback)
+{
+ /* Count amp number and do init on playback link only. */
+ if (!playback)
+ return 0;
+
+ info->amp_num++;
+ dai_links->init = cs_spk_init;
+
+ return 0;
+}
diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c
index 0aef718e82b2..5aa16fd3939b 100644
--- a/sound/soc/intel/boards/sof_ssp_amp.c
+++ b/sound/soc/intel/boards/sof_ssp_amp.c
@@ -472,6 +472,15 @@ static const struct platform_device_id board_ids[] = {
SOF_NO_OF_HDMI_PLAYBACK(3) |
SOF_HDMI_PLAYBACK_PRESENT),
},
+ {
+ .name = "rpl_lt6911_hdmi_ssp",
+ .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+ SOF_HDMI_CAPTURE_1_SSP(0) |
+ SOF_HDMI_CAPTURE_2_SSP(2) |
+ SOF_SSP_HDMI_CAPTURE_PRESENT |
+ SOF_NO_OF_HDMI_PLAYBACK(3) |
+ SOF_HDMI_PLAYBACK_PRESENT),
+ },
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index 30ca5416c9a3..f1a5cb825ff1 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -684,6 +684,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
return 0;
}
+static const struct snd_soc_dai_ops catpt_dai_ops = {
+ .pcm_new = catpt_dai_pcm_new,
+};
+
static struct snd_soc_dai_driver dai_drivers[] = {
/* FE DAIs */
{
@@ -764,7 +768,6 @@ static struct snd_soc_dai_driver dai_drivers[] = {
{
.name = "ssp0-port",
.id = CATPT_SSP_IFACE_0,
- .pcm_new = catpt_dai_pcm_new,
.playback = {
.channels_min = 1,
.channels_max = 8,
@@ -773,11 +776,11 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 1,
.channels_max = 8,
},
+ .ops = &catpt_dai_ops,
},
{
.name = "ssp1-port",
.id = CATPT_SSP_IFACE_1,
- .pcm_new = catpt_dai_pcm_new,
.playback = {
.channels_min = 1,
.channels_max = 8,
@@ -786,6 +789,7 @@ static struct snd_soc_dai_driver dai_drivers[] = {
.channels_min = 1,
.channels_max = 8,
},
+ .ops = &catpt_dai_ops,
},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index bcd66e0094b4..8e995edf4c10 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -570,6 +570,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
},
{
.comp_ids = &adl_rt5682_rt5682s_hp,
+ .drv_name = "adl_rt5682_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &adl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &adl_rt5682_rt5682s_hp,
.drv_name = "adl_rt5682",
.sof_tplg_filename = "sof-adl-rt5682.tplg",
},
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index ed9821adc1d9..0304246d2922 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -161,6 +161,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+ {
+ .adr = 0x000130025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1318-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+ {
+ .adr = 0x000232025D131801ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1318-2"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+ {
+ .adr = 0x000030025D071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
{
.adr = 0x000130025D071401ull,
@@ -232,6 +259,25 @@ static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = {
{}
};
+static const struct snd_soc_acpi_link_adr mtl_sdw_rt1318_l12_rt714_l0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+ .adr_d = rt1318_1_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+ .adr_d = rt1318_2_group1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt714_0_adr),
+ .adr_d = rt714_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = {
{
.adr = 0x000230019F836300ull,
@@ -299,6 +345,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
},
{
+ .link_mask = GENMASK(2, 0),
+ .links = mtl_sdw_rt1318_l12_rt714_l0,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg"
+ },
+ {
.link_mask = GENMASK(3, 0),
.links = mtl_3_in_1_sdca,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
index 302a08018572..122673c1dae2 100644
--- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c
@@ -308,6 +308,15 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] =
{}
};
+static const struct snd_soc_acpi_link_adr rpl_sdca_rvp[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+ .adr_d = rt711_sdca_0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr rplp_crb[] = {
{
.mask = BIT(2),
@@ -322,6 +331,16 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = {
.codecs = {"10EC5682", "RTL5682"},
};
+static const struct snd_soc_acpi_codecs rpl_essx_83x6 = {
+ .num_codecs = 3,
+ .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
+static const struct snd_soc_acpi_codecs rpl_max98357a_amp = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
static const struct snd_soc_acpi_codecs rpl_max98360a_amp = {
.num_codecs = 1,
.codecs = {"MX98360A"},
@@ -332,6 +351,16 @@ static const struct snd_soc_acpi_codecs rpl_max98373_amp = {
.codecs = {"MX98373"}
};
+static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = {
+ .num_codecs = 1,
+ .codecs = {"INTC10B0"}
+};
+
+static const struct snd_soc_acpi_codecs rpl_nau8318_amp = {
+ .num_codecs = 1,
+ .codecs = {"NVTN2012"}
+};
+
static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = {
.num_codecs = 1,
.codecs = {"RTL1019"}
@@ -340,6 +369,13 @@ static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = {
struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
{
.comp_ids = &rpl_rt5682_hp,
+ .drv_name = "rpl_mx98357_rt5682",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rpl_max98357a_amp,
+ .sof_tplg_filename = "sof-rpl-max98357a-rt5682.tplg",
+ },
+ {
+ .comp_ids = &rpl_rt5682_hp,
.drv_name = "rpl_mx98360_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rpl_max98360a_amp,
@@ -353,12 +389,39 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
.sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg",
},
{
+ .id = "10508825",
+ .drv_name = "rpl_nau8318_8825",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rpl_nau8318_amp,
+ .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg",
+ },
+ {
.comp_ids = &rpl_rt5682_hp,
.drv_name = "rpl_rt1019_rt5682",
.machine_quirk = snd_soc_acpi_codec_list,
.quirk_data = &rpl_rt1019p_amp,
.sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg",
},
+ {
+ .comp_ids = &rpl_essx_83x6,
+ .drv_name = "rpl_es83x6_c1_h02",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &rpl_lt6911_hdmi,
+ .sof_tplg_filename = "sof-rpl-es83x6-ssp1-hdmi-ssp02.tplg",
+ },
+ {
+ .comp_ids = &rpl_essx_83x6,
+ .drv_name = "sof-essx8336",
+ .sof_tplg_filename = "sof-rpl-es83x6", /* the tplg suffix is added at run time */
+ .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+ SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+ SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+ },
+ {
+ .id = "INTC10B0",
+ .drv_name = "rpl_lt6911_hdmi_ssp",
+ .sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg"
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines);
@@ -414,6 +477,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
.sof_tplg_filename = "sof-rpl-rt711-l0.tplg",
},
{
+ .link_mask = 0x1, /* link0 required */
+ .links = rpl_sdca_rvp,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-rpl-rt711-l0.tplg",
+ },
+ {
.link_mask = 0x4, /* link2 required */
.links = rplp_crb,
.drv_name = "sof_sdw",
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index b4893365d01d..6b06b7b5ede8 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -733,6 +733,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops kmb_dai_ops = {
+ .probe = kmb_probe,
.startup = kmb_dai_startup,
.trigger = kmb_dai_trigger,
.hw_params = kmb_dai_hw_params,
@@ -755,7 +756,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
},
.ops = &kmb_dai_ops,
- .probe = kmb_probe,
},
};
@@ -787,7 +787,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
SNDRV_PCM_FMTBIT_S16_LE),
},
.ops = &kmb_dai_ops,
- .probe = kmb_probe,
},
};
@@ -807,7 +806,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
SNDRV_PCM_FMTBIT_S16_LE),
},
.ops = &kmb_dai_ops,
- .probe = kmb_probe,
},
};
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 578af21769c9..517619531615 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
+ .probe = jz4740_i2s_dai_probe,
.startup = jz4740_i2s_startup,
.shutdown = jz4740_i2s_shutdown,
.trigger = jz4740_i2s_trigger,
@@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver jz4740_i2s_dai = {
- .probe = jz4740_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = {
};
static struct snd_soc_dai_driver jz4770_i2s_dai = {
- .probe = jz4740_i2s_dai_probe,
.playback = {
.channels_min = 1,
.channels_max = 2,
diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index 9ded16329747..406ee8db1a3c 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -208,7 +208,7 @@ static struct platform_driver loongson_audio_driver = {
.driver = {
.name = "loongson-asoc-card",
.pm = &snd_soc_pm_ops,
- .of_match_table = of_match_ptr(loongson_asoc_dt_ids),
+ .of_match_table = loongson_asoc_dt_ids,
},
};
module_platform_driver(loongson_audio_driver);
diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c
index b919f0fe8361..d45228a3a558 100644
--- a/sound/soc/loongson/loongson_i2s.c
+++ b/sound/soc/loongson/loongson_i2s.c
@@ -204,13 +204,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
- .trigger = loongson_i2s_trigger,
- .hw_params = loongson_i2s_hw_params,
- .set_sysclk = loongson_i2s_set_dai_sysclk,
- .set_fmt = loongson_i2s_set_fmt,
-};
-
static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
@@ -222,9 +215,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
return 0;
}
+static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
+ .probe = loongson_i2s_dai_probe,
+ .trigger = loongson_i2s_trigger,
+ .hw_params = loongson_i2s_hw_params,
+ .set_sysclk = loongson_i2s_set_dai_sysclk,
+ .set_fmt = loongson_i2s_set_fmt,
+};
+
struct snd_soc_dai_driver loongson_i2s_dai = {
.name = "loongson-i2s",
- .probe = loongson_i2s_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 90db67e0ce4f..8d1bc8814486 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -54,6 +54,26 @@ config SND_SOC_MT6797_MT6351
Select Y if you have such device.
If unsure select "N".
+config SND_SOC_MT7986
+ tristate "ASoC support for Mediatek MT7986 chip"
+ depends on ARCH_MEDIATEK
+ select SND_SOC_MEDIATEK
+ help
+ This adds ASoC platform driver support for MediaTek MT7986 chip
+ that can be used with other codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
+config SND_SOC_MT7986_WM8960
+ tristate "ASoc Audio driver for MT7986 with WM8960 codec"
+ depends on SND_SOC_MT7986 && I2C
+ select SND_SOC_WM8960
+ help
+ This adds support for ASoC machine driver for MediaTek MT7986
+ boards with the WM8960 codecs.
+ Select Y if you have such device.
+ If unsure select "N".
+
config SND_SOC_MT8173
tristate "ASoC support for Mediatek MT8173 chip"
depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 3de38cfc69e5..3938e7f75c2e 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
+obj-$(CONFIG_SND_SOC_MT7986) += mt7986/
obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile
new file mode 100644
index 000000000000..fc4c82559b29
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt7986-afe-objs := \
+ mt7986-afe-pcm.o \
+ mt7986-dai-etdm.o
+
+obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
+obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
new file mode 100644
index 000000000000..fc3bb31e5167
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt7986-afe-common.h -- MediaTek 7986 audio driver definitions
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#ifndef _MT_7986_AFE_COMMON_H_
+#define _MT_7986_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+ MT7986_MEMIF_DL1,
+ MT7986_MEMIF_VUL12,
+ MT7986_MEMIF_NUM,
+ MT7986_DAI_ETDM = MT7986_MEMIF_NUM,
+ MT7986_DAI_NUM,
+};
+
+enum {
+ MT7986_IRQ_0,
+ MT7986_IRQ_1,
+ MT7986_IRQ_2,
+ MT7986_IRQ_NUM,
+};
+
+struct mt7986_afe_private {
+ struct clk_bulk_data *clks;
+ int num_clks;
+
+ int pm_runtime_bypass_reg_ctl;
+
+ /* dai */
+ void *dai_priv[MT7986_DAI_NUM];
+};
+
+unsigned int mt7986_afe_rate_transform(struct device *dev,
+ unsigned int rate);
+
+/* dai register */
+int mt7986_dai_etdm_register(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
new file mode 100644
index 000000000000..d497e1129889
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC AFE platform driver for MT7986
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+ MTK_AFE_RATE_8K = 0,
+ MTK_AFE_RATE_11K = 1,
+ MTK_AFE_RATE_12K = 2,
+ MTK_AFE_RATE_16K = 4,
+ MTK_AFE_RATE_22K = 5,
+ MTK_AFE_RATE_24K = 6,
+ MTK_AFE_RATE_32K = 8,
+ MTK_AFE_RATE_44K = 9,
+ MTK_AFE_RATE_48K = 10,
+ MTK_AFE_RATE_88K = 13,
+ MTK_AFE_RATE_96K = 14,
+ MTK_AFE_RATE_176K = 17,
+ MTK_AFE_RATE_192K = 18,
+};
+
+enum {
+ CLK_INFRA_AUD_BUS_CK = 0,
+ CLK_INFRA_AUD_26M_CK,
+ CLK_INFRA_AUD_L_CK,
+ CLK_INFRA_AUD_AUD_CK,
+ CLK_INFRA_AUD_EG2_CK,
+ CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+ [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
+ [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck",
+ [CLK_INFRA_AUD_L_CK] = "aud_l_ck",
+ [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
+ [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
+};
+
+unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_AFE_RATE_8K;
+ case 11025:
+ return MTK_AFE_RATE_11K;
+ case 12000:
+ return MTK_AFE_RATE_12K;
+ case 16000:
+ return MTK_AFE_RATE_16K;
+ case 22050:
+ return MTK_AFE_RATE_22K;
+ case 24000:
+ return MTK_AFE_RATE_24K;
+ case 32000:
+ return MTK_AFE_RATE_32K;
+ case 44100:
+ return MTK_AFE_RATE_44K;
+ case 48000:
+ return MTK_AFE_RATE_48K;
+ case 88200:
+ return MTK_AFE_RATE_88K;
+ case 96000:
+ return MTK_AFE_RATE_96K;
+ case 176400:
+ return MTK_AFE_RATE_176K;
+ case 192000:
+ return MTK_AFE_RATE_192K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
+ __func__, rate, MTK_AFE_RATE_48K);
+ return MTK_AFE_RATE_48K;
+ }
+}
+
+static const struct snd_pcm_hardware mt7986_afe_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ .period_bytes_min = 256,
+ .period_bytes_max = 4 * 48 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 8 * 48 * 1024,
+ .fifo_size = 0,
+};
+
+static int mt7986_memif_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ return mt7986_afe_rate_transform(afe->dev, rate);
+}
+
+static int mt7986_irq_fs(struct snd_pcm_substream *substream,
+ unsigned int rate)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+ return mt7986_afe_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = {
+ /* FE DAIs: memory intefaces to CPU */
+ {
+ .name = "DL1",
+ .id = MT7986_MEMIF_DL1,
+ .playback = {
+ .stream_name = "DL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+ {
+ .name = "UL1",
+ .id = MT7986_MEMIF_VUL12,
+ .capture = {
+ .stream_name = "UL1",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_PCM_RATES,
+ .formats = MTK_PCM_FORMATS,
+ },
+ .ops = &mtk_afe_fe_ops,
+ },
+};
+
+static const struct snd_kcontrol_new o018_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new o019_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = {
+ /* DL */
+ SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* UL */
+ SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
+ o018_mix, ARRAY_SIZE(o018_mix)),
+ SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
+ o019_mix, ARRAY_SIZE(o019_mix)),
+};
+
+static const struct snd_soc_dapm_route mt7986_memif_routes[] = {
+ {"I032", NULL, "DL1"},
+ {"I033", NULL, "DL1"},
+ {"UL1", NULL, "O018"},
+ {"UL1", NULL, "O019"},
+ {"O018", "I150_Switch", "I150"},
+ {"O019", "I151_Switch", "I151"},
+};
+
+static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = {
+ .name = "mt7986-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = {
+ [MT7986_MEMIF_DL1] = {
+ .name = "DL1",
+ .id = MT7986_MEMIF_DL1,
+ .reg_ofs_base = AFE_DL0_BASE,
+ .reg_ofs_cur = AFE_DL0_CUR,
+ .reg_ofs_end = AFE_DL0_END,
+ .reg_ofs_base_msb = AFE_DL0_BASE_MSB,
+ .reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
+ .reg_ofs_end_msb = AFE_DL0_END_MSB,
+ .fs_reg = AFE_DL0_CON0,
+ .fs_shift = DL0_MODE_SFT,
+ .fs_maskbit = DL0_MODE_MASK,
+ .mono_reg = AFE_DL0_CON0,
+ .mono_shift = DL0_MONO_SFT,
+ .enable_reg = AFE_DL0_CON0,
+ .enable_shift = DL0_ON_SFT,
+ .hd_reg = AFE_DL0_CON0,
+ .hd_shift = DL0_HD_MODE_SFT,
+ .hd_align_reg = AFE_DL0_CON0,
+ .hd_align_mshift = DL0_HALIGN_SFT,
+ .pbuf_reg = AFE_DL0_CON0,
+ .pbuf_shift = DL0_PBUF_SIZE_SFT,
+ .minlen_reg = AFE_DL0_CON0,
+ .minlen_shift = DL0_MINLEN_SFT,
+ },
+ [MT7986_MEMIF_VUL12] = {
+ .name = "VUL12",
+ .id = MT7986_MEMIF_VUL12,
+ .reg_ofs_base = AFE_VUL0_BASE,
+ .reg_ofs_cur = AFE_VUL0_CUR,
+ .reg_ofs_end = AFE_VUL0_END,
+ .reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
+ .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
+ .reg_ofs_end_msb = AFE_VUL0_END_MSB,
+ .fs_reg = AFE_VUL0_CON0,
+ .fs_shift = VUL0_MODE_SFT,
+ .fs_maskbit = VUL0_MODE_MASK,
+ .mono_reg = AFE_VUL0_CON0,
+ .mono_shift = VUL0_MONO_SFT,
+ .enable_reg = AFE_VUL0_CON0,
+ .enable_shift = VUL0_ON_SFT,
+ .hd_reg = AFE_VUL0_CON0,
+ .hd_shift = VUL0_HD_MODE_SFT,
+ .hd_align_reg = AFE_VUL0_CON0,
+ .hd_align_mshift = VUL0_HALIGN_SFT,
+ },
+};
+
+static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = {
+ [MT7986_IRQ_0] = {
+ .id = MT7986_IRQ_0,
+ .irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+ .irq_fs_reg = AFE_IRQ0_MCU_CFG0,
+ .irq_fs_shift = IRQ_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ0_MCU_CFG0,
+ .irq_en_shift = IRQ_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ0_MCU_CLR_SFT,
+ },
+ [MT7986_IRQ_1] = {
+ .id = MT7986_IRQ_1,
+ .irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+ .irq_fs_reg = AFE_IRQ1_MCU_CFG0,
+ .irq_fs_shift = IRQ_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ1_MCU_CFG0,
+ .irq_en_shift = IRQ_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+ },
+ [MT7986_IRQ_2] = {
+ .id = MT7986_IRQ_2,
+ .irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
+ .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+ .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+ .irq_fs_reg = AFE_IRQ2_MCU_CFG0,
+ .irq_fs_shift = IRQ_MCU_MODE_SFT,
+ .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+ .irq_en_reg = AFE_IRQ2_MCU_CFG0,
+ .irq_en_shift = IRQ_MCU_ON_SFT,
+ .irq_clr_reg = AFE_IRQ_MCU_CLR,
+ .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+ },
+};
+
+static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /*
+ * Those auto-gen regs are read-only, so put it as volatile because
+ * volatile registers cannot be cached, which means that they cannot
+ * be set when power is off
+ */
+
+ switch (reg) {
+ case AFE_DL0_CUR_MSB:
+ case AFE_DL0_CUR:
+ case AFE_DL0_RCH_MON:
+ case AFE_DL0_LCH_MON:
+ case AFE_VUL0_CUR_MSB:
+ case AFE_VUL0_CUR:
+ case AFE_IRQ_MCU_STATUS:
+ case AFE_MEMIF_RD_MON:
+ case AFE_MEMIF_WR_MON:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config mt7986_afe_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .volatile_reg = mt7986_is_volatile_reg,
+ .max_register = AFE_MAX_REGISTER,
+ .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
+};
+
+static int mt7986_init_clock(struct mtk_base_afe *afe)
+{
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret, i;
+
+ afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM,
+ sizeof(*afe_priv->clks), GFP_KERNEL);
+ if (!afe_priv->clks)
+ return -ENOMEM;
+ afe_priv->num_clks = CLK_NUM;
+
+ for (i = 0; i < afe_priv->num_clks; i++)
+ afe_priv->clks[i].id = aud_clks[i];
+
+ ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "Failed to get clocks\n");
+
+ return 0;
+}
+
+static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev)
+{
+ struct mtk_base_afe *afe = dev;
+ struct mtk_base_afe_irq *irq;
+ u32 mcu_en, status, status_mcu;
+ int i, ret;
+ irqreturn_t irq_ret = IRQ_HANDLED;
+
+ /* get irq that is sent to MCU */
+ regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+ ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+ /* only care IRQ which is sent to MCU */
+ status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+ if (ret || status_mcu == 0) {
+ dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+ __func__, ret, status, mcu_en);
+
+ irq_ret = IRQ_NONE;
+ goto err_irq;
+ }
+
+ for (i = 0; i < MT7986_MEMIF_NUM; i++) {
+ struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+ if (!memif->substream)
+ continue;
+
+ if (memif->irq_usage < 0)
+ continue;
+
+ irq = &afe->irqs[memif->irq_usage];
+
+ if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+ snd_pcm_period_elapsed(memif->substream);
+ }
+
+err_irq:
+ /* clear irq */
+ regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
+
+ return irq_ret;
+}
+
+static int mt7986_afe_runtime_suspend(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+
+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+ goto skip_regmap;
+
+ /* disable clk*/
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0);
+
+ /* make sure all irq status are cleared, twice intended */
+ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+skip_regmap:
+ clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
+
+ return 0;
+}
+
+static int mt7986_afe_runtime_resume(struct device *dev)
+{
+ struct mtk_base_afe *afe = dev_get_drvdata(dev);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+
+ if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+ return 0;
+
+ /* enable clk*/
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+ AUD_APLL2_EN);
+ regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+ AUD_26M_EN);
+
+ return 0;
+}
+
+static int mt7986_afe_component_probe(struct snd_soc_component *component)
+{
+ return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt7986_afe_component = {
+ .name = AFE_PCM_NAME,
+ .probe = mt7986_afe_component_probe,
+ .pointer = mtk_afe_pcm_pointer,
+ .pcm_construct = mtk_afe_pcm_new,
+};
+
+static int mt7986_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt7986_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver);
+
+ dai->dapm_widgets = mt7986_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets);
+ dai->dapm_routes = mt7986_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes);
+
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt7986_dai_etdm_register,
+ mt7986_dai_memif_register,
+};
+
+static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+ struct mtk_base_afe *afe;
+ struct mt7986_afe_private *afe_priv;
+ struct device *dev;
+ int i, irq_id, ret;
+
+ afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ if (!afe)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, afe);
+
+ afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+ GFP_KERNEL);
+ if (!afe->platform_priv)
+ return -ENOMEM;
+
+ afe_priv = afe->platform_priv;
+ afe->dev = &pdev->dev;
+ dev = afe->dev;
+
+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(afe->base_addr))
+ return PTR_ERR(afe->base_addr);
+
+ /* initial audio related clock */
+ ret = mt7986_init_clock(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot initialize clocks\n");
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ /* enable clock for regcache get default value from hw */
+ afe_priv->pm_runtime_bypass_reg_ctl = true;
+ pm_runtime_get_sync(&pdev->dev);
+
+ afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+ &mt7986_afe_regmap_config);
+
+ pm_runtime_put_sync(&pdev->dev);
+ if (IS_ERR(afe->regmap))
+ return PTR_ERR(afe->regmap);
+
+ afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+ /* init memif */
+ afe->memif_size = MT7986_MEMIF_NUM;
+ afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+ GFP_KERNEL);
+ if (!afe->memif)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->memif_size; i++) {
+ afe->memif[i].data = &memif_data[i];
+ afe->memif[i].irq_usage = -1;
+ }
+
+ mutex_init(&afe->irq_alloc_lock);
+
+ /* irq initialize */
+ afe->irqs_size = MT7986_IRQ_NUM;
+ afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ GFP_KERNEL);
+ if (!afe->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < afe->irqs_size; i++)
+ afe->irqs[i].irq_data = &irq_data[i];
+
+ /* request irq */
+ irq_id = platform_get_irq(pdev, 0);
+ if (irq_id < 0) {
+ ret = irq_id;
+ return dev_err_probe(dev, ret, "No irq found\n");
+ }
+ ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler,
+ IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n");
+
+ /* init sub_dais */
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i);
+ }
+
+ /* init dai_driver and component_driver */
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret)
+ return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+ afe->mtk_afe_hardware = &mt7986_afe_hardware;
+ afe->memif_fs = mt7986_memif_fs;
+ afe->irq_fs = mt7986_irq_fs;
+
+ afe->runtime_resume = mt7986_afe_runtime_resume;
+ afe->runtime_suspend = mt7986_afe_runtime_suspend;
+
+ /* register component */
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &mt7986_afe_component,
+ NULL, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot register AFE component\n");
+
+ ret = devm_snd_soc_register_component(afe->dev,
+ &mt7986_afe_pcm_dai_component,
+ afe->dai_drivers,
+ afe->num_dai_drivers);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n");
+
+ return 0;
+}
+
+static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mt7986_afe_runtime_suspend(&pdev->dev);
+}
+
+static const struct of_device_id mt7986_afe_pcm_dt_match[] = {
+ { .compatible = "mediatek,mt7986-afe" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt7986_afe_pm_ops = {
+ SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend,
+ mt7986_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt7986_afe_pcm_driver = {
+ .driver = {
+ .name = "mt7986-audio",
+ .of_match_table = mt7986_afe_pcm_dt_match,
+ .pm = &mt7986_afe_pm_ops,
+ },
+ .probe = mt7986_afe_pcm_dev_probe,
+ .remove_new = mt7986_afe_pcm_dev_remove,
+};
+module_platform_driver(mt7986_afe_pcm_driver);
+
+MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
new file mode 100644
index 000000000000..e523d33846fe
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI eTDM Control
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+
+#define HOPPING_CLK 0
+#define APLL_CLK 1
+#define MTK_DAI_ETDM_FORMAT_I2S 0
+#define MTK_DAI_ETDM_FORMAT_DSPA 4
+#define MTK_DAI_ETDM_FORMAT_DSPB 5
+
+enum {
+ MTK_ETDM_RATE_8K = 0,
+ MTK_ETDM_RATE_12K = 1,
+ MTK_ETDM_RATE_16K = 2,
+ MTK_ETDM_RATE_24K = 3,
+ MTK_ETDM_RATE_32K = 4,
+ MTK_ETDM_RATE_48K = 5,
+ MTK_ETDM_RATE_96K = 7,
+ MTK_ETDM_RATE_192K = 9,
+ MTK_ETDM_RATE_11K = 16,
+ MTK_ETDM_RATE_22K = 17,
+ MTK_ETDM_RATE_44K = 18,
+ MTK_ETDM_RATE_88K = 19,
+ MTK_ETDM_RATE_176K = 20,
+};
+
+struct mtk_dai_etdm_priv {
+ bool bck_inv;
+ bool lrck_inv;
+ bool slave_mode;
+ unsigned int format;
+};
+
+static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate)
+{
+ switch (rate) {
+ case 8000:
+ return MTK_ETDM_RATE_8K;
+ case 11025:
+ return MTK_ETDM_RATE_11K;
+ case 12000:
+ return MTK_ETDM_RATE_12K;
+ case 16000:
+ return MTK_ETDM_RATE_16K;
+ case 22050:
+ return MTK_ETDM_RATE_22K;
+ case 24000:
+ return MTK_ETDM_RATE_24K;
+ case 32000:
+ return MTK_ETDM_RATE_32K;
+ case 44100:
+ return MTK_ETDM_RATE_44K;
+ case 48000:
+ return MTK_ETDM_RATE_48K;
+ case 88200:
+ return MTK_ETDM_RATE_88K;
+ case 96000:
+ return MTK_ETDM_RATE_96K;
+ case 176400:
+ return MTK_ETDM_RATE_176K;
+ case 192000:
+ return MTK_ETDM_RATE_192K;
+ default:
+ dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
+ __func__, rate, MTK_ETDM_RATE_48K);
+ return MTK_ETDM_RATE_48K;
+ }
+}
+
+static int get_etdm_wlen(unsigned int bitwidth)
+{
+ return bitwidth <= 16 ? 16 : 32;
+}
+
+/* dai component */
+/* interconnection */
+
+static const struct snd_kcontrol_new o124_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new o125_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
+
+ /* DL */
+ SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
+ /* UL */
+ SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)),
+ SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
+ {"I150", NULL, "ETDM Capture"},
+ {"I151", NULL, "ETDM Capture"},
+ {"ETDM Playback", NULL, "O124"},
+ {"ETDM Playback", NULL, "O125"},
+ {"O124", "I032_Switch", "I032"},
+ {"O125", "I033_Switch", "I033"},
+};
+
+/* dai ops */
+static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ int ret;
+
+ ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+ if (ret)
+ return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
+
+ return 0;
+}
+
+static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
+ CLK_OUT5_PDN);
+ regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
+ CLK_IN5_PDN);
+
+ clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
+}
+
+static unsigned int get_etdm_ch_fixup(unsigned int channels)
+{
+ if (channels > 16)
+ return 24;
+ else if (channels > 8)
+ return 16;
+ else if (channels > 4)
+ return 8;
+ else if (channels > 2)
+ return 4;
+ else
+ return 2;
+}
+
+static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai,
+ int stream)
+{
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
+ unsigned int rate = params_rate(params);
+ unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate);
+ unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate);
+ unsigned int channels = params_channels(params);
+ unsigned int bit_width = params_width(params);
+ unsigned int wlen = get_etdm_wlen(bit_width);
+ unsigned int val = 0;
+ unsigned int mask = 0;
+
+ dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
+ __func__, stream, rate, bit_width);
+
+ /* CON0 */
+ mask |= ETDM_BIT_LEN_MASK;
+ val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1);
+ mask |= ETDM_WRD_LEN_MASK;
+ val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1);
+ mask |= ETDM_FMT_MASK;
+ val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format);
+ mask |= ETDM_CH_NUM_MASK;
+ val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1);
+ mask |= RELATCH_SRC_MASK;
+ val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK);
+
+ switch (stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ /* set ETDM_OUT5_CON0 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
+
+ /* set ETDM_OUT5_CON4 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+ OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+ OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+ OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
+
+ /* set ETDM_OUT5_CON5 */
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
+ ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
+ break;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ /* set ETDM_IN5_CON0 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
+ ETDM_SYNC_MASK, ETDM_SYNC);
+
+ /* set ETDM_IN5_CON2 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
+ IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
+
+ /* set ETDM_IN5_CON3 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
+ IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
+
+ /* set ETDM_IN5_CON4 */
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
+ IN_RELATCH_MASK, IN_RELATCH(afe_rate));
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
+ mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
+
+ return 0;
+}
+
+static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+ dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+ ETDM_EN);
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+ ETDM_EN);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+ 0);
+ regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+ 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt7986_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_etdm_priv *etdm_data;
+ void *priv_data;
+
+ switch (dai->id) {
+ case MT7986_DAI_ETDM:
+ break;
+ default:
+ dev_warn(afe->dev, "%s(), id %d not support\n",
+ __func__, dai->id);
+ return -EINVAL;
+ }
+
+ priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
+ GFP_KERNEL);
+ if (!priv_data)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[dai->id] = priv_data;
+ etdm_data = afe_priv->dai_priv[dai->id];
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ etdm_data->bck_inv = false;
+ etdm_data->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ etdm_data->bck_inv = false;
+ etdm_data->lrck_inv = true;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ etdm_data->bck_inv = true;
+ etdm_data->lrck_inv = false;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ etdm_data->bck_inv = true;
+ etdm_data->lrck_inv = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ etdm_data->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ etdm_data->slave_mode = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+ .startup = mtk_dai_etdm_startup,
+ .shutdown = mtk_dai_etdm_shutdown,
+ .hw_params = mtk_dai_etdm_hw_params,
+ .trigger = mtk_dai_etdm_trigger,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+ SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
+ {
+ .name = "ETDM",
+ .id = MT7986_DAI_ETDM,
+ .capture = {
+ .stream_name = "ETDM Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .playback = {
+ .stream_name = "ETDM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MTK_ETDM_RATES,
+ .formats = MTK_ETDM_FORMATS,
+ },
+ .ops = &mtk_dai_etdm_ops,
+ .symmetric_rate = 1,
+ .symmetric_sample_bits = 1,
+ },
+};
+
+int mt7986_dai_etdm_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_etdm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
+
+ dai->dapm_widgets = mtk_dai_etdm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
+ dai->dapm_routes = mtk_dai_etdm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
+
+ return 0;
+}
diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h
new file mode 100644
index 000000000000..c2b200743c3f
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-reg.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt7986-reg.h -- MediaTek 7986 audio driver reg definition
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#ifndef _MT7986_REG_H_
+#define _MT7986_REG_H_
+
+#define AUDIO_TOP_CON2 0x0008
+#define AUDIO_TOP_CON4 0x0010
+#define AUDIO_ENGEN_CON0 0x0014
+#define AFE_IRQ_MCU_EN 0x0100
+#define AFE_IRQ_MCU_STATUS 0x0120
+#define AFE_IRQ_MCU_CLR 0x0128
+#define AFE_IRQ0_MCU_CFG0 0x0140
+#define AFE_IRQ0_MCU_CFG1 0x0144
+#define AFE_IRQ1_MCU_CFG0 0x0148
+#define AFE_IRQ1_MCU_CFG1 0x014c
+#define AFE_IRQ2_MCU_CFG0 0x0150
+#define AFE_IRQ2_MCU_CFG1 0x0154
+#define ETDM_IN5_CON0 0x13f0
+#define ETDM_IN5_CON1 0x13f4
+#define ETDM_IN5_CON2 0x13f8
+#define ETDM_IN5_CON3 0x13fc
+#define ETDM_IN5_CON4 0x1400
+#define ETDM_OUT5_CON0 0x1570
+#define ETDM_OUT5_CON4 0x1580
+#define ETDM_OUT5_CON5 0x1584
+#define ETDM_4_7_COWORK_CON0 0x15e0
+#define ETDM_4_7_COWORK_CON1 0x15e4
+#define AFE_CONN018_1 0x1b44
+#define AFE_CONN018_4 0x1b50
+#define AFE_CONN019_1 0x1b64
+#define AFE_CONN019_4 0x1b70
+#define AFE_CONN124_1 0x2884
+#define AFE_CONN124_4 0x2890
+#define AFE_CONN125_1 0x28a4
+#define AFE_CONN125_4 0x28b0
+#define AFE_CONN_RS_0 0x3920
+#define AFE_CONN_RS_3 0x392c
+#define AFE_CONN_16BIT_0 0x3960
+#define AFE_CONN_16BIT_3 0x396c
+#define AFE_CONN_24BIT_0 0x3980
+#define AFE_CONN_24BIT_3 0x398c
+#define AFE_MEMIF_CON0 0x3d98
+#define AFE_MEMIF_RD_MON 0x3da0
+#define AFE_MEMIF_WR_MON 0x3da4
+#define AFE_DL0_BASE_MSB 0x3e40
+#define AFE_DL0_BASE 0x3e44
+#define AFE_DL0_CUR_MSB 0x3e48
+#define AFE_DL0_CUR 0x3e4c
+#define AFE_DL0_END_MSB 0x3e50
+#define AFE_DL0_END 0x3e54
+#define AFE_DL0_RCH_MON 0x3e58
+#define AFE_DL0_LCH_MON 0x3e5c
+#define AFE_DL0_CON0 0x3e60
+#define AFE_VUL0_BASE_MSB 0x4220
+#define AFE_VUL0_BASE 0x4224
+#define AFE_VUL0_CUR_MSB 0x4228
+#define AFE_VUL0_CUR 0x422c
+#define AFE_VUL0_END_MSB 0x4230
+#define AFE_VUL0_END 0x4234
+#define AFE_VUL0_CON0 0x4238
+
+#define AFE_MAX_REGISTER AFE_VUL0_CON0
+#define AFE_IRQ_STATUS_BITS 0x7
+#define AFE_IRQ_CNT_SHIFT 0
+#define AFE_IRQ_CNT_MASK 0xffffff
+
+/* AUDIO_TOP_CON2 */
+#define CLK_OUT5_PDN BIT(14)
+#define CLK_OUT5_PDN_MASK BIT(14)
+#define CLK_IN5_PDN BIT(7)
+#define CLK_IN5_PDN_MASK BIT(7)
+
+/* AUDIO_TOP_CON4 */
+#define PDN_APLL_TUNER2 BIT(12)
+#define PDN_APLL_TUNER2_MASK BIT(12)
+
+/* AUDIO_ENGEN_CON0 */
+#define AUD_APLL2_EN BIT(3)
+#define AUD_APLL2_EN_MASK BIT(3)
+#define AUD_26M_EN BIT(0)
+#define AUD_26M_EN_MASK BIT(0)
+
+/* AFE_DL0_CON0 */
+#define DL0_ON_SFT 28
+#define DL0_ON_MASK 0x1
+#define DL0_ON_MASK_SFT BIT(28)
+#define DL0_MINLEN_SFT 20
+#define DL0_MINLEN_MASK 0xf
+#define DL0_MINLEN_MASK_SFT (0xf << 20)
+#define DL0_MODE_SFT 8
+#define DL0_MODE_MASK 0x1f
+#define DL0_MODE_MASK_SFT (0x1f << 8)
+#define DL0_PBUF_SIZE_SFT 5
+#define DL0_PBUF_SIZE_MASK 0x3
+#define DL0_PBUF_SIZE_MASK_SFT (0x3 << 5)
+#define DL0_MONO_SFT 4
+#define DL0_MONO_MASK 0x1
+#define DL0_MONO_MASK_SFT BIT(4)
+#define DL0_HALIGN_SFT 2
+#define DL0_HALIGN_MASK 0x1
+#define DL0_HALIGN_MASK_SFT BIT(2)
+#define DL0_HD_MODE_SFT 0
+#define DL0_HD_MODE_MASK 0x3
+#define DL0_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_VUL0_CON0 */
+#define VUL0_ON_SFT 28
+#define VUL0_ON_MASK 0x1
+#define VUL0_ON_MASK_SFT BIT(28)
+#define VUL0_MODE_SFT 8
+#define VUL0_MODE_MASK 0x1f
+#define VUL0_MODE_MASK_SFT (0x1f << 8)
+#define VUL0_MONO_SFT 4
+#define VUL0_MONO_MASK 0x1
+#define VUL0_MONO_MASK_SFT BIT(4)
+#define VUL0_HALIGN_SFT 2
+#define VUL0_HALIGN_MASK 0x1
+#define VUL0_HALIGN_MASK_SFT BIT(2)
+#define VUL0_HD_MODE_SFT 0
+#define VUL0_HD_MODE_MASK 0x3
+#define VUL0_HD_MODE_MASK_SFT (0x3 << 0)
+
+/* AFE_IRQ_MCU_CON */
+#define IRQ_MCU_MODE_SFT 4
+#define IRQ_MCU_MODE_MASK 0x1f
+#define IRQ_MCU_MODE_MASK_SFT (0x1f << 4)
+#define IRQ_MCU_ON_SFT 0
+#define IRQ_MCU_ON_MASK 0x1
+#define IRQ_MCU_ON_MASK_SFT BIT(0)
+#define IRQ0_MCU_CLR_SFT 0
+#define IRQ0_MCU_CLR_MASK 0x1
+#define IRQ0_MCU_CLR_MASK_SFT BIT(0)
+#define IRQ1_MCU_CLR_SFT 1
+#define IRQ1_MCU_CLR_MASK 0x1
+#define IRQ1_MCU_CLR_MASK_SFT BIT(1)
+#define IRQ2_MCU_CLR_SFT 2
+#define IRQ2_MCU_CLR_MASK 0x1
+#define IRQ2_MCU_CLR_MASK_SFT BIT(2)
+
+/* ETDM_IN5_CON2 */
+#define IN_CLK_SRC(x) ((x) << 10)
+#define IN_CLK_SRC_SFT 10
+#define IN_CLK_SRC_MASK GENMASK(12, 10)
+
+/* ETDM_IN5_CON3 */
+#define IN_SEL_FS(x) ((x) << 26)
+#define IN_SEL_FS_SFT 26
+#define IN_SEL_FS_MASK GENMASK(30, 26)
+
+/* ETDM_IN5_CON4 */
+#define IN_RELATCH(x) ((x) << 20)
+#define IN_RELATCH_SFT 20
+#define IN_RELATCH_MASK GENMASK(24, 20)
+#define IN_CLK_INV BIT(18)
+#define IN_CLK_INV_MASK BIT(18)
+
+/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
+#define RELATCH_SRC_MASK GENMASK(30, 28)
+#define ETDM_CH_NUM_MASK GENMASK(27, 23)
+#define ETDM_WRD_LEN_MASK GENMASK(20, 16)
+#define ETDM_BIT_LEN_MASK GENMASK(15, 11)
+#define ETDM_FMT_MASK GENMASK(8, 6)
+#define ETDM_SYNC BIT(1)
+#define ETDM_SYNC_MASK BIT(1)
+#define ETDM_EN BIT(0)
+#define ETDM_EN_MASK BIT(0)
+
+/* ETDM_OUT5_CON4 */
+#define OUT_RELATCH(x) ((x) << 24)
+#define OUT_RELATCH_SFT 24
+#define OUT_RELATCH_MASK GENMASK(28, 24)
+#define OUT_CLK_SRC(x) ((x) << 6)
+#define OUT_CLK_SRC_SFT 6
+#define OUT_CLK_SRC_MASK GENMASK(8, 6)
+#define OUT_SEL_FS(x) (x)
+#define OUT_SEL_FS_SFT 0
+#define OUT_SEL_FS_MASK GENMASK(4, 0)
+
+/* ETDM_OUT5_CON5 */
+#define ETDM_CLK_DIV BIT(12)
+#define ETDM_CLK_DIV_MASK BIT(12)
+#define OUT_CLK_INV BIT(9)
+#define OUT_CLK_INV_MASK BIT(9)
+
+/* ETDM_4_7_COWORK_CON0 */
+#define OUT_SEL(x) ((x) << 12)
+#define OUT_SEL_SFT 12
+#define OUT_SEL_MASK GENMASK(15, 12)
+#endif
diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
new file mode 100644
index 000000000000..364d13b1c426
--- /dev/null
+++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ * Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt7986-afe-common.h"
+
+struct mt7986_wm8960_priv {
+ struct device_node *platform_node;
+ struct device_node *codec_node;
+};
+
+static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("AMIC", NULL),
+};
+
+static const struct snd_kcontrol_new mt7986_wm8960_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("AMIC"),
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+ DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+ DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+ DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
+ /* FE */
+ {
+ .name = "wm8960-playback",
+ .stream_name = "wm8960-playback",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ SND_SOC_DAILINK_REG(playback),
+ },
+ {
+ .name = "wm8960-capture",
+ .stream_name = "wm8960-capture",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(capture),
+ },
+ /* BE */
+ {
+ .name = "wm8960-codec",
+ .no_pcm = 1,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS |
+ SND_SOC_DAIFMT_GATED,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ SND_SOC_DAILINK_REG(codec),
+ },
+};
+
+static struct snd_soc_card mt7986_wm8960_card = {
+ .name = "mt7986-wm8960",
+ .owner = THIS_MODULE,
+ .dai_link = mt7986_wm8960_dai_links,
+ .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links),
+ .controls = mt7986_wm8960_controls,
+ .num_controls = ARRAY_SIZE(mt7986_wm8960_controls),
+ .dapm_widgets = mt7986_wm8960_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets),
+};
+
+static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &mt7986_wm8960_card;
+ struct snd_soc_dai_link *dai_link;
+ struct device_node *platform, *codec;
+ struct mt7986_wm8960_priv *priv;
+ int ret, i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform = of_get_child_by_name(pdev->dev.of_node, "platform");
+
+ if (platform) {
+ priv->platform_node = of_parse_phandle(platform, "sound-dai", 0);
+ of_node_put(platform);
+
+ if (!priv->platform_node) {
+ dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->platforms->name)
+ continue;
+ dai_link->platforms->of_node = priv->platform_node;
+ }
+
+ card->dev = &pdev->dev;
+
+ codec = of_get_child_by_name(pdev->dev.of_node, "codec");
+
+ if (codec) {
+ priv->codec_node = of_parse_phandle(codec, "sound-dai", 0);
+ of_node_put(codec);
+
+ if (!priv->codec_node) {
+ of_node_put(priv->platform_node);
+ dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
+ return -EINVAL;
+ }
+ } else {
+ of_node_put(priv->platform_node);
+ dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for_each_card_prelinks(card, i, dai_link) {
+ if (dai_link->codecs->name)
+ continue;
+ dai_link->codecs->of_node = priv->codec_node;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
+ goto err_of_node_put;
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
+ if (ret) {
+ dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
+ goto err_of_node_put;
+ }
+
+err_of_node_put:
+ of_node_put(priv->codec_node);
+ of_node_put(priv->platform_node);
+ return ret;
+}
+
+static void mt7986_wm8960_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card);
+
+ of_node_put(priv->codec_node);
+ of_node_put(priv->platform_node);
+}
+
+static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
+ {.compatible = "mediatek,mt7986-wm8960-sound"},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match);
+
+static struct platform_driver mt7986_wm8960_machine = {
+ .driver = {
+ .name = "mt7986-wm8960",
+ .of_match_table = mt7986_wm8960_machine_dt_match,
+ },
+ .probe = mt7986_wm8960_machine_probe,
+ .remove_new = mt7986_wm8960_machine_remove,
+};
+
+module_platform_driver(mt7986_wm8960_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt7986 wm8960 soc card");
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c
index c2b0619b6158..bfb2094758ff 100644
--- a/sound/soc/mediatek/mt8173/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c
@@ -70,7 +70,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
/* enable jack detection */
- ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE,
+ ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET,
&mt8173_max98090_jack,
mt8173_max98090_jack_pins,
ARRAY_SIZE(mt8173_max98090_jack_pins));
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index f803f121659d..e502cd1670ba 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -40,6 +40,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
+static struct snd_soc_jack_pin mt8173_rt5650_rt5514_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -82,11 +93,13 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
RT5645_CLK_SEL_I2S1_ASRC);
/* enable jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &mt8173_rt5650_rt5514_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_rt5514_jack,
+ mt8173_rt5650_rt5514_jack_pins,
+ ARRAY_SIZE(mt8173_rt5650_rt5514_jack_pins));
if (ret) {
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
return ret;
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index 8794720cea3a..ffb094284bfb 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -44,6 +44,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
+static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -95,11 +106,13 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
RT5677_CLK_SEL_I2S2_ASRC);
/* enable jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &mt8173_rt5650_rt5676_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_rt5676_jack,
+ mt8173_rt5650_rt5676_jack_pins,
+ ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins));
if (ret) {
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
return ret;
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 3ece4b5eaca2..18cf84bb25c7 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -54,6 +54,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_controls[] = {
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
+static struct snd_soc_jack_pin mt8173_rt5650_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -128,11 +139,13 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
}
/* enable jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &mt8173_rt5650_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &mt8173_rt5650_jack,
+ mt8173_rt5650_jack_pins,
+ ARRAY_SIZE(mt8173_rt5650_jack_pins));
if (ret) {
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
return ret;
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 87bb04846991..701fbcc0f2c9 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -29,6 +29,21 @@ struct mt8183_da7219_max98357_priv {
struct snd_soc_jack headset_jack, hdmi_jack;
};
+static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
+};
+
static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -572,13 +587,15 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
snd_soc_card_get_drvdata(component->card);
/* Enable Headset and 4 Buttons Jack detection */
- ret = snd_soc_card_jack_new(component->card,
- "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_LINEOUT,
- &priv->headset_jack);
+ ret = snd_soc_card_jack_new_pins(component->card,
+ "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_LINEOUT,
+ &priv->headset_jack,
+ mt8183_da7219_max98357_jack_pins,
+ ARRAY_SIZE(mt8183_da7219_max98357_jack_pins));
if (ret)
return ret;
@@ -609,12 +626,18 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = {
};
static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Speakers"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const
struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_SPK("Line Out", NULL),
SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
"aud_tdm_out_on", "aud_tdm_out_off"),
};
@@ -657,14 +680,20 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = {
};
static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Left Spk"),
SOC_DAPM_PIN_SWITCH("Right Spk"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const
struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
"aud_tdm_out_on", "aud_tdm_out_off"),
};
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index ce9aedde7e1e..850f4d949d97 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -592,11 +592,38 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
},
};
+static const
+struct snd_kcontrol_new mt8183_mt6358_ts3a227_max98357_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const
+struct snd_soc_dapm_widget mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static struct snd_soc_jack_pin mt8183_mt6358_ts3a227_max98357_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = {
.name = "mt8183_mt6358_ts3a227_max98357",
.owner = THIS_MODULE,
.dai_link = mt8183_mt6358_ts3a227_dai_links,
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
@@ -604,6 +631,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
.owner = THIS_MODULE,
.dai_link = mt8183_mt6358_ts3a227_dai_links,
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = {
@@ -624,6 +655,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = {
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
.codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf,
.num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = {
@@ -631,6 +666,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = {
.owner = THIS_MODULE,
.dai_link = mt8183_mt6358_ts3a227_dai_links,
.num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+ .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+ .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+ .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
};
static int
@@ -641,12 +680,14 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component)
snd_soc_card_get_drvdata(component->card);
/* Enable Headset and 4 Buttons Jack detection */
- ret = snd_soc_card_jack_new(component->card,
- "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &priv->headset_jack);
+ ret = snd_soc_card_jack_new_pins(component->card,
+ "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &priv->headset_jack,
+ mt8183_mt6358_ts3a227_max98357_jack_pins,
+ ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_jack_pins));
if (ret)
return ret;
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
index 539e3a023bc4..70ec101890d3 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
@@ -13,8 +13,6 @@
#include "mt8186-afe-clk.h"
#include "mt8186-audsys-clk.h"
-static DEFINE_MUTEX(mutex_request_dram);
-
static const char *aud_clks[CLK_NUM] = {
[CLK_AFE] = "aud_afe_clk",
[CLK_DAC] = "aud_dac_clk",
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
index 0432f9d89020..aa8e00bba19b 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
@@ -46,6 +46,10 @@ static struct snd_soc_jack_pin mt8186_jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = {
@@ -964,6 +968,7 @@ mt8186_mt6366_da7219_max98357_widgets[] = {
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_OUTPUT("HDMI1"),
SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -996,6 +1001,7 @@ mt8186_mt6366_da7219_max98357_controls[] = {
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("HDMI1"),
};
diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
index eedb9165f911..fd4f9f8f032d 100644
--- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
@@ -2456,25 +2456,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai,
return mtk_dai_etdm_cal_mclk(afe, freq, dai->id);
}
-static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
- .startup = mtk_dai_etdm_startup,
- .shutdown = mtk_dai_etdm_shutdown,
- .hw_params = mtk_dai_etdm_hw_params,
- .trigger = mtk_dai_etdm_trigger,
- .set_sysclk = mtk_dai_etdm_set_sysclk,
- .set_fmt = mtk_dai_etdm_set_fmt,
- .set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
-};
-
-static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
- .startup = mtk_dai_hdmitx_dptx_startup,
- .shutdown = mtk_dai_hdmitx_dptx_shutdown,
- .hw_params = mtk_dai_hdmitx_dptx_hw_params,
- .trigger = mtk_dai_hdmitx_dptx_trigger,
- .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
- .set_fmt = mtk_dai_etdm_set_fmt,
-};
-
/* dai driver */
#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000)
@@ -2505,6 +2486,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
+ .startup = mtk_dai_hdmitx_dptx_startup,
+ .shutdown = mtk_dai_hdmitx_dptx_shutdown,
+ .hw_params = mtk_dai_hdmitx_dptx_hw_params,
+ .trigger = mtk_dai_hdmitx_dptx_trigger,
+ .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = {
+ .probe = mtk_dai_etdm_probe,
+ .startup = mtk_dai_hdmitx_dptx_startup,
+ .shutdown = mtk_dai_hdmitx_dptx_shutdown,
+ .hw_params = mtk_dai_hdmitx_dptx_hw_params,
+ .trigger = mtk_dai_hdmitx_dptx_trigger,
+ .set_sysclk = mtk_dai_hdmitx_dptx_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+ .probe = mtk_dai_etdm_probe,
+ .startup = mtk_dai_etdm_startup,
+ .shutdown = mtk_dai_etdm_shutdown,
+ .hw_params = mtk_dai_etdm_hw_params,
+ .trigger = mtk_dai_etdm_trigger,
+ .set_sysclk = mtk_dai_etdm_set_sysclk,
+ .set_fmt = mtk_dai_etdm_set_fmt,
+ .set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
+};
+
static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
{
.name = "DPTX",
@@ -2529,7 +2540,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM2_IN",
@@ -2542,7 +2552,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM1_OUT",
@@ -2555,7 +2564,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM2_OUT",
@@ -2568,7 +2576,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.formats = MTK_ETDM_FORMATS,
},
.ops = &mtk_dai_etdm_ops,
- .probe = mtk_dai_etdm_probe,
},
{
.name = "ETDM3_OUT",
@@ -2580,8 +2587,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
.rates = MTK_ETDM_RATES,
.formats = MTK_ETDM_FORMATS,
},
- .ops = &mtk_dai_hdmitx_dptx_ops,
- .probe = mtk_dai_etdm_probe,
+ .ops = &mtk_dai_hdmitx_dptx_ops2,
},
};
diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c
index d0f0ada5f4bc..7b04b97f7b41 100644
--- a/sound/soc/meson/aiu-acodec-ctrl.c
+++ b/sound/soc/meson/aiu-acodec-ctrl.c
@@ -103,6 +103,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = aiu_acodec_ctrl_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -130,8 +132,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = {
.name = "ACODEC CTRL " xname, \
.playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \
.ops = &aiu_acodec_ctrl_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define AIU_ACODEC_OUTPUT(xname) { \
diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c
index 84c10956c241..ee0ef6301010 100644
--- a/sound/soc/meson/aiu-codec-ctrl.c
+++ b/sound/soc/meson/aiu-codec-ctrl.c
@@ -75,6 +75,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = {
};
static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = meson_codec_glue_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -102,8 +104,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = {
.name = "CODEC CTRL " xname, \
.playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \
.ops = &aiu_codec_ctrl_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define AIU_CODEC_CTRL_OUTPUT(xname) { \
diff --git a/sound/soc/meson/aiu-fifo-i2s.c b/sound/soc/meson/aiu-fifo-i2s.c
index 59e00a74b5f8..7d833500c799 100644
--- a/sound/soc/meson/aiu-fifo-i2s.c
+++ b/sound/soc/meson/aiu-fifo-i2s.c
@@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
}
const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = {
+ .pcm_new = aiu_fifo_pcm_new,
+ .probe = aiu_fifo_i2s_dai_probe,
+ .remove = aiu_fifo_dai_remove,
.trigger = aiu_fifo_i2s_trigger,
.prepare = aiu_fifo_i2s_prepare,
.hw_params = aiu_fifo_i2s_hw_params,
diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c
index ddbd2fc40185..fa91f3c53fa4 100644
--- a/sound/soc/meson/aiu-fifo-spdif.c
+++ b/sound/soc/meson/aiu-fifo-spdif.c
@@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream,
}
const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
+ .pcm_new = aiu_fifo_pcm_new,
+ .probe = aiu_fifo_spdif_dai_probe,
+ .remove = aiu_fifo_dai_remove,
.trigger = fifo_spdif_trigger,
.prepare = fifo_spdif_prepare,
.hw_params = fifo_spdif_hw_params,
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
index da351a60df0c..7109b81cc3d0 100644
--- a/sound/soc/meson/aiu.c
+++ b/sound/soc/meson/aiu.c
@@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
.formats = AIU_FORMATS,
},
.ops = &aiu_fifo_i2s_dai_ops,
- .pcm_new = aiu_fifo_pcm_new,
- .probe = aiu_fifo_i2s_dai_probe,
- .remove = aiu_fifo_dai_remove,
},
[CPU_SPDIF_FIFO] = {
.name = "SPDIF FIFO",
@@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
.formats = AIU_FORMATS,
},
.ops = &aiu_fifo_spdif_dai_ops,
- .pcm_new = aiu_fifo_pcm_new,
- .probe = aiu_fifo_spdif_dai_probe,
- .remove = aiu_fifo_dai_remove,
},
[CPU_I2S_ENCODER] = {
.name = "I2S Encoder",
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
index 61f9d417fd60..8c166a5f338c 100644
--- a/sound/soc/meson/axg-frddr.c
+++ b/sound/soc/meson/axg-frddr.c
@@ -100,6 +100,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = {
.hw_params = axg_frddr_dai_hw_params,
.startup = axg_frddr_dai_startup,
.shutdown = axg_frddr_dai_shutdown,
+ .pcm_new = axg_frddr_pcm_new,
};
static struct snd_soc_dai_driver axg_frddr_dai_drv = {
@@ -112,7 +113,6 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = {
.formats = AXG_FIFO_FORMATS,
},
.ops = &axg_frddr_ops,
- .pcm_new = axg_frddr_pcm_new,
};
static const char * const axg_frddr_sel_texts[] = {
@@ -175,6 +175,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = {
.hw_params = axg_frddr_dai_hw_params,
.startup = axg_frddr_dai_startup,
.shutdown = axg_frddr_dai_shutdown,
+ .pcm_new = axg_frddr_pcm_new,
};
static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
@@ -187,7 +188,6 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
.formats = AXG_FIFO_FORMATS,
},
.ops = &g12a_frddr_ops,
- .pcm_new = axg_frddr_pcm_new,
};
static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
diff --git a/sound/soc/meson/axg-pdm.c b/sound/soc/meson/axg-pdm.c
index ad43cb2a1e3f..d59050914d3c 100644
--- a/sound/soc/meson/axg-pdm.c
+++ b/sound/soc/meson/axg-pdm.c
@@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream,
clk_disable_unprepare(priv->dclk);
}
-static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
- .trigger = axg_pdm_trigger,
- .hw_params = axg_pdm_hw_params,
- .startup = axg_pdm_startup,
- .shutdown = axg_pdm_shutdown,
-};
-
static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv)
{
const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic;
@@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
+ .probe = axg_pdm_dai_probe,
+ .remove = axg_pdm_dai_remove,
+ .trigger = axg_pdm_trigger,
+ .hw_params = axg_pdm_hw_params,
+ .startup = axg_pdm_startup,
+ .shutdown = axg_pdm_shutdown,
+};
+
static struct snd_soc_dai_driver axg_pdm_dai_drv = {
.name = "PDM",
.capture = {
@@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = {
SNDRV_PCM_FMTBIT_S32_LE),
},
.ops = &axg_pdm_dai_ops,
- .probe = axg_pdm_dai_probe,
- .remove = axg_pdm_dai_remove,
};
static const struct snd_soc_component_driver axg_pdm_component_drv = {
diff --git a/sound/soc/meson/axg-spdifin.c b/sound/soc/meson/axg-spdifin.c
index e2cc4c4be758..d86880169075 100644
--- a/sound/soc/meson/axg-spdifin.c
+++ b/sound/soc/meson/axg-spdifin.c
@@ -267,6 +267,8 @@ static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops axg_spdifin_ops = {
+ .probe = axg_spdifin_dai_probe,
+ .remove = axg_spdifin_dai_remove,
.prepare = axg_spdifin_prepare,
.startup = axg_spdifin_startup,
.shutdown = axg_spdifin_shutdown,
@@ -429,8 +431,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
drv->name = "SPDIF Input";
drv->ops = &axg_spdifin_ops;
- drv->probe = axg_spdifin_dai_probe;
- drv->remove = axg_spdifin_dai_remove;
drv->capture.stream_name = "Capture";
drv->capture.channels_min = 1;
drv->capture.channels_max = 2;
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
index 5e5e4c56d505..1c3d433cefd2 100644
--- a/sound/soc/meson/axg-tdm-interface.c
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -395,6 +395,8 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
+ .probe = axg_tdm_iface_probe_dai,
+ .remove = axg_tdm_iface_remove_dai,
.set_sysclk = axg_tdm_iface_set_sysclk,
.set_fmt = axg_tdm_iface_set_fmt,
.startup = axg_tdm_iface_startup,
@@ -423,8 +425,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
},
.id = TDM_IFACE_PAD,
.ops = &axg_tdm_iface_ops,
- .probe = axg_tdm_iface_probe_dai,
- .remove = axg_tdm_iface_remove_dai,
},
[TDM_IFACE_LOOPBACK] = {
.name = "TDM Loopback",
@@ -437,8 +437,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
},
.id = TDM_IFACE_LOOPBACK,
.ops = &axg_tdm_iface_ops,
- .probe = axg_tdm_iface_probe_dai,
- .remove = axg_tdm_iface_remove_dai,
},
};
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
index e9208e74e965..1a0be177b8fe 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -122,6 +122,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = {
.hw_params = axg_toddr_dai_hw_params,
.startup = axg_toddr_dai_startup,
.shutdown = axg_toddr_dai_shutdown,
+ .pcm_new = axg_toddr_pcm_new,
};
static struct snd_soc_dai_driver axg_toddr_dai_drv = {
@@ -134,7 +135,6 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = {
.formats = AXG_FIFO_FORMATS,
},
.ops = &axg_toddr_ops,
- .pcm_new = axg_toddr_pcm_new,
};
static const char * const axg_toddr_sel_texts[] = {
@@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = {
.hw_params = axg_toddr_dai_hw_params,
.startup = g12a_toddr_dai_startup,
.shutdown = axg_toddr_dai_shutdown,
+ .pcm_new = axg_toddr_pcm_new,
};
static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
@@ -229,7 +230,6 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
.formats = AXG_FIFO_FORMATS,
},
.ops = &g12a_toddr_ops,
- .pcm_new = axg_toddr_pcm_new,
};
static const struct snd_soc_component_driver g12a_toddr_component_drv = {
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
index ddc667956cf5..6c4503766fdc 100644
--- a/sound/soc/meson/g12a-toacodec.c
+++ b/sound/soc/meson/g12a-toacodec.c
@@ -162,6 +162,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops g12a_toacodec_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = g12a_toacodec_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -185,8 +187,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = {
.id = (xid), \
.playback = TOACODEC_STREAM(xname, "Playback", 8), \
.ops = &g12a_toacodec_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define TOACODEC_OUTPUT(xname, xid) { \
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
index 579a04ad4d19..f7ef9aa1eed8 100644
--- a/sound/soc/meson/g12a-tohdmitx.c
+++ b/sound/soc/meson/g12a-tohdmitx.c
@@ -140,6 +140,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = {
};
static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = {
+ .probe = meson_codec_glue_input_dai_probe,
+ .remove = meson_codec_glue_input_dai_remove,
.hw_params = meson_codec_glue_input_hw_params,
.set_fmt = meson_codec_glue_input_set_fmt,
};
@@ -172,8 +174,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = {
.id = (xid), \
.playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \
.ops = &g12a_tohdmitx_input_ops, \
- .probe = meson_codec_glue_input_dai_probe, \
- .remove = meson_codec_glue_input_dai_remove, \
}
#define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index a1ed141b8795..abfaf3cdf5bb 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+ .probe = mmp_sspa_probe,
.startup = mmp_sspa_startup,
.shutdown = mmp_sspa_shutdown,
.trigger = mmp_sspa_trigger,
@@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
};
static struct snd_soc_dai_driver mmp_sspa_dai = {
- .probe = mmp_sspa_probe,
.playback = {
.channels_min = 1,
.channels_max = 128,
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 430dd446321e..b70034c07eee 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -591,7 +591,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
if (ret < 0) {
const struct pxa_ssp_clock_mode *m;
- int ssacd, acds;
+ int ssacd;
for (m = pxa_ssp_clock_modes; m->rate; m++) {
if (m->rate == rate)
@@ -601,12 +601,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
if (!m->rate)
return -EINVAL;
- acds = m->acds;
-
- /* The values in the table are for 16 bits */
- if (width == 32)
- acds--;
-
ret = pxa_ssp_set_pll(priv, bclk);
if (ret < 0)
return ret;
@@ -819,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+ .probe = pxa_ssp_probe,
+ .remove = pxa_ssp_remove,
.startup = pxa_ssp_startup,
.shutdown = pxa_ssp_shutdown,
.trigger = pxa_ssp_trigger,
@@ -830,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
};
static struct snd_soc_dai_driver pxa_ssp_dai = {
- .probe = pxa_ssp_probe,
- .remove = pxa_ssp_remove,
.playback = {
.channels_min = 1,
.channels_max = 8,
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 10636506b622..437bfccd04f8 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -329,6 +329,8 @@ static int pxa2xx_i2s_remove(struct snd_soc_dai *dai)
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+ .probe = pxa2xx_i2s_probe,
+ .remove = pxa2xx_i2s_remove,
.startup = pxa2xx_i2s_startup,
.shutdown = pxa2xx_i2s_shutdown,
.trigger = pxa2xx_i2s_trigger,
@@ -338,8 +340,6 @@ static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
};
static struct snd_soc_dai_driver pxa_i2s_dai = {
- .probe = pxa2xx_i2s_probe,
- .remove = pxa2xx_i2s_remove,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index e54b8961112f..6de533d45e7d 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -44,6 +44,17 @@ struct apq8016_sbc_data {
#define DEFAULT_MCLK_RATE 9600000
#define MI2S_BCLK_RATE 1536000
+static struct snd_soc_jack_pin apq8016_sbc_jack_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
{
struct snd_soc_dai *codec_dai;
@@ -90,13 +101,15 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
if (!pdata->jack_setup) {
struct snd_jack *jack;
- rval = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_HEADPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4,
- &pdata->jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4,
+ &pdata->jack,
+ apq8016_sbc_jack_pins,
+ ARRAY_SIZE(apq8016_sbc_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headphone Jack\n");
@@ -255,8 +268,14 @@ static void msm8916_qdsp6_add_ops(struct snd_soc_card *card)
}
}
-static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+static const struct snd_kcontrol_new apq8016_sbc_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Secondary Mic", NULL),
@@ -285,6 +304,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
card->owner = THIS_MODULE;
card->dapm_widgets = apq8016_sbc_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets);
+ card->controls = apq8016_sbc_snd_controls;
+ card->num_controls = ARRAY_SIZE(apq8016_sbc_snd_controls);
ret = qcom_snd_parse_of(card);
if (ret)
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index abaf694ee9a3..f919d46e18ca 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
[MI2S_SECONDARY] = {
@@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
[MI2S_TERTIARY] = {
@@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
[MI2S_QUATERNARY] = {
@@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
},
};
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index dbdaaa85ce48..39571fed4001 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
return 0;
}
-const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
- .set_sysclk = lpass_cpu_daiops_set_sysclk,
- .startup = lpass_cpu_daiops_startup,
- .shutdown = lpass_cpu_daiops_shutdown,
- .hw_params = lpass_cpu_daiops_hw_params,
- .trigger = lpass_cpu_daiops_trigger,
- .prepare = lpass_cpu_daiops_prepare,
-};
-EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
-
-int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai)
+static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
int ret;
struct snd_soc_dai_driver *drv = dai->driver;
@@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new);
-int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai)
{
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
int ret;
@@ -446,7 +434,29 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
return ret;
}
-EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
+ .probe = lpass_cpu_daiops_probe,
+ .set_sysclk = lpass_cpu_daiops_set_sysclk,
+ .startup = lpass_cpu_daiops_startup,
+ .shutdown = lpass_cpu_daiops_shutdown,
+ .hw_params = lpass_cpu_daiops_hw_params,
+ .trigger = lpass_cpu_daiops_trigger,
+ .prepare = lpass_cpu_daiops_prepare,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = {
+ .pcm_new = lpass_cpu_daiops_pcm_new,
+ .probe = lpass_cpu_daiops_probe,
+ .set_sysclk = lpass_cpu_daiops_set_sysclk,
+ .startup = lpass_cpu_daiops_startup,
+ .shutdown = lpass_cpu_daiops_shutdown,
+ .hw_params = lpass_cpu_daiops_hw_params,
+ .trigger = lpass_cpu_daiops_trigger,
+ .prepare = lpass_cpu_daiops_prepare,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2);
static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
const struct of_phandle_args *args,
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index ef8a7984f232..2c97f295e394 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
.channels_min = 1,
.channels_max = 8,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
};
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index 56db852f4eab..d16c0d83aaad 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
}, {
.id = MI2S_SECONDARY,
@@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
- .ops = &asoc_qcom_lpass_cpu_dai_ops,
- .pcm_new = lpass_cpu_pcm_new,
+ .ops = &asoc_qcom_lpass_cpu_dai_ops2,
}, {
.id = LPASS_DP_RX,
.name = "Hdmi",
diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
index bcf18fe8e14d..6b2eb25ed939 100644
--- a/sound/soc/qcom/lpass-sc7280.c
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
}, {
.id = MI2S_SECONDARY,
@@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
.channels_min = 2,
.channels_max = 2,
},
- .probe = &asoc_qcom_lpass_cpu_dai_probe,
.ops = &asoc_qcom_lpass_cpu_dai_ops,
}, {
.id = LPASS_DP_RX,
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index dd78600fc7b0..bdfe66ec3314 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -402,10 +402,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *);
int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev);
int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
-int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
-int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai);
+extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2;
extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops;
#endif /* __LPASS_H__ */
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index dbff55a97162..3faa7e0eb0dd 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -619,44 +619,6 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"},
};
-static const struct snd_soc_dai_ops q6hdmi_ops = {
- .prepare = q6afe_dai_prepare,
- .hw_params = q6hdmi_hw_params,
- .shutdown = q6afe_dai_shutdown,
-};
-
-static const struct snd_soc_dai_ops q6i2s_ops = {
- .prepare = q6afe_dai_prepare,
- .hw_params = q6i2s_hw_params,
- .set_fmt = q6i2s_set_fmt,
- .shutdown = q6afe_dai_shutdown,
- .set_sysclk = q6afe_mi2s_set_sysclk,
-};
-
-static const struct snd_soc_dai_ops q6slim_ops = {
- .prepare = q6afe_dai_prepare,
- .hw_params = q6slim_hw_params,
- .shutdown = q6afe_dai_shutdown,
- .set_channel_map = q6slim_set_channel_map,
-};
-
-static const struct snd_soc_dai_ops q6tdm_ops = {
- .prepare = q6afe_dai_prepare,
- .shutdown = q6afe_dai_shutdown,
- .set_sysclk = q6afe_mi2s_set_sysclk,
- .set_tdm_slot = q6tdm_set_tdm_slot,
- .set_channel_map = q6tdm_set_channel_map,
- .hw_params = q6tdm_hw_params,
-};
-
-static const struct snd_soc_dai_ops q6dma_ops = {
- .prepare = q6afe_dai_prepare,
- .shutdown = q6afe_dai_shutdown,
- .set_sysclk = q6afe_mi2s_set_sysclk,
- .set_channel_map = q6dma_set_channel_map,
- .hw_params = q6dma_hw_params,
-};
-
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
{
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -682,6 +644,54 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops q6hdmi_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6hdmi_hw_params,
+ .shutdown = q6afe_dai_shutdown,
+};
+
+static const struct snd_soc_dai_ops q6i2s_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6i2s_hw_params,
+ .set_fmt = q6i2s_set_fmt,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops q6slim_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .hw_params = q6slim_hw_params,
+ .shutdown = q6afe_dai_shutdown,
+ .set_channel_map = q6slim_set_channel_map,
+};
+
+static const struct snd_soc_dai_ops q6tdm_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+ .set_tdm_slot = q6tdm_set_tdm_slot,
+ .set_channel_map = q6tdm_set_channel_map,
+ .hw_params = q6tdm_hw_params,
+};
+
+static const struct snd_soc_dai_ops q6dma_ops = {
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .prepare = q6afe_dai_prepare,
+ .shutdown = q6afe_dai_shutdown,
+ .set_sysclk = q6afe_mi2s_set_sysclk,
+ .set_channel_map = q6dma_set_channel_map,
+ .hw_params = q6dma_hw_params,
+};
+
static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
@@ -1041,8 +1051,6 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev)
dev_set_drvdata(dev, dai_data);
of_q6afe_parse_dai_data(dev, dai_data);
- cfg.probe = msm_dai_q6_dai_probe;
- cfg.remove = msm_dai_q6_dai_remove;
cfg.q6hdmi_ops = &q6hdmi_ops;
cfg.q6slim_ops = &q6slim_ops;
cfg.q6i2s_ops = &q6i2s_ops;
diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h
index 8ee40732ce9e..f486bd639b9f 100644
--- a/sound/soc/qcom/qdsp6/q6apm.h
+++ b/sound/soc/qcom/qdsp6/q6apm.h
@@ -126,7 +126,6 @@ int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
struct audioreach_module_config *cfg);
/* read/write related */
-int q6apm_send_eos_nowait(struct q6apm_graph *graph);
int q6apm_read(struct q6apm_graph *graph);
int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
uint32_t lsw_ts, uint32_t wflags);
@@ -144,7 +143,6 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
/* Callback for graph specific */
struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph,
uint32_t mid);
-void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv);
int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);
bool q6apm_is_adsp_ready(void);
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 5fc8088e63c8..fe0666e9fd23 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -1230,6 +1230,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
Q6ASM_FEDAI_DRIVER(8),
};
+static const struct snd_soc_dai_ops q6asm_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static int of_q6asm_parse_dai_data(struct device *dev,
struct q6asm_dai_data *pdata)
{
@@ -1272,7 +1276,7 @@ static int of_q6asm_parse_dai_data(struct device *dev,
dai_drv->playback = empty_stream;
if (of_property_read_bool(node, "is-compress-dai"))
- dai_drv->compress_new = snd_soc_new_compress;
+ dai_drv->ops = &q6asm_dai_ops;
}
return 0;
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
index ac937a6bf909..4919001de08b 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
@@ -603,9 +603,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
int i;
for (i = 0; i < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) {
- q6dsp_audio_fe_dais[i].probe = cfg->probe;
- q6dsp_audio_fe_dais[i].remove = cfg->remove;
-
switch (q6dsp_audio_fe_dais[i].id) {
case HDMI_RX:
case DISPLAY_PORT_RX:
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c
index f5f7c64b23a2..57c5f35dfcc5 100644
--- a/sound/soc/qcom/sc7180.c
+++ b/sound/soc/qcom/sc7180.c
@@ -42,6 +42,17 @@ static void sc7180_jack_free(struct snd_jack *jack)
snd_soc_component_set_jack(component, NULL, NULL);
}
+static struct snd_soc_jack_pin sc7180_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
@@ -51,13 +62,14 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
struct snd_jack *jack;
int rval;
- rval = snd_soc_card_jack_new(
- card, "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_HEADPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pdata->hs_jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pdata->hs_jack,
+ sc7180_jack_pins,
+ ARRAY_SIZE(sc7180_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -297,6 +309,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
+static const struct snd_kcontrol_new sc7180_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = {
SND_SOC_DAPM_MIC("DMIC", NULL),
};
@@ -320,6 +337,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = {
SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control),
};
+static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = {
{"Dmic Mux", "Front Mic", "DMIC"},
{"Dmic Mux", "Rear Mic", "DMIC"},
@@ -348,10 +370,14 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
card->dev = dev;
card->dapm_widgets = sc7180_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets);
+ card->controls = sc7180_snd_controls;
+ card->num_controls = ARRAY_SIZE(sc7180_snd_controls);
if (of_property_read_bool(dev->of_node, "dmic-gpios")) {
card->dapm_widgets = sc7180_snd_dual_mic_widgets,
card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets),
+ card->controls = sc7180_snd_dual_mic_controls,
+ card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls),
card->dapm_routes = sc7180_snd_dual_mic_audio_route,
card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route),
data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c
index 787dd49e03f6..43010e4e2242 100644
--- a/sound/soc/qcom/sc7280.c
+++ b/sound/soc/qcom/sc7280.c
@@ -43,6 +43,17 @@ static void sc7280_jack_free(struct snd_jack *jack)
snd_soc_component_set_jack(component, NULL, NULL);
}
+static struct snd_soc_jack_pin sc7280_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
@@ -54,13 +65,15 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
int rval, i;
if (!pdata->jack_setup) {
- rval = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET | SND_JACK_LINEOUT |
- SND_JACK_MECHANICAL |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &pdata->hs_jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_LINEOUT |
+ SND_JACK_MECHANICAL |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4 | SND_JACK_BTN_5,
+ &pdata->hs_jack,
+ sc7280_jack_pins,
+ ARRAY_SIZE(sc7280_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -361,6 +374,11 @@ static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
+static const struct snd_kcontrol_new sc7280_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -396,6 +414,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev)
card->dapm_widgets = sc7280_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets);
+ card->controls = sc7280_snd_controls;
+ card->num_controls = ARRAY_SIZE(sc7280_snd_controls);
ret = qcom_snd_parse_of(card);
if (ret)
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 02612af714a8..29d23fe5dfa2 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -42,6 +42,17 @@ struct sdm845_snd_data {
struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
};
+static struct snd_soc_jack_pin sdm845_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
@@ -242,12 +253,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
if (!pdata->jack_setup) {
- rval = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADSET |
- SND_JACK_HEADPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &pdata->jack);
+ rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pdata->jack,
+ sdm845_jack_pins,
+ ARRAY_SIZE(sdm845_jack_pins));
if (rval < 0) {
dev_err(card->dev, "Unable to add Headphone Jack\n");
@@ -539,6 +552,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
SND_SOC_DAPM_MIC("Int Mic", NULL),
};
+static const struct snd_kcontrol_new sdm845_snd_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
static void sdm845_add_ops(struct snd_soc_card *card)
{
struct snd_soc_dai_link *link;
@@ -572,6 +590,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
card->driver_name = DRIVER_NAME;
card->dapm_widgets = sdm845_snd_widgets;
card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
+ card->controls = sdm845_snd_controls;
+ card->num_controls = ARRAY_SIZE(sdm845_snd_controls);
card->dev = dev;
card->owner = THIS_MODULE;
dev_set_drvdata(dev, card);
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 5e52e9d60d44..0f704d22d21b 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -41,13 +41,17 @@ static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
-
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
SND_SOC_DAPM_LINE("HDMI", NULL),
};
@@ -56,6 +60,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
SOC_DAPM_PIN_SWITCH("HDMI"),
};
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 575a0b9b01e9..834fbb5cf810 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -539,6 +539,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
+ .probe = rockchip_i2s_dai_probe,
.hw_params = rockchip_i2s_hw_params,
.set_bclk_ratio = rockchip_i2s_set_bclk_ratio,
.set_sysclk = rockchip_i2s_set_sysclk,
@@ -547,7 +548,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
};
static struct snd_soc_dai_driver rockchip_i2s_dai = {
- .probe = rockchip_i2s_dai_probe,
.ops = &rockchip_i2s_dai_ops,
.symmetric_rate = 1,
};
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index 166257c6ae14..d3700f3c98e6 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -1114,6 +1114,7 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai,
}
static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
+ .probe = rockchip_i2s_tdm_dai_probe,
.hw_params = rockchip_i2s_tdm_hw_params,
.set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio,
.set_sysclk = rockchip_i2s_tdm_set_sysclk,
@@ -1324,7 +1325,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = {
};
static const struct snd_soc_dai_driver i2s_tdm_dai = {
- .probe = rockchip_i2s_tdm_dai_probe,
.ops = &rockchip_i2s_tdm_dai_ops,
};
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index 52f9aae60be8..4756cfc23218 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -379,6 +379,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
+ .probe = rockchip_pdm_dai_probe,
.set_fmt = rockchip_pdm_set_fmt,
.trigger = rockchip_pdm_trigger,
.hw_params = rockchip_pdm_hw_params,
@@ -391,7 +392,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver rockchip_pdm_dai = {
- .probe = rockchip_pdm_dai_probe,
.capture = {
.stream_name = "Capture",
.channels_min = 2,
@@ -584,7 +584,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
match = of_match_device(rockchip_pdm_match, &pdev->dev);
if (match)
- pdm->version = (enum rk_pdm_version)match->data;
+ pdm->version = (uintptr_t)match->data;
if (pdm->version == RK_PDM_RK3308) {
pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index e73a342b7953..ef9fdf0386cb 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -22,6 +22,16 @@
#define DRV_NAME "rockchip-snd-rt5645"
static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
@@ -103,11 +113,13 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
int ret;
/* Enable Headset and 4 Buttons Jack detection */
- ret = snd_soc_card_jack_new(card, "Headset Jack",
- SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3,
- &headset_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+ SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
if (ret) {
dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
return ret;
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 0b73fe94e4bb..1a24b78e9e02 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -202,12 +202,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops rk_spdif_dai_ops = {
+ .probe = rk_spdif_dai_probe,
.hw_params = rk_spdif_hw_params,
.trigger = rk_spdif_trigger,
};
static struct snd_soc_dai_driver rk_spdif_dai = {
- .probe = rk_spdif_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 7492bb41456c..dd3cd2c9644a 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -620,10 +620,14 @@ static int aries_audio_probe(struct platform_device *pdev)
/* Update card-name if provided through DT, else use default name */
snd_soc_of_parse_card_name(card, "model");
- ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret < 0) {
- dev_err(dev, "Audio routing invalid/unspecified\n");
- return ret;
+ /* Backwards compatible way */
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0) {
+ dev_err(dev, "Audio routing invalid/unspecified\n");
+ return ret;
+ }
}
aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt;
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index f3d98abd5f0d..3af48c9b5ab7 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1120,6 +1120,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+ .probe = samsung_i2s_dai_probe,
+ .remove = samsung_i2s_dai_remove,
.trigger = i2s_trigger,
.hw_params = i2s_hw_params,
.set_fmt = i2s_set_fmt,
@@ -1188,9 +1190,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
for (i = 0; i < num_dais; i++) {
dai_drv = &priv->dai_drv[i];
- dai_drv->probe = samsung_i2s_dai_probe;
- dai_drv->remove = samsung_i2s_dai_remove;
-
dai_drv->symmetric_rate = 1;
dai_drv->ops = &samsung_i2s_dai_ops;
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 5d8118e69359..fafadcef234e 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -225,12 +225,15 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
}
static const struct snd_kcontrol_new controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("WM1250 Input"),
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
};
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_HP("Headset Mic", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
@@ -255,6 +258,16 @@ static const struct snd_soc_dapm_route audio_paths[] = {
};
static struct snd_soc_jack littlemill_headset;
+static struct snd_soc_jack_pin littlemill_headset_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
static int littlemill_late_probe(struct snd_soc_card *card)
{
@@ -281,12 +294,14 @@ static int littlemill_late_probe(struct snd_soc_card *card)
if (ret < 0)
return ret;
- ret = snd_soc_card_jack_new(card, "Headset",
- SND_JACK_HEADSET | SND_JACK_MECHANICAL |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 |
- SND_JACK_BTN_2 | SND_JACK_BTN_3 |
- SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &littlemill_headset);
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+ SND_JACK_BTN_4 | SND_JACK_BTN_5,
+ &littlemill_headset,
+ littlemill_headset_pins,
+ ARRAY_SIZE(littlemill_headset_pins));
if (ret)
return ret;
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 106770be6fc5..a79df871ea13 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -22,12 +22,16 @@ static struct snd_soc_jack lowland_headset;
static struct snd_soc_jack_pin lowland_headset_pins[] = {
{
.pin = "Headphone",
- .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
+ .mask = SND_JACK_HEADPHONE,
},
{
.pin = "Headset Mic",
.mask = SND_JACK_MICROPHONE,
},
+ {
+ .pin = "Line Out",
+ .mask = SND_JACK_LINEOUT,
+ },
};
static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
@@ -140,11 +144,13 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("WM1250 Input"),
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Line Out"),
};
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SPK("Main Speaker", NULL),
diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index 6931b9a45b3e..2ec7e16ddfa2 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -38,6 +38,17 @@ struct midas_priv {
struct snd_soc_jack headset_jack;
};
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
{
struct snd_soc_card *card = rtd->card;
@@ -261,6 +272,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
SND_SOC_DAPM_LINE("HDMI", NULL),
SND_SOC_DAPM_LINE("FM In", midas_fm_set),
+ SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
@@ -305,11 +317,13 @@ static int midas_late_probe(struct snd_soc_card *card)
return ret;
}
- ret = snd_soc_card_jack_new(card, "Headset",
- SND_JACK_HEADSET | SND_JACK_MECHANICAL |
- SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &priv->headset_jack);
+ ret = snd_soc_card_jack_new_pins(card, "Headset",
+ SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
+ &priv->headset_jack,
+ headset_jack_pins,
+ ARRAY_SIZE(headset_jack_pins));
if (ret)
return ret;
@@ -462,10 +476,14 @@ static int midas_probe(struct platform_device *pdev)
return ret;
}
- ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret < 0) {
- dev_err(dev, "Audio routing invalid/unspecified\n");
- return ret;
+ /* Backwards compatible way */
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0) {
+ dev_err(dev, "Audio routing invalid/unspecified\n");
+ return ret;
+ }
}
cpu = of_get_child_by_name(dev->of_node, "cpu");
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index a5442592bde4..c93cb5a86426 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -223,19 +223,20 @@ static int odroid_audio_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) {
+ if (of_property_present(dev->of_node, "samsung,audio-widgets")) {
ret = snd_soc_of_parse_audio_simple_widgets(card,
"samsung,audio-widgets");
if (ret < 0)
return ret;
}
- if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) {
- ret = snd_soc_of_parse_audio_routing(card,
- "samsung,audio-routing");
- if (ret < 0)
- return ret;
- }
+ ret = 0;
+ if (of_property_present(dev->of_node, "audio-routing"))
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ else if (of_property_present(dev->of_node, "samsung,audio-routing"))
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0)
+ return ret;
card->dai_link = odroid_card_dais;
card->num_links = ARRAY_SIZE(odroid_card_dais);
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 335fe5cb9cfc..d2cdc5c8e05b 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
return 0;
}
-static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
- .set_sysclk = s3c_pcm_set_sysclk,
- .set_clkdiv = s3c_pcm_set_clkdiv,
- .trigger = s3c_pcm_trigger,
- .hw_params = s3c_pcm_hw_params,
- .set_fmt = s3c_pcm_set_fmt,
-};
-
static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
{
struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai);
@@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+ .probe = s3c_pcm_dai_probe,
+ .set_sysclk = s3c_pcm_set_sysclk,
+ .set_clkdiv = s3c_pcm_set_clkdiv,
+ .trigger = s3c_pcm_trigger,
+ .hw_params = s3c_pcm_hw_params,
+ .set_fmt = s3c_pcm_set_fmt,
+};
+
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
#define S3C_PCM_DAI_DECLARE \
.symmetric_rate = 1, \
- .probe = s3c_pcm_dai_probe, \
.ops = &s3c_pcm_dai_ops, \
.playback = { \
.channels_min = 2, \
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index d611ec9e5325..5ebf17f3de1e 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -523,10 +523,14 @@ static int tm2_probe(struct platform_device *pdev)
return ret;
}
- ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret < 0) {
- dev_err(dev, "Audio routing is not specified or invalid\n");
- return ret;
+ /* Backwards compatible way */
+ ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+ if (ret < 0) {
+ dev_err(dev, "Audio routing is not specified or invalid\n");
+ return ret;
+ }
}
card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node,
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 0b8926600d90..230c48648af3 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -358,8 +358,6 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
ckr = 0x80000000; /* BRGB output = 48kHz */
rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
- rsnd_mod_write(adg_mod, BRRA, adg->brga);
- rsnd_mod_write(adg_mod, BRRB, adg->brgb);
dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
(ckr) ? 'B' : 'A',
@@ -372,9 +370,16 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct clk *clk;
int i;
+ if (enable) {
+ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr);
+ rsnd_mod_write(adg_mod, BRRA, adg->brga);
+ rsnd_mod_write(adg_mod, BRRB, adg->brgb);
+ }
+
for_each_rsnd_clkin(clk, adg, i) {
if (enable) {
clk_prepare_enable(clk);
@@ -485,12 +490,12 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
struct device_node *np = dev->of_node;
struct property *prop;
u32 ckr, brgx, brga, brgb;
- u32 rate, div;
u32 req_rate[ADG_HZ_SIZE] = {};
uint32_t count = 0;
unsigned long req_Hz[ADG_HZ_SIZE];
int clkout_size;
int i, req_size;
+ int approximate = 0;
const char *parent_clk_name = NULL;
const char * const *clkout_name;
int brg_table[] = {
@@ -501,8 +506,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
};
ckr = 0;
- brga = 2; /* default 1/6 */
- brgb = 2; /* default 1/6 */
+ brga = 0xff; /* default */
+ brgb = 0xff; /* default */
/*
* ADG supports BRRA/BRRB output only
@@ -537,17 +542,41 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
* rsnd_adg_ssi_clk_try_start()
* rsnd_ssi_master_clk_start()
*/
+
+ /*
+ * [APPROXIMATE]
+ *
+ * clk_i (internal clock) can't create accurate rate, it will be approximate rate.
+ *
+ * <Note>
+ *
+ * clk_i needs x2 of required maximum rate.
+ * see
+ * - Minimum division of BRRA/BRRB
+ * - rsnd_ssi_clk_query()
+ *
+ * Sample Settings for TDM 8ch, 32bit width
+ *
+ * 8(ch) x 32(bit) x 44100(Hz) x 2<Note> = 22579200
+ * 8(ch) x 32(bit) x 48000(Hz) x 2<Note> = 24576000
+ *
+ * clock-frequency = <22579200 24576000>;
+ */
for_each_rsnd_clkin(clk, adg, i) {
+ u32 rate, div;
+
rate = clk_get_rate(clk);
if (0 == rate) /* not used */
continue;
/* BRGA */
- if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) {
- div = 6;
- if (req_Hz[ADG_HZ_441])
- div = rate / req_Hz[ADG_HZ_441];
+
+ if (i == CLKI)
+ /* see [APPROXIMATE] */
+ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441];
+ if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) {
+ div = rate / req_Hz[ADG_HZ_441];
brgx = rsnd_adg_calculate_brgx(div);
if (BRRx_MASK(brgx) == brgx) {
brga = brgx;
@@ -555,14 +584,18 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
ckr |= brg_table[i] << 20;
if (req_Hz[ADG_HZ_441])
parent_clk_name = __clk_get_name(clk);
+ if (i == CLKI)
+ approximate = 1;
}
}
/* BRGB */
- if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) {
- div = 6;
- if (req_Hz[ADG_HZ_48])
- div = rate / req_Hz[ADG_HZ_48];
+
+ if (i == CLKI)
+ /* see [APPROXIMATE] */
+ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48];
+ if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) {
+ div = rate / req_Hz[ADG_HZ_48];
brgx = rsnd_adg_calculate_brgx(div);
if (BRRx_MASK(brgx) == brgx) {
brgb = brgx;
@@ -570,10 +603,19 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
ckr |= brg_table[i] << 16;
if (req_Hz[ADG_HZ_48])
parent_clk_name = __clk_get_name(clk);
+ if (i == CLKI)
+ approximate = 1;
}
}
}
+ if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) &&
+ !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441]))
+ goto rsnd_adg_get_clkout_end;
+
+ if (approximate)
+ dev_info(dev, "It uses CLK_I as approximate rate");
+
clkout_name = clkout_name_gen2;
clkout_size = ARRAY_SIZE(clkout_name_gen2);
if (rsnd_is_gen4(priv))
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 6a522e6dd85a..e29c2fee9521 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1085,17 +1085,6 @@ static u64 rsnd_soc_dai_formats[] = {
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
- .startup = rsnd_soc_dai_startup,
- .shutdown = rsnd_soc_dai_shutdown,
- .trigger = rsnd_soc_dai_trigger,
- .set_fmt = rsnd_soc_dai_set_fmt,
- .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
- .prepare = rsnd_soc_dai_prepare,
- .auto_selectable_formats = rsnd_soc_dai_formats,
- .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats),
-};
-
static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct device_node *dai_np)
@@ -1260,13 +1249,13 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name
return i;
}
-static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
- int *is_graph)
+static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
- struct device_node *dai_node;
- struct device_node *ret;
+ struct device_node *ports, *node;
+ int nr = 0;
+ int i = 0;
*is_graph = 0;
@@ -1274,26 +1263,53 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
* parse both previous dai (= rcar_sound,dai), and
* graph dai (= ports/port)
*/
- dai_node = of_get_child_by_name(np, RSND_NODE_DAI);
- if (dai_node) {
- ret = dai_node;
- goto of_node_compatible;
- }
- ret = np;
+ /*
+ * Simple-Card
+ */
+ node = of_get_child_by_name(np, RSND_NODE_DAI);
+ if (!node)
+ goto audio_graph;
- dai_node = of_graph_get_next_endpoint(np, NULL);
- if (dai_node)
- goto of_node_graph;
+ of_node_put(node);
- return NULL;
+ for_each_child_of_node(np, node) {
+ if (!of_node_name_eq(node, RSND_NODE_DAI))
+ continue;
+
+ priv->component_dais[i] = of_get_child_count(node);
+ nr += priv->component_dais[i];
+ i++;
+ if (i >= RSND_MAX_COMPONENT) {
+ dev_info(dev, "reach to max component\n");
+ of_node_put(node);
+ break;
+ }
+ }
+
+ return nr;
+
+audio_graph:
+ /*
+ * Audio-Graph-Card
+ */
+ for_each_child_of_node(np, ports) {
+ if (!of_node_name_eq(ports, "ports") &&
+ !of_node_name_eq(ports, "port"))
+ continue;
+ priv->component_dais[i] = of_graph_get_endpoint_count(ports);
+ nr += priv->component_dais[i];
+ i++;
+ if (i >= RSND_MAX_COMPONENT) {
+ dev_info(dev, "reach to max component\n");
+ of_node_put(node);
+ break;
+ }
+ }
-of_node_graph:
*is_graph = 1;
-of_node_compatible:
- of_node_put(dai_node);
- return ret;
+ return nr;
}
@@ -1328,8 +1344,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd,
- struct snd_soc_dai *dai)
+static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
int ret;
@@ -1355,8 +1370,22 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+ .pcm_new = rsnd_soc_dai_pcm_new,
+ .startup = rsnd_soc_dai_startup,
+ .shutdown = rsnd_soc_dai_shutdown,
+ .trigger = rsnd_soc_dai_trigger,
+ .set_fmt = rsnd_soc_dai_set_fmt,
+ .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
+ .prepare = rsnd_soc_dai_prepare,
+ .auto_selectable_formats = rsnd_soc_dai_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats),
+};
+
static void __rsnd_dai_probe(struct rsnd_priv *priv,
struct device_node *dai_np,
+ struct device_node *node_np,
+ uint32_t node_arg,
int dai_i)
{
struct rsnd_dai_stream *io_playback;
@@ -1374,10 +1403,16 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
+ /* for multi Component */
+ rdai->dai_args.np = node_np;
+ rdai->dai_args.args_count = 1;
+ rdai->dai_args.args[0] = node_arg;
+
rdai->priv = priv;
drv->name = rdai->name;
drv->ops = &rsnd_soc_dai_ops;
- drv->pcm_new = rsnd_pcm_new;
+ drv->id = dai_i;
+ drv->dai_args = &rdai->dai_args;
io_playback->rdai = rdai;
io_capture->rdai = rdai;
@@ -1441,21 +1476,15 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
static int rsnd_dai_probe(struct rsnd_priv *priv)
{
- struct device_node *dai_node;
- struct device_node *dai_np;
struct snd_soc_dai_driver *rdrv;
struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *np = dev->of_node;
struct rsnd_dai *rdai;
- int nr;
+ int nr = 0;
int is_graph;
int dai_i;
- dai_node = rsnd_dai_of_node(priv, &is_graph);
- if (is_graph)
- nr = of_graph_get_endpoint_count(dai_node);
- else
- nr = of_get_child_count(dai_node);
-
+ nr = rsnd_dai_of_node(priv, &is_graph);
if (!nr)
return -EINVAL;
@@ -1473,26 +1502,42 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
*/
dai_i = 0;
if (is_graph) {
- for_each_endpoint_of_node(dai_node, dai_np) {
- __rsnd_dai_probe(priv, dai_np, dai_i);
- if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
- rdai = rsnd_rdai_get(priv, dai_i);
-
- rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
- rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
+ struct device_node *ports;
+ struct device_node *dai_np;
+
+ for_each_child_of_node(np, ports) {
+ if (!of_node_name_eq(ports, "ports") &&
+ !of_node_name_eq(ports, "port"))
+ continue;
+ for_each_endpoint_of_node(ports, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
+ if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
+ rdai = rsnd_rdai_get(priv, dai_i);
+
+ rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+ rsnd_parse_connect_graph(priv, &rdai->capture, dai_np);
+ }
+ dai_i++;
}
- dai_i++;
}
} else {
- for_each_child_of_node(dai_node, dai_np) {
- __rsnd_dai_probe(priv, dai_np, dai_i);
- if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
- rdai = rsnd_rdai_get(priv, dai_i);
+ struct device_node *node;
+ struct device_node *dai_np;
+
+ for_each_child_of_node(np, node) {
+ if (!of_node_name_eq(node, RSND_NODE_DAI))
+ continue;
- rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
- rsnd_parse_connect_simple(priv, &rdai->capture, dai_np);
+ for_each_child_of_node(node, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i);
+ if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
+ rdai = rsnd_rdai_get(priv, dai_i);
+
+ rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
+ rsnd_parse_connect_simple(priv, &rdai->capture, dai_np);
+ }
+ dai_i++;
}
- dai_i++;
}
}
@@ -1922,6 +1967,7 @@ static int rsnd_probe(struct platform_device *pdev)
rsnd_dai_probe,
};
int ret, i;
+ int ci;
/*
* init priv data
@@ -1958,11 +2004,18 @@ static int rsnd_probe(struct platform_device *pdev)
/*
* asoc register
*/
- ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
- priv->daidrv, rsnd_rdai_nr(priv));
- if (ret < 0) {
- dev_err(dev, "cannot snd dai register\n");
- goto exit_snd_probe;
+ ci = 0;
+ for (i = 0; priv->component_dais[i] > 0; i++) {
+ int nr = priv->component_dais[i];
+
+ ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
+ priv->daidrv + ci, nr);
+ if (ret < 0) {
+ dev_err(dev, "cannot snd component register\n");
+ goto exit_snd_probe;
+ }
+
+ ci += nr;
}
pm_runtime_enable(dev);
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 239705d52517..43c0d675cc34 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -545,6 +545,7 @@ struct rsnd_dai {
struct rsnd_dai_stream capture;
struct rsnd_priv *priv;
struct snd_pcm_hw_constraint_list constraint;
+ struct of_phandle_args dai_args;
int max_channels; /* 2ch - 16ch */
int ssi_lane; /* 1lane - 4lane */
@@ -702,6 +703,9 @@ struct rsnd_priv {
struct snd_soc_dai_driver *daidrv;
struct rsnd_dai *rdai;
int rdai_nr;
+
+#define RSND_MAX_COMPONENT 3
+ int component_dais[RSND_MAX_COMPONENT];
};
#define rsnd_priv_to_pdev(priv) ((priv)->pdev)
diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c
index 142476f1396f..6d693b2ad5a3 100644
--- a/sound/soc/soc-acpi.c
+++ b/sound/soc/soc-acpi.c
@@ -125,5 +125,78 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
}
EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
+#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
+ SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
+
+/* Check if all Slaves defined on the link can be found */
+bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
+ const struct snd_soc_acpi_link_adr *link,
+ struct sdw_extended_slave_id *ids,
+ int num_slaves)
+{
+ unsigned int part_id, link_id, unique_id, mfg_id, version;
+ int i, j, k;
+
+ for (i = 0; i < link->num_adr; i++) {
+ u64 adr = link->adr_d[i].adr;
+ int reported_part_count = 0;
+
+ mfg_id = SDW_MFG_ID(adr);
+ part_id = SDW_PART_ID(adr);
+ link_id = SDW_DISCO_LINK_ID(adr);
+ version = SDW_VERSION(adr);
+
+ for (j = 0; j < num_slaves; j++) {
+ /* find out how many identical parts were reported on that link */
+ if (ids[j].link_id == link_id &&
+ ids[j].id.part_id == part_id &&
+ ids[j].id.mfg_id == mfg_id &&
+ ids[j].id.sdw_version == version)
+ reported_part_count++;
+ }
+
+ for (j = 0; j < num_slaves; j++) {
+ int expected_part_count = 0;
+
+ if (ids[j].link_id != link_id ||
+ ids[j].id.part_id != part_id ||
+ ids[j].id.mfg_id != mfg_id ||
+ ids[j].id.sdw_version != version)
+ continue;
+
+ /* find out how many identical parts are expected */
+ for (k = 0; k < link->num_adr; k++) {
+ u64 adr2 = link->adr_d[k].adr;
+
+ if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
+ expected_part_count++;
+ }
+
+ if (reported_part_count == expected_part_count) {
+ /*
+ * we have to check unique id
+ * if there is more than one
+ * Slave on the link
+ */
+ unique_id = SDW_UNIQUE_ID(adr);
+ if (reported_part_count == 1 ||
+ ids[j].id.unique_id == unique_id) {
+ dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id);
+ break;
+ }
+ } else {
+ dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n",
+ part_id, reported_part_count, expected_part_count, link_id);
+ }
+ }
+ if (j == num_slaves) {
+ dev_dbg(dev, "Slave part_id %#x not found\n", part_id);
+ return false;
+ }
+ }
+ return true;
+}
+EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ALSA SoC ACPI module");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a5b96c17633a..cc442c52cdea 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -942,7 +942,7 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
* component list.
*/
if (!soc_find_component(dlc))
- goto component_not_find;
+ goto component_not_found;
}
/* Platform check */
@@ -963,7 +963,7 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
* component list.
*/
if (!soc_find_component(dlc))
- goto component_not_find;
+ goto component_not_found;
}
/* CPU check */
@@ -988,7 +988,7 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
* Defer card registration if Component is not added
*/
if (!soc_find_component(dlc))
- goto component_not_find;
+ goto component_not_found;
}
}
@@ -1002,8 +1002,8 @@ component_empty:
dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name);
return -EINVAL;
-component_not_find:
- dev_err(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
+component_not_found:
+ dev_dbg(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
return -EPROBE_DEFER;
dai_empty:
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 02dd64dea179..3f33f0630ad8 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -424,6 +424,9 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
{
int ret = 0;
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return 0;
+
if (dai->driver->ops &&
dai->driver->ops->startup)
ret = dai->driver->ops->startup(substream, dai);
@@ -439,6 +442,9 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
struct snd_pcm_substream *substream,
int rollback)
{
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return;
+
if (rollback && !soc_dai_mark_match(dai, substream, startup))
return;
@@ -454,8 +460,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
struct snd_soc_pcm_runtime *rtd, int num)
{
int ret = -ENOTSUPP;
- if (dai->driver->compress_new)
- ret = dai->driver->compress_new(rtd, num);
+ if (dai->driver->ops &&
+ dai->driver->ops->compress_new)
+ ret = dai->driver->ops->compress_new(rtd, num);
return soc_dai_ret(dai, ret);
}
@@ -539,19 +546,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
int i;
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->probe_order != order)
- continue;
-
if (dai->probed)
continue;
- if (dai->driver->probe) {
- int ret = dai->driver->probe(dai);
+ if (dai->driver->ops) {
+ if (dai->driver->ops->probe_order != order)
+ continue;
- if (ret < 0)
- return soc_dai_ret(dai, ret);
- }
+ if (dai->driver->ops->probe) {
+ int ret = dai->driver->ops->probe(dai);
+ if (ret < 0)
+ return soc_dai_ret(dai, ret);
+ }
+ }
dai->probed = 1;
}
@@ -564,16 +572,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
int i, r, ret = 0;
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->remove_order != order)
+ if (!dai->probed)
continue;
- if (dai->probed &&
- dai->driver->remove) {
- r = dai->driver->remove(dai);
- if (r < 0)
- ret = r; /* use last error */
- }
+ if (dai->driver->ops) {
+ if (dai->driver->ops->remove_order != order)
+ continue;
+ if (dai->driver->ops->remove) {
+ r = dai->driver->ops->remove(dai);
+ if (r < 0)
+ ret = r; /* use last error */
+ }
+ }
dai->probed = 0;
}
@@ -586,8 +597,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
int i;
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->pcm_new) {
- int ret = dai->driver->pcm_new(rtd, dai);
+ if (dai->driver->ops &&
+ dai->driver->ops->pcm_new) {
+ int ret = dai->driver->ops->pcm_new(rtd, dai);
if (ret < 0)
return soc_dai_ret(dai, ret);
}
@@ -603,6 +615,8 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
int i, ret;
for_each_rtd_dais(rtd, i, dai) {
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ continue;
if (dai->driver->ops &&
dai->driver->ops->prepare) {
ret = dai->driver->ops->prepare(substream, dai);
@@ -619,6 +633,9 @@ static int soc_dai_trigger(struct snd_soc_dai *dai,
{
int ret = 0;
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return 0;
+
if (dai->driver->ops &&
dai->driver->ops->trigger)
ret = dai->driver->ops->trigger(substream, cmd, dai);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 3091e8160bad..f07e83678373 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -916,6 +916,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
return -EINVAL;
}
}
+ if (w->no_wname_in_kcontrol_name)
+ wname_in_long_name = false;
if (wname_in_long_name && kcname_in_long_name) {
/*
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index f951acb2ce36..b2cc13b9c77b 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -37,7 +37,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
struct snd_soc_jack_pin *pin;
unsigned int sync = 0;
- if (!jack)
+ if (!jack || !jack->jack)
return;
trace_snd_soc_jack_report(jack, mask, status);
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 3592ff09f692..2362c282ec8b 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1560,6 +1560,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
1 : 0;
}
+static const struct snd_soc_dai_ops tplg_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static int soc_tplg_dai_create(struct soc_tplg *tplg,
struct snd_soc_tplg_pcm *pcm)
{
@@ -1601,7 +1605,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
}
if (pcm->compress)
- dai_drv->compress_new = snd_soc_new_compress;
+ dai_drv->ops = &tplg_dai_ops;
/* pass control to component driver for optional further init */
ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 7dbc8df5cfe6..f2faa08f0c0e 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -2,7 +2,7 @@
# This file is provided under a dual BSD/GPLv2 license. When using or
# redistributing this file, you may do so under either license.
#
-# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
config SND_SOC_SOF_AMD_TOPLEVEL
tristate "SOF support for AMD audio DSPs"
@@ -34,6 +34,16 @@ config SND_SOC_SOF_AMD_RENOIR
help
Select this option for SOF support on AMD Renoir platform
+config SND_SOC_SOF_AMD_VANGOGH
+ tristate "SOF support for VANGOGH"
+ depends on SND_SOC_SOF_PCI
+ select SND_SOC_SOF_AMD_COMMON
+ help
+ Select this option for SOF support
+ on AMD Vangogh platform.
+ Say Y if you want to enable SOF on Vangogh.
+ If unsure select "N".
+
config SND_SOC_SOF_AMD_REMBRANDT
tristate "SOF support for REMBRANDT"
depends on SND_SOC_SOF_PCI
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile
index ef9f7df4e379..f3b375e67a6f 100644
--- a/sound/soc/sof/amd/Makefile
+++ b/sound/soc/sof/amd/Makefile
@@ -2,13 +2,15 @@
# This file is provided under a dual BSD/GPLv2 license. When using or
# redistributing this file, you may do so under either license.
#
-# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o
snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o
snd-sof-amd-renoir-objs := pci-rn.o renoir.o
snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o
+snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o
obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) +=snd-sof-amd-vangogh.o
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index 920155dee819..a913f1cc4c80 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -3,7 +3,7 @@
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
- * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
*
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
*/
@@ -49,27 +49,33 @@
#define ACP_CONTROL 0x1004
#define ACP3X_I2S_PIN_CONFIG 0x1400
+#define ACP5X_I2S_PIN_CONFIG 0x1400
#define ACP6X_I2S_PIN_CONFIG 0x1440
/* Registers offsets from ACP_PGFSM block */
#define ACP3X_PGFSM_BASE 0x141C
+#define ACP5X_PGFSM_BASE 0x1424
#define ACP6X_PGFSM_BASE 0x1024
#define PGFSM_CONTROL_OFFSET 0x0
#define PGFSM_STATUS_OFFSET 0x4
#define ACP3X_CLKMUX_SEL 0x1424
+#define ACP5X_CLKMUX_SEL 0x142C
#define ACP6X_CLKMUX_SEL 0x102C
/* Registers from ACP_INTR block */
#define ACP3X_EXT_INTR_STAT 0x1808
+#define ACP5X_EXT_INTR_STAT 0x1808
#define ACP6X_EXT_INTR_STAT 0x1A0C
#define ACP3X_DSP_SW_INTR_BASE 0x1814
+#define ACP5X_DSP_SW_INTR_BASE 0x1814
#define ACP6X_DSP_SW_INTR_BASE 0x1808
#define DSP_SW_INTR_CNTL_OFFSET 0x0
#define DSP_SW_INTR_STAT_OFFSET 0x4
#define DSP_SW_INTR_TRIG_OFFSET 0x8
#define ACP_ERROR_STATUS 0x18C4
#define ACP3X_AXI2DAGB_SEM_0 0x1880
+#define ACP5X_AXI2DAGB_SEM_0 0x1884
#define ACP6X_AXI2DAGB_SEM_0 0x1874
/* Registers from ACP_SHA block */
@@ -81,6 +87,7 @@
#define ACP_SHA_DMA_CMD_STS 0x1CC0
#define ACP_SHA_DMA_ERR_STATUS 0x1CC4
#define ACP_SHA_TRANSFER_BYTE_CNT 0x1CC8
+#define ACP_SHA_DMA_INCLUDE_HDR 0x1CCC
#define ACP_SHA_PSP_ACK 0x1C74
#define ACP_SCRATCH_REG_0 0x10000
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index 81a2c096a185..fcb54f545fea 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -170,6 +170,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status),
true);
+ status = 0;
+ acp_mailbox_write(sdev, sdev->dsp_box.offset, &status, sizeof(status));
return IRQ_HANDLED;
}
snd_sof_ipc_msgs_rx(sdev);
@@ -199,6 +201,8 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
acp_mailbox_read(sdev, sdev->debug_box.offset, &status, sizeof(u32));
if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, sdev->dsp_oops_offset, true);
+ status = 0;
+ acp_mailbox_write(sdev, sdev->debug_box.offset, &status, sizeof(status));
return IRQ_HANDLED;
}
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index a4bce5a3ae48..a427673cfb03 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -3,7 +3,7 @@
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
-// Copyright(c) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
@@ -158,7 +158,11 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
int ret;
adata = sdev->pdata->hw_pdata;
- size_fw = adata->fw_bin_size;
+
+ if (adata->signed_fw_image)
+ size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
+ else
+ size_fw = adata->fw_bin_size;
page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
adata->fw_bin_page_count = page_count;
@@ -203,6 +207,7 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON);
int acp_sof_dsp_run(struct snd_sof_dev *sdev)
{
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
int val;
@@ -211,7 +216,7 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val);
/* Some platforms won't support fusion DSP,keep offset zero for no support */
- if (desc->fusion_dsp_offset) {
+ if (desc->fusion_dsp_offset && adata->enable_fw_debug) {
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN);
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset);
dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val);
@@ -219,3 +224,34 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev)
return 0;
}
EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON);
+
+int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct acp_dev_data *adata = plat_data->hw_pdata;
+ int ret;
+
+ ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "sof signed firmware code bin is missing\n");
+ return ret;
+ } else {
+ dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin);
+ }
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
+ (void *)sdev->basefw.fw->data, sdev->basefw.fw->size);
+
+ ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "sof signed firmware data bin is missing\n");
+ return ret;
+
+ } else {
+ dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin);
+ }
+
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
+ (void *)adata->fw_dbin->data, adata->fw_dbin->size);
+ return ret;
+}
+EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON);
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index c450931ae77e..19a801908b56 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -3,7 +3,7 @@
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
-// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
// Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
@@ -20,6 +20,26 @@
#include "acp.h"
#include "acp-dsp-offset.h"
+#define SECURED_FIRMWARE 1
+
+static bool enable_fw_debug;
+module_param(enable_fw_debug, bool, 0444);
+MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
+
+const struct dmi_system_id acp_sof_quirk_table[] = {
+ {
+ /* Valve Jupiter device */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"),
+ },
+ .driver_data = (void *)SECURED_FIRMWARE,
+ },
+ {}
+};
+EXPORT_SYMBOL_GPL(acp_sof_quirk_table);
+
static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
{
pci_write_config_dword(dev, 0x60, smn_addr);
@@ -235,6 +255,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
}
}
+ if (adata->signed_fw_image)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER);
+
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length);
@@ -318,14 +341,7 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
- unsigned int val, count = ACP_HW_SEM_RETRY_COUNT;
-
- val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
- if (val & ACP_SHA_STAT) {
- /* Clear SHA interrupt raised by PSP */
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val);
- return IRQ_HANDLED;
- }
+ unsigned int count = ACP_HW_SEM_RETRY_COUNT;
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
/* Wait until acquired HW Semaphore lock or timeout */
@@ -351,9 +367,9 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
unsigned int val;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
- if (val) {
- val |= ACP_DSP_TO_HOST_IRQ;
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val);
+ if (val & ACP_DSP_TO_HOST_IRQ) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
+ ACP_DSP_TO_HOST_IRQ);
return IRQ_WAKE_THREAD;
}
@@ -407,7 +423,12 @@ static int acp_reset(struct snd_sof_dev *sdev)
if (ret < 0)
dev_err(sdev->dev, "timeout in releasing reset\n");
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
+ if (desc->acp_clkmux_sel)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
+
+ if (desc->ext_intr_enb)
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01);
+
return ret;
}
@@ -445,7 +466,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_resume(struct snd_sof_dev *sdev)
{
- const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
int ret;
ret = acp_init(sdev);
@@ -453,20 +473,17 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "ACP Init failed\n");
return ret;
}
-
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);
-
- ret = acp_memory_init(sdev);
-
- return ret;
+ return acp_memory_init(sdev);
}
EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
+ struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata;
const struct sof_amd_acp_desc *chip;
+ const struct dmi_system_id *dmi_id;
unsigned int addr;
int ret;
@@ -527,6 +544,21 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
sdev->debug_box.size = BOX_SIZE_1024;
+ adata->signed_fw_image = false;
+ dmi_id = dmi_first_match(acp_sof_quirk_table);
+ if (dmi_id && dmi_id->driver_data) {
+ adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin",
+ plat_data->fw_filename_prefix,
+ chip->name);
+ adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin",
+ plat_data->fw_filename_prefix,
+ chip->name);
+ adata->signed_fw_image = dmi_id->driver_data;
+
+ dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin,
+ adata->fw_data_bin);
+ }
+ adata->enable_fw_debug = enable_fw_debug;
acp_memory_init(sdev);
acp_dsp_stream_init(sdev);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 72fa0af971f0..4dcceb764769 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -3,7 +3,7 @@
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
- * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
*
* Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
*/
@@ -11,6 +11,8 @@
#ifndef __SOF_AMD_ACP_H
#define __SOF_AMD_ACP_H
+#include <linux/dmi.h>
+
#include "../sof-priv.h"
#include "../sof-audio.h"
@@ -32,6 +34,7 @@
#define ACP_DSP_INTR_EN_MASK 0x00000001
#define ACP3X_SRAM_PTE_OFFSET 0x02050000
+#define ACP5X_SRAM_PTE_OFFSET 0x02050000
#define ACP6X_SRAM_PTE_OFFSET 0x03800000
#define PAGE_SIZE_4K_ENABLE 0x2
#define ACP_PAGE_SIZE 0x1000
@@ -40,6 +43,7 @@
#define DSP_FW_RUN_ENABLE 0x01
#define ACP_SHA_RUN 0x01
#define ACP_SHA_RESET 0x02
+#define ACP_SHA_HEADER 0x01
#define ACP_DMA_CH_RST 0x01
#define ACP_DMA_CH_GRACEFUL_RST_EN 0x10
#define ACP_ATU_CACHE_INVALID 0x01
@@ -56,9 +60,11 @@
#define ACP_DSP_TO_HOST_IRQ 0x04
#define ACP_RN_PCI_ID 0x01
+#define ACP_VANGOGH_PCI_ID 0x50
#define ACP_RMB_PCI_ID 0x6F
#define HOST_BRIDGE_CZN 0x1630
+#define HOST_BRIDGE_VGH 0x1645
#define HOST_BRIDGE_RMB 0x14B5
#define ACP_SHA_STAT 0x8000
#define ACP_PSP_TIMEOUT_US 1000000
@@ -79,6 +85,8 @@
#define SRAM1_SIZE 0x13A000
#define PROBE_STATUS_BIT BIT(31)
+#define ACP_FIRMWARE_SIGNATURE 0x100
+
enum clock_source {
ACP_CLOCK_96M = 0,
ACP_CLOCK_48M,
@@ -163,8 +171,10 @@ struct acp_dsp_stream {
struct sof_amd_acp_desc {
unsigned int rev;
+ const char *name;
unsigned int host_bridge_id;
u32 pgfsm_base;
+ u32 ext_intr_enb;
u32 ext_intr_stat;
u32 dsp_intr_base;
u32 sram_pte_offset;
@@ -177,20 +187,25 @@ struct sof_amd_acp_desc {
/* Common device data struct for ACP devices */
struct acp_dev_data {
struct snd_sof_dev *dev;
+ const struct firmware *fw_dbin;
/* DMIC device */
struct platform_device *dmic_dev;
unsigned int fw_bin_size;
unsigned int fw_data_bin_size;
+ const char *fw_code_bin;
+ const char *fw_data_bin;
u32 fw_bin_page_count;
dma_addr_t sha_dma_addr;
u8 *bin_buf;
dma_addr_t dma_addr;
u8 *data_buf;
+ bool signed_fw_image;
struct dma_descriptor dscr_info[ACP_MAX_DESC];
struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
struct acp_dsp_stream *dtrace_stream;
struct pci_dev *smn_dev;
struct acp_dsp_stream *probe_stream;
+ bool enable_fw_debug;
};
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -210,6 +225,7 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev);
/* DSP Loader callbacks */
int acp_sof_dsp_run(struct snd_sof_dev *sdev);
int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev);
+int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev);
int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type);
/* Block IO callbacks */
@@ -253,6 +269,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops;
extern struct snd_sof_dsp_ops sof_renoir_ops;
int sof_renoir_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_vangogh_ops;
+int sof_vangogh_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_rembrandt_ops;
int sof_rembrandt_ops_init(struct snd_sof_dev *sdev);
@@ -282,4 +300,6 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata
int acp_probes_register(struct snd_sof_dev *sdev);
void acp_probes_unregister(struct snd_sof_dev *sdev);
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[];
+extern const struct dmi_system_id acp_sof_quirk_table[];
#endif
diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c
new file mode 100644
index 000000000000..d8be42fbcb6d
--- /dev/null
+++ b/sound/soc/sof/amd/pci-vangogh.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com>
+
+/*.
+ * PCI interface for Vangogh ACP device
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <sound/sof.h>
+#include <sound/soc-acpi.h>
+
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+#include "../../amd/mach-config.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define ACP5X_FUTURE_REG_ACLK_0 0x1864
+
+static const struct sof_amd_acp_desc vangogh_chip_info = {
+ .rev = 5,
+ .name = "vangogh",
+ .host_bridge_id = HOST_BRIDGE_VGH,
+ .pgfsm_base = ACP5X_PGFSM_BASE,
+ .ext_intr_stat = ACP5X_EXT_INTR_STAT,
+ .dsp_intr_base = ACP5X_DSP_SW_INTR_BASE,
+ .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET,
+ .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0,
+ .acp_clkmux_sel = ACP5X_CLKMUX_SEL,
+ .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0,
+};
+
+static const struct sof_dev_desc vangogh_desc = {
+ .machines = snd_soc_acpi_amd_vangogh_sof_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &vangogh_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC),
+ .ipc_default = SOF_IPC,
+ .default_fw_path = {
+ [SOF_IPC] = "amd/sof",
+ },
+ .default_tplg_path = {
+ [SOF_IPC] = "amd/sof-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC] = "sof-vangogh.ri",
+ },
+ .nocodec_tplg_filename = "sof-acp.tplg",
+ .ops = &sof_vangogh_ops,
+ .ops_init = sof_vangogh_ops_init,
+};
+
+static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ unsigned int flag;
+
+ if (pci->revision != ACP_VANGOGH_PCI_ID)
+ return -ENODEV;
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+ return -ENODEV;
+
+ return sof_pci_probe(pci, pci_id);
+};
+
+static void acp_pci_vgh_remove(struct pci_dev *pci)
+{
+ sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id vgh_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+ .driver_data = (unsigned long)&vangogh_desc},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, vgh_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_vgh_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = vgh_pci_ids,
+ .probe = acp_pci_vgh_probe,
+ .remove = acp_pci_vgh_remove,
+ .driver = {
+ .pm = &sof_pci_pm,
+ },
+};
+module_pci_driver(snd_sof_pci_amd_vgh_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c
new file mode 100644
index 000000000000..de15d21aa6d9
--- /dev/null
+++ b/sound/soc/sof/amd/vangogh.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on Vangogh platform
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include "../ops.h"
+#include "../sof-audio.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define I2S_HS_INSTANCE 0
+#define I2S_BT_INSTANCE 1
+#define I2S_SP_INSTANCE 2
+#define PDM_DMIC_INSTANCE 3
+#define I2S_HS_VIRTUAL_INSTANCE 4
+
+static struct snd_soc_dai_driver vangogh_sof_dai[] = {
+ [I2S_HS_INSTANCE] = {
+ .id = I2S_HS_INSTANCE,
+ .name = "acp-sof-hs",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_BT_INSTANCE] = {
+ .id = I2S_BT_INSTANCE,
+ .name = "acp-sof-bt",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S BT controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_SP_INSTANCE] = {
+ .id = I2S_SP_INSTANCE,
+ .name = "acp-sof-sp",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S SP controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM_DMIC_INSTANCE] = {
+ .id = PDM_DMIC_INSTANCE,
+ .name = "acp-sof-dmic",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_HS_VIRTUAL_INSTANCE] = {
+ .id = I2S_HS_VIRTUAL_INSTANCE,
+ .name = "acp-sof-hs-virtual",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS-Virtual controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+};
+
+/* Vangogh ops */
+struct snd_sof_dsp_ops sof_vangogh_ops;
+EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON);
+
+int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
+{
+ const struct dmi_system_id *dmi_id;
+
+ /* common defaults */
+ memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ sof_vangogh_ops.drv = vangogh_sof_dai;
+ sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai);
+
+ dmi_id = dmi_first_match(acp_sof_quirk_table);
+ if (dmi_id && dmi_id->driver_data)
+ sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware;
+
+ return 0;
+}
+
+MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_DESCRIPTION("VANGOGH SOF Driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index 69c1a370d3b6..9d0107932117 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -262,6 +262,22 @@ config SND_SOC_SOF_METEORLAKE
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_SOF_INTEL_LNL
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_INTEL_IPC4
+
+config SND_SOC_SOF_LUNARLAKE
+ tristate "SOF support for Lunarlake"
+ default SND_SOC_SOF_PCI
+ select SND_SOC_SOF_INTEL_LNL
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Lunarlake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
config SND_SOC_SOF_HDA_COMMON
tristate
select SND_SOC_SOF_INTEL_COMMON
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index fdb463c12e91..030574dbc998 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -7,7 +7,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
hda-dai.o hda-dai-ops.o hda-bus.o \
skl.o hda-loader-skl.o \
- apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
+ apl.o cnl.o tgl.o icl.o mtl.o lnl.o hda-common-ops.o
snd-sof-intel-hda-mlink-objs := hda-mlink.o
@@ -31,6 +31,7 @@ snd-sof-pci-intel-cnl-objs := pci-cnl.o
snd-sof-pci-intel-icl-objs := pci-icl.o
snd-sof-pci-intel-tgl-objs := pci-tgl.o
snd-sof-pci-intel-mtl-objs := pci-mtl.o
+snd-sof-pci-intel-lnl-objs := pci-lnl.o
obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o
@@ -39,3 +40,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index a95222e53ecf..c6fbf4285262 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -466,6 +466,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
@@ -501,6 +502,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index f33051eac1c0..494ced2b746e 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -7,6 +7,7 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
#include "../ipc4-priv.h"
@@ -144,9 +145,17 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream)
{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *dai;
struct hdac_ext_stream *hext_stream;
- hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+ /* only allocate a stream_tag for the first DAI in the dailink */
+ dai = asoc_rtd_to_cpu(rtd, 0);
+ if (dai == cpu_dai)
+ hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+ else
+ hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+
if (!hext_stream)
return NULL;
@@ -159,9 +168,14 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_dai *dai;
+ /* only release a stream_tag for the first DAI in the dailink */
+ dai = asoc_rtd_to_cpu(rtd, 0);
+ if (dai == cpu_dai)
+ snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
- snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
}
static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
@@ -219,6 +233,77 @@ static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
}
+static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int format_val;
+
+ format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
+ params_format(params),
+ params_physical_width(params),
+ 0);
+
+ dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+ params_rate(params), params_channels(params), params_format(params));
+
+ return format_val;
+}
+
+static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int format_val;
+ snd_pcm_format_t format;
+ unsigned int channels;
+ unsigned int width;
+
+ channels = params_channels(params);
+ format = params_format(params);
+ width = params_physical_width(params);
+
+ if (format == SNDRV_PCM_FORMAT_S16_LE) {
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ channels /= 2;
+ width = 32;
+ }
+
+ format_val = snd_hdac_calc_stream_format(params_rate(params), channels,
+ format,
+ width,
+ 0);
+
+ dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+ params_rate(params), channels, format);
+
+ return format_val;
+}
+
+static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_ssp_get_hlink(bus);
+}
+
+static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_dmic_get_hlink(bus);
+}
+
+static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_sdw_get_hlink(bus);
+}
+
static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
@@ -234,6 +319,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
+ if (pipe_widget->instance_id < 0)
+ return 0;
+
mutex_lock(&ipc4_data->pipeline_state_mutex);
switch (cmd) {
@@ -297,6 +385,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
+ if (pipe_widget->instance_id < 0)
+ return 0;
+
mutex_lock(&ipc4_data->pipeline_state_mutex);
switch (cmd) {
@@ -343,6 +434,28 @@ out:
return ret;
}
+static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
+ struct snd_soc_dai *cpu_dai,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_sof_dai *dai = swidget->private;
+ struct sof_ipc4_copier *ipc4_copier = dai->private;
+ struct sof_ipc4_alh_configuration_blob *blob;
+
+ blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
+
+ /*
+ * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using
+ * the multi-gateway firmware configuration. The DMA hardware can take care of
+ * multiple links without needing any firmware assistance
+ */
+ blob->alh_cfg.device_count = 1;
+
+ return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream);
+}
+
static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
@@ -357,6 +470,45 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.get_hlink = hda_get_hlink,
};
+static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
+ .get_hext_stream = hda_ipc4_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .pre_trigger = hda_ipc4_pre_trigger,
+ .trigger = hda_trigger,
+ .post_trigger = hda_ipc4_post_trigger,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = ssp_get_hlink,
+};
+
+static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
+ .get_hext_stream = hda_ipc4_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .pre_trigger = hda_ipc4_pre_trigger,
+ .trigger = hda_trigger,
+ .post_trigger = hda_ipc4_post_trigger,
+ .calc_stream_format = dmic_calc_stream_format,
+ .get_hlink = dmic_get_hlink,
+};
+
+static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
+ .get_hext_stream = sdw_hda_ipc4_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .pre_trigger = hda_ipc4_pre_trigger,
+ .trigger = hda_trigger,
+ .post_trigger = hda_ipc4_post_trigger,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = sdw_get_hlink,
+};
+
static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.get_hext_stream = hda_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
@@ -468,8 +620,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
case SOF_INTEL_IPC4:
{
struct sof_ipc4_copier *ipc4_copier = sdai->private;
+ const struct sof_intel_dsp_desc *chip;
- if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
+ chip = get_chip_info(sdev->pdata);
+
+ switch (ipc4_copier->dai_type) {
+ case SOF_DAI_INTEL_HDA:
+ {
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
@@ -478,6 +635,22 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
return &hda_ipc4_dma_ops;
}
+ case SOF_DAI_INTEL_SSP:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &ssp_ipc4_dma_ops;
+ case SOF_DAI_INTEL_DMIC:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &dmic_ipc4_dma_ops;
+ case SOF_DAI_INTEL_ALH:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &sdw_ipc4_dma_ops;
+
+ default:
+ break;
+ }
break;
}
default:
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 863865f3d77e..f3cefd866081 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -10,6 +10,8 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
+#include <sound/hda_register.h>
#include <sound/intel-nhlt.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
@@ -329,6 +331,175 @@ static const struct snd_soc_dai_ops hda_dai_ops = {
#endif
+static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
+{
+ struct snd_sof_widget *swidget = w->dobj.private;
+ struct snd_sof_dai *sdai = swidget->private;
+ struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
+
+ return ipc4_copier;
+}
+
+static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct sof_ipc4_dma_config_tlv *dma_config_tlv;
+ const struct hda_dai_widget_dma_ops *ops;
+ struct sof_ipc4_dma_config *dma_config;
+ struct sof_ipc4_copier *ipc4_copier;
+ struct hdac_ext_stream *hext_stream;
+ struct hdac_stream *hstream;
+ struct snd_sof_dev *sdev;
+ int stream_id;
+ int ret;
+
+ ops = hda_dai_get_ops(substream, cpu_dai);
+ if (!ops) {
+ dev_err(cpu_dai->dev, "DAI widget ops not set\n");
+ return -EINVAL;
+ }
+
+ /* use HDaudio stream handling */
+ ret = hda_dai_hw_params(substream, params, cpu_dai);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* get stream_id */
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ if (!hext_stream) {
+ dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
+ return -ENODEV;
+ }
+
+ hstream = &hext_stream->hstream;
+ stream_id = hstream->stream_tag;
+
+ if (!stream_id) {
+ dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
+ return -ENODEV;
+ }
+
+ /* configure TLV */
+ ipc4_copier = widget_to_copier(w);
+
+ dma_config_tlv = &ipc4_copier->dma_config_tlv;
+ dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
+ /* dma_config_priv_size is zero */
+ dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
+
+ dma_config = &dma_config_tlv->dma_config;
+
+ dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
+ dma_config->pre_allocated_by_host = 1;
+ dma_config->dma_channel_id = stream_id - 1;
+ dma_config->stream_id = stream_id;
+ dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
+ dma_config->dma_priv_config_size = 0;
+
+ return 0;
+}
+
+static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ int stream = substream->stream;
+
+ return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
+}
+
+static const struct snd_soc_dai_ops ssp_dai_ops = {
+ .hw_params = non_hda_dai_hw_params,
+ .hw_free = hda_dai_hw_free,
+ .trigger = hda_dai_trigger,
+ .prepare = non_hda_dai_prepare,
+};
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+ .hw_params = non_hda_dai_hw_params,
+ .hw_free = hda_dai_hw_free,
+ .trigger = hda_dai_trigger,
+ .prepare = non_hda_dai_prepare,
+};
+
+int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai,
+ int link_id)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ const struct hda_dai_widget_dma_ops *ops;
+ struct hdac_ext_stream *hext_stream;
+ struct snd_sof_dev *sdev;
+ int ret;
+
+ ret = non_hda_dai_hw_params(substream, params, cpu_dai);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ ops = hda_dai_get_ops(substream, cpu_dai);
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ if (!hext_stream)
+ return -ENODEV;
+
+ /* in the case of SoundWire we need to program the PCMSyCM registers */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ GENMASK(params_channels(params) - 1, 0),
+ hdac_stream(hext_stream)->stream_tag,
+ substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai,
+ int link_id)
+{
+ struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_sof_dev *sdev;
+ int ret;
+
+ ret = hda_dai_hw_free(substream, cpu_dai);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ sdev = widget_to_sdev(w);
+
+ /* in the case of SoundWire we need to reset the PCMSyCM registers */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ 0, 0, substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ return hda_dai_trigger(substream, cmd, cpu_dai);
+}
+
static int hda_dai_suspend(struct hdac_bus *bus)
{
struct snd_soc_pcm_runtime *rtd;
@@ -383,7 +554,42 @@ static int hda_dai_suspend(struct hdac_bus *bus)
return 0;
}
-#endif
+static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+ const struct sof_intel_dsp_desc *chip;
+ int i;
+
+ chip = get_chip_info(sdev->pdata);
+
+ if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+ for (i = 0; i < ops->num_drv; i++) {
+ if (strstr(ops->drv[i].name, "SSP"))
+ ops->drv[i].ops = &ssp_dai_ops;
+ }
+ }
+}
+
+static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+ const struct sof_intel_dsp_desc *chip;
+ int i;
+
+ chip = get_chip_info(sdev->pdata);
+
+ if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+ for (i = 0; i < ops->num_drv; i++) {
+ if (strstr(ops->drv[i].name, "DMIC"))
+ ops->drv[i].ops = &dmic_dai_ops;
+ }
+ }
+}
+
+#else
+
+static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
@@ -398,6 +604,9 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
#endif
}
+ ssp_set_dai_drv_ops(sdev, ops);
+ dmic_set_dai_drv_ops(sdev, ops);
+
if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index b7cbf66badf5..b592e687a87a 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -331,14 +331,19 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask)
return !!(val & cmdsync_mask);
}
-static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num)
+static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid)
{
- u32 val;
+ return readw(lsdiid);
+}
+
+static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num)
+{
+ u16 val;
- val = readl(lsdiid);
+ val = readw(lsdiid);
val |= BIT(dev_num);
- writel(val, lsdiid);
+ writew(val, lsdiid);
}
static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan,
@@ -752,6 +757,22 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink)
}
EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
+int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid)
+{
+ struct hdac_ext2_link *h2link;
+ struct hdac_ext_link *hlink;
+
+ h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
+ if (!h2link)
+ return -ENODEV;
+
+ hlink = &h2link->hext_link;
+
+ *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink));
+
+ return 0;
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK);
+
int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
{
struct hdac_ext2_link *h2link;
@@ -781,6 +802,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
{
struct hdac_ext2_link *h2link;
u16 __iomem *pcmsycm;
+ int hchan;
+ int lchan;
u16 val;
h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
@@ -791,17 +814,25 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
h2link->instance_offset * sublink +
AZX_REG_SDW_SHIM_PCMSyCM(y);
+ if (channel_mask) {
+ hchan = __fls(channel_mask);
+ lchan = __ffs(channel_mask);
+ } else {
+ hchan = 0;
+ lchan = 0;
+ }
+
mutex_lock(&h2link->eml_lock);
- hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask),
+ hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan,
stream_id, dir);
mutex_unlock(&h2link->eml_lock);
val = readw(pcmsycm);
- dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
- channel_mask, stream_id, dir, val);
+ dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
+ sublink, channel_mask, stream_id, dir, val);
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index b13acb959653..0b0087abcc50 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -869,8 +869,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return -ENOMEM;
}
- /* create capture streams */
- for (i = 0; i < num_capture; i++) {
+ /* create capture and playback streams */
+ for (i = 0; i < num_total; i++) {
struct sof_intel_hda_stream *hda_stream;
hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
@@ -909,69 +909,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
hstream->index = i;
sd_offset = SOF_STREAM_SD_OFFSET(hstream);
hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
- hstream->stream_tag = i + 1;
hstream->opened = false;
hstream->running = false;
- hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
- /* memory alloc for stream BDL */
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
- HDA_DSP_BDL_SIZE, &hstream->bdl);
- if (ret < 0) {
- dev_err(sdev->dev, "error: stream bdl dma alloc failed\n");
- return -ENOMEM;
- }
- hstream->posbuf = (__le32 *)(bus->posbuf.area +
- (hstream->index) * 8);
-
- list_add_tail(&hstream->list, &bus->stream_list);
- }
-
- /* create playback streams */
- for (i = num_capture; i < num_total; i++) {
- struct sof_intel_hda_stream *hda_stream;
-
- hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
- GFP_KERNEL);
- if (!hda_stream)
- return -ENOMEM;
-
- hda_stream->sdev = sdev;
-
- hext_stream = &hda_stream->hext_stream;
-
- if (sdev->bar[HDA_DSP_PP_BAR]) {
- hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
- SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
-
- hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
- SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
- SOF_HDA_PPLC_INTERVAL * i;
- }
-
- hstream = &hext_stream->hstream;
-
- /* do we support SPIB */
- if (sdev->bar[HDA_DSP_SPIB_BAR]) {
- hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
- SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
- SOF_HDA_SPIB_SPIB;
-
- hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
- SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
- SOF_HDA_SPIB_MAXFIFO;
+ if (i < num_capture) {
+ hstream->stream_tag = i + 1;
+ hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
+ } else {
+ hstream->stream_tag = i - num_capture + 1;
+ hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
}
- hstream->bus = bus;
- hstream->sd_int_sta_mask = 1 << i;
- hstream->index = i;
- sd_offset = SOF_STREAM_SD_OFFSET(hstream);
- hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
- hstream->stream_tag = i - num_capture + 1;
- hstream->opened = false;
- hstream->running = false;
- hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
-
/* mem alloc for stream BDL */
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
HDA_DSP_BDL_SIZE, &hstream->bdl);
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 64bebe1a72bb..15e6779efaa3 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -71,6 +71,11 @@ static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
break;
+ case SOF_INTEL_ACE_2_0:
+ interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
+ BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
+ interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */
+ break;
default:
break;
}
@@ -107,6 +112,34 @@ struct sdw_intel_ops sdw_callback = {
.params_stream = sdw_params_stream,
};
+static int sdw_ace2x_params_stream(struct device *dev,
+ struct sdw_intel_stream_params_data *params_data)
+{
+ return sdw_hda_dai_hw_params(params_data->substream,
+ params_data->hw_params,
+ params_data->dai,
+ params_data->link_id);
+}
+
+static int sdw_ace2x_free_stream(struct device *dev,
+ struct sdw_intel_stream_free_data *free_data)
+{
+ return sdw_hda_dai_hw_free(free_data->substream,
+ free_data->dai,
+ free_data->link_id);
+}
+
+static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+ return sdw_hda_dai_trigger(substream, cmd, dai);
+}
+
+static struct sdw_intel_ops sdw_ace2x_callback = {
+ .params_stream = sdw_ace2x_params_stream,
+ .free_stream = sdw_ace2x_free_stream,
+ .trigger = sdw_ace2x_trigger,
+};
+
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
struct sof_intel_hda_dev *hdev;
@@ -174,6 +207,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
res.shim_base = hdev->desc->sdw_shim_base;
res.alh_base = hdev->desc->sdw_alh_base;
res.ext = false;
+ res.ops = &sdw_callback;
} else {
/*
* retrieve eml_lock needed to protect shared registers
@@ -191,11 +225,13 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
*/
res.hw_ops = &sdw_intel_lnl_hw_ops;
res.ext = true;
+ res.ops = &sdw_ace2x_callback;
+
}
res.irq = sdev->ipc_irq;
res.handle = hdev->info.handle;
res.parent = sdev->dev;
- res.ops = &sdw_callback;
+
res.dev = sdev->dev;
res.clock_stop_quirks = sdw_clock_stop_quirks;
res.hbus = sof_to_bus(sdev);
@@ -363,14 +399,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
return sdw_intel_thread(irq, context);
}
-static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
{
- u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev;
- if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
- return false;
-
hdev = sdev->pdata->hw_pdata;
if (hdev->sdw &&
snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -380,6 +412,21 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
return false;
}
+static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+{
+ u32 interface_mask = hda_get_interface_mask(sdev);
+ const struct sof_intel_dsp_desc *chip;
+
+ if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
+ return false;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->check_sdw_wakeen_irq)
+ return chip->check_sdw_wakeen_irq(sdev);
+
+ return false;
+}
+
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
@@ -1429,83 +1476,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
-#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
- SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
-
-/* Check if all Slaves defined on the link can be found */
-static bool link_slaves_found(struct snd_sof_dev *sdev,
- const struct snd_soc_acpi_link_adr *link,
- struct sdw_intel_ctx *sdw)
-{
- struct hdac_bus *bus = sof_to_bus(sdev);
- struct sdw_intel_slave_id *ids = sdw->ids;
- int num_slaves = sdw->num_slaves;
- unsigned int part_id, link_id, unique_id, mfg_id, version;
- int i, j, k;
-
- for (i = 0; i < link->num_adr; i++) {
- u64 adr = link->adr_d[i].adr;
- int reported_part_count = 0;
-
- mfg_id = SDW_MFG_ID(adr);
- part_id = SDW_PART_ID(adr);
- link_id = SDW_DISCO_LINK_ID(adr);
- version = SDW_VERSION(adr);
-
- for (j = 0; j < num_slaves; j++) {
- /* find out how many identical parts were reported on that link */
- if (ids[j].link_id == link_id &&
- ids[j].id.part_id == part_id &&
- ids[j].id.mfg_id == mfg_id &&
- ids[j].id.sdw_version == version)
- reported_part_count++;
- }
-
- for (j = 0; j < num_slaves; j++) {
- int expected_part_count = 0;
-
- if (ids[j].link_id != link_id ||
- ids[j].id.part_id != part_id ||
- ids[j].id.mfg_id != mfg_id ||
- ids[j].id.sdw_version != version)
- continue;
-
- /* find out how many identical parts are expected */
- for (k = 0; k < link->num_adr; k++) {
- u64 adr2 = link->adr_d[k].adr;
-
- if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
- expected_part_count++;
- }
-
- if (reported_part_count == expected_part_count) {
- /*
- * we have to check unique id
- * if there is more than one
- * Slave on the link
- */
- unique_id = SDW_UNIQUE_ID(adr);
- if (reported_part_count == 1 ||
- ids[j].id.unique_id == unique_id) {
- dev_dbg(bus->dev, "found %x at link %d\n",
- part_id, link_id);
- break;
- }
- } else {
- dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n",
- part_id, reported_part_count, expected_part_count, link_id);
- }
- }
- if (j == num_slaves) {
- dev_dbg(bus->dev,
- "Slave %x not found\n",
- part_id);
- return false;
- }
- }
- return true;
-}
-
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
@@ -1549,7 +1519,9 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
* Try next machine if any expected Slaves
* are not found on this link.
*/
- if (!link_slaves_found(sdev, link, hdev->sdw))
+ if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
+ hdev->sdw->ids,
+ hdev->sdw->num_slaves))
break;
}
/* Found if all Slaves are checked */
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 5b9e4ebcc18b..5c517ec57d4a 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -785,6 +785,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev);
int hda_sdw_startup(struct snd_sof_dev *sdev);
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
+bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev);
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
@@ -813,6 +814,11 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
}
+static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
+{
+ return false;
+}
+
static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{
}
@@ -824,6 +830,18 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
#endif
+int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai,
+ int link_id);
+
+int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai,
+ int link_id);
+
+int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai);
+
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
@@ -845,6 +863,8 @@ extern struct snd_sof_dsp_ops sof_icl_ops;
int sof_icl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_mtl_ops;
int sof_mtl_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_lnl_ops;
+int sof_lnl_ops_init(struct snd_sof_dev *sdev);
extern const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc apl_chip_info;
@@ -856,6 +876,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info;
extern const struct sof_intel_dsp_desc jsl_chip_info;
extern const struct sof_intel_dsp_desc adls_chip_info;
extern const struct sof_intel_dsp_desc mtl_chip_info;
+extern const struct sof_intel_dsp_desc lnl_chip_info;
/* Probes support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index 0f249efc6a5a..7ac10167a90d 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -188,6 +188,7 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
new file mode 100644
index 000000000000..db94b45e53af
--- /dev/null
+++ b/sound/soc/sof/intel/lnl.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+
+/*
+ * Hardware interface for audio DSP on LunarLake.
+ */
+
+#include <linux/firmware.h>
+#include <sound/hda_register.h>
+#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof_intel.h>
+#include "../ipc4-priv.h"
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+#include "mtl.h"
+#include <sound/hda-mlink.h>
+
+/* LunarLake ops */
+struct snd_sof_dsp_ops sof_lnl_ops;
+EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {
+ {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
+ {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
+/* this helps allows the DSP to setup DMIC/SSP */
+static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus)
+{
+ int ret;
+
+ ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP, true);
+ if (ret < 0)
+ return ret;
+
+ ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hda_dsp_probe(sdev);
+ if (ret < 0)
+ return ret;
+
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+}
+
+static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hda_dsp_resume(sdev);
+ if (ret < 0)
+ return ret;
+
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+}
+
+static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hda_dsp_runtime_resume(sdev);
+ if (ret < 0)
+ return ret;
+
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+}
+
+int sof_lnl_ops_init(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data;
+
+ /* common defaults */
+ memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ /* probe */
+ sof_lnl_ops.probe = lnl_hda_dsp_probe;
+
+ /* shutdown */
+ sof_lnl_ops.shutdown = hda_dsp_shutdown;
+
+ /* doorbell */
+ sof_lnl_ops.irq_thread = mtl_ipc_irq_thread;
+
+ /* ipc */
+ sof_lnl_ops.send_msg = mtl_ipc_send_msg;
+ sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
+ sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
+
+ /* debug */
+ sof_lnl_ops.debug_map = lnl_dsp_debugfs;
+ sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs);
+ sof_lnl_ops.dbg_dump = mtl_dsp_dump;
+ sof_lnl_ops.ipc_dump = mtl_ipc_dump;
+
+ /* pre/post fw run */
+ sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
+ sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run;
+
+ /* parse platform specific extended manifest */
+ sof_lnl_ops.parse_platform_ext_manifest = NULL;
+
+ /* dsp core get/put */
+ /* TODO: add core_get and core_put */
+
+ /* PM */
+ sof_lnl_ops.resume = lnl_hda_dsp_resume;
+ sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
+
+ sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
+
+ sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
+ if (!sdev->private)
+ return -ENOMEM;
+
+ ipc4_data = sdev->private;
+ ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
+
+ ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+
+ /* External library loading support */
+ ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
+ /* set DAI ops */
+ hda_set_dai_drv_ops(sdev, &sof_lnl_ops);
+
+ sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
+
+ return 0;
+};
+EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+/* Check if an SDW IRQ occurred */
+static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
+}
+
+static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+ struct hdac_bus *bus = sof_to_bus(sdev);
+
+ hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable);
+}
+
+static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
+{
+ lnl_enable_sdw_irq(sdev, false);
+ mtl_disable_ipc_interrupts(sdev);
+ return mtl_enable_interrupts(sdev, false);
+}
+
+const struct sof_intel_dsp_desc lnl_chip_info = {
+ .cores_num = 5,
+ .init_core_mask = BIT(0),
+ .host_managed_cores_mask = BIT(0),
+ .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+ .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+ .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+ .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+ .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+ .rom_status_reg = MTL_DSP_ROM_STS,
+ .rom_init_timeout = 300,
+ .ssp_count = MTL_SSP_COUNT,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_ext,
+ .enable_sdw_irq = lnl_enable_sdw_irq,
+ .check_sdw_irq = lnl_dsp_check_sdw_irq,
+ .check_ipc_irq = mtl_dsp_check_ipc_irq,
+ .cl_init = mtl_dsp_cl_init,
+ .power_down_dsp = mtl_power_down_dsp,
+ .disable_interrupts = lnl_dsp_disable_interrupts,
+ .hw_ip_version = SOF_INTEL_ACE_2_0,
+};
+EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 30fe77fd87bf..b84ca58da9d5 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -91,7 +91,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
return false;
}
-static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
@@ -230,7 +230,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
}
/* pre fw run operations */
-static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
+int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
u32 dsphfpwrsts;
@@ -279,7 +279,7 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
return ret;
}
-static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
int ret;
@@ -301,7 +301,7 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
return 0;
}
-static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
u32 romdbgsts;
@@ -495,7 +495,7 @@ err:
return ret;
}
-static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
+irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
@@ -578,17 +578,17 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
+int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MTL_DSP_MBOX_UPLINK_OFFSET;
}
-static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MTL_SRAM_WINDOW_OFFSET(id);
}
-static void mtl_ipc_dump(struct snd_sof_dev *sdev)
+void mtl_ipc_dump(struct snd_sof_dev *sdev)
{
u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;
@@ -612,9 +612,9 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return mtl_enable_interrupts(sdev, false);
}
-static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
- struct snd_soc_component *component,
- struct snd_pcm_substream *substream)
+u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
u32 llp_l, llp_u;
@@ -735,6 +735,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = mtl_enable_sdw_irq,
.check_sdw_irq = mtl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = mtl_dsp_check_ipc_irq,
.cl_init = mtl_dsp_cl_init,
.power_down_dsp = mtl_power_down_dsp,
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index 2794fe6e8139..02181490f12a 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -82,10 +82,28 @@
#define MTL_DSP_REG_HfIMRIS1 0x162088
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)
+bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
+int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
+
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
-bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
-int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
+
+int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev);
+int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev);
+void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
+
int mtl_power_down_dsp(struct snd_sof_dev *sdev);
+int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
+
+irqreturn_t mtl_ipc_irq_thread(int irq, void *context);
+
+int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
+int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
+
+void mtl_ipc_dump(struct snd_sof_dev *sdev);
+
+u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
+ struct snd_soc_component *component,
+ struct snd_pcm_substream *substream);
diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c
new file mode 100644
index 000000000000..1b12c280edb4
--- /dev/null
+++ b/sound/soc/sof/intel/pci-lnl.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+//
+// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.h"
+#include "mtl.h"
+
+static const struct sof_dev_desc lnl_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_lnl_machines,
+ .alt_machines = snd_soc_acpi_intel_lnl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &lnl_chip_info,
+ .ipc_supported_mask = BIT(SOF_INTEL_IPC4),
+ .ipc_default = SOF_INTEL_IPC4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_INTEL_IPC4] = "intel/sof-ipc4/lnl",
+ },
+ .default_tplg_path = {
+ [SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_INTEL_IPC4] = "sof-lnl.ri",
+ },
+ .nocodec_tplg_filename = "sof-lnl-nocodec.tplg",
+ .ops = &sof_lnl_ops,
+ .ops_init = sof_lnl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_lnl_driver = {
+ .name = "sof-audio-pci-intel-lnl",
+ .id_table = sof_pci_ids,
+ .probe = hda_pci_intel_probe,
+ .remove = sof_pci_remove,
+ .shutdown = sof_pci_shutdown,
+ .driver = {
+ .pm = &sof_pci_pm,
+ },
+};
+module_pci_driver(snd_sof_pci_intel_lnl_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index 207df48e27cf..9515d753c816 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -189,6 +189,7 @@ struct sof_intel_dsp_desc {
int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
+ bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev);
bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
int (*power_down_dsp)(struct snd_sof_dev *sdev);
int (*disable_interrupts)(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 8e2b07e1612b..bb9f20253c99 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -147,6 +147,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
@@ -175,6 +176,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
@@ -203,6 +205,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
@@ -231,6 +234,7 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = hda_common_enable_sdw_irq,
.check_sdw_irq = hda_common_check_sdw_irq,
+ .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c
index 35da85a45a9a..bd07f0472efd 100644
--- a/sound/soc/sof/ipc3-dtrace.c
+++ b/sound/soc/sof/ipc3-dtrace.c
@@ -196,15 +196,9 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user
return -EINVAL;
}
- string = kmalloc(count + 1, GFP_KERNEL);
- if (!string)
- return -ENOMEM;
-
- if (copy_from_user(string, from, count)) {
- ret = -EFAULT;
- goto error;
- }
- string[count] = '\0';
+ string = memdup_user_nul(from, count);
+ if (IS_ERR(string))
+ return PTR_ERR(string);
ret = trace_filter_parse(sdev, string, &num_elems, &elems);
if (ret < 0)
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 304faf6425ab..cb58ee8c158a 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -309,6 +309,23 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = private->dai_config->afe.channels;
channels->max = private->dai_config->afe.channels;
+ snd_mask_none(fmt);
+
+ switch (private->dai_config->afe.format) {
+ case SOF_IPC_FRAME_S16_LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ break;
+ case SOF_IPC_FRAME_S24_4LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ break;
+ case SOF_IPC_FRAME_S32_LE:
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+ break;
+ default:
+ dev_err(component->dev, "Not available format!\n");
+ return -EINVAL;
+ }
+
dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
channels->min, channels->max);
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index 580960ff273d..fb40378ad084 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -312,7 +312,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
} else {
if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
- if (msg->reply_size)
+ if (reply_data && msg->reply_size)
/* copy the data returned from DSP */
memcpy(reply_data, msg->reply_data,
msg->reply_size);
@@ -567,13 +567,10 @@ int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
/* create read-only cc_version debugfs to store compiler version info */
/* use local copy of the cc_version to prevent data corruption */
if (sdev->first_boot) {
- sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
- GFP_KERNEL);
-
+ sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL);
if (!sdev->cc_version)
return -ENOMEM;
- memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
cc->ext_hdr.hdr.size,
"cc_version", 0444);
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 027416eb2f50..db19cd03ecad 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -23,7 +23,8 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
/* trigger a single pipeline */
if (trigger_list->count == 1)
- return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state);
+ return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
+ state);
primary = state;
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
@@ -42,15 +43,15 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size);
}
-int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state)
{
struct sof_ipc4_msg msg = {{ 0 }};
u32 primary;
- dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
+ dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state);
primary = state;
- primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
+ primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id);
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -79,19 +80,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
* for the first time
*/
if (spipe->started_count == spipe->paused_count)
- trigger_list->pipeline_ids[trigger_list->count++] =
+ trigger_list->pipeline_instance_ids[trigger_list->count++] =
pipe_widget->instance_id;
break;
case SOF_IPC4_PIPE_RESET:
/* RESET if the pipeline is neither running nor paused */
if (!spipe->started_count && !spipe->paused_count)
- trigger_list->pipeline_ids[trigger_list->count++] =
+ trigger_list->pipeline_instance_ids[trigger_list->count++] =
pipe_widget->instance_id;
break;
case SOF_IPC4_PIPE_PAUSED:
/* Pause the pipeline only when its started_count is 1 more than paused_count */
if (spipe->paused_count == (spipe->started_count - 1))
- trigger_list->pipeline_ids[trigger_list->count++] =
+ trigger_list->pipeline_instance_ids[trigger_list->count++] =
pipe_widget->instance_id;
break;
default:
@@ -113,7 +114,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
/* set state for pipeline if it was just triggered */
for (i = 0; i < trigger_list->count; i++) {
- if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) {
+ if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) {
pipeline->state = state;
break;
}
@@ -314,8 +315,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
/* allocate memory for the pipeline data */
- trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
- GFP_KERNEL);
+ trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
+ pipeline_list->count), GFP_KERNEL);
if (!trigger_list)
return -ENOMEM;
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 11361e1cd688..f2a30cd31378 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -17,6 +17,19 @@
#include "ipc4-topology.h"
#include "ops.h"
+/*
+ * The ignore_cpc flag can be used to ignore the CPC value for all modules by
+ * using 0 instead.
+ * The CPC is sent to the firmware along with the SOF_IPC4_MOD_INIT_INSTANCE
+ * message and it is used for clock scaling.
+ * 0 as CPC value will instruct the firmware to use maximum frequency, thus
+ * deactivating the clock scaling.
+ */
+static bool ignore_cpc;
+module_param_named(ipc4_ignore_cpc, ignore_cpc, bool, 0444);
+MODULE_PARM_DESC(ipc4_ignore_cpc,
+ "Ignore CPC values. This option will disable clock scaling in firmware.");
+
#define SOF_IPC4_GAIN_PARAM_ID 0
#define SOF_IPC4_TPLG_ABI_SIZE 6
#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
@@ -970,9 +983,16 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *
/* Update base_config->cpc from the module manifest */
sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
- dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
- swidget->widget->name, base_config->ibs, base_config->obs,
- base_config->cpc);
+ if (ignore_cpc) {
+ dev_dbg(sdev->dev, "%s: ibs / obs: %u / %u, forcing cpc to 0 from %u\n",
+ swidget->widget->name, base_config->ibs, base_config->obs,
+ base_config->cpc);
+ base_config->cpc = 0;
+ } else {
+ dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
+ swidget->widget->name, base_config->ibs, base_config->obs,
+ base_config->cpc);
+ }
}
static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
@@ -1349,23 +1369,29 @@ static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_s
}
#endif
-static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth)
+static bool sof_ipc4_copier_is_single_format(struct snd_sof_dev *sdev,
+ struct sof_ipc4_pin_format *pin_fmts,
+ u32 pin_fmts_size)
{
- switch (bit_depth) {
- case 16:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
- break;
- case 24:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- break;
- case 32:
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
- break;
- default:
- return -EINVAL;
+ struct sof_ipc4_audio_format *fmt;
+ u32 valid_bits;
+ int i;
+
+ fmt = &pin_fmts[0].audio_fmt;
+ valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ /* check if all output formats in topology are the same */
+ for (i = 1; i < pin_fmts_size; i++) {
+ u32 _valid_bits;
+
+ fmt = &pin_fmts[i].audio_fmt;
+ _valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ if (_valid_bits != valid_bits)
+ return false;
}
- return 0;
+ return true;
}
static int
@@ -1381,8 +1407,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_pcm_hw_params *ref_params;
struct sof_ipc4_copier *ipc4_copier;
struct snd_sof_dai *dai;
- struct snd_mask *fmt;
- int out_sample_valid_bits;
u32 gtw_cfg_config_length;
u32 dma_config_tlv_size = 0;
void **ipc_config_data;
@@ -1392,6 +1416,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
u32 out_ref_rate, out_ref_channels;
u32 deep_buffer_dma_ms = 0;
int output_fmt_index;
+ bool single_output_format;
dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
@@ -1525,6 +1550,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
return ret;
/* set the reference params for output format selection */
+ single_output_format = sof_ipc4_copier_is_single_format(sdev,
+ available_fmt->output_pin_fmts,
+ available_fmt->num_output_formats);
switch (swidget->id) {
case snd_soc_dapm_aif_in:
case snd_soc_dapm_dai_out:
@@ -1535,17 +1563,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
out_ref_rate = in_fmt->sampling_frequency;
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+
+ if (!single_output_format)
+ out_ref_valid_bits =
+ SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
break;
}
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai_in:
- out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
- if (out_ref_valid_bits < 0)
- return out_ref_valid_bits;
-
out_ref_rate = params_rate(fe_params);
out_ref_channels = params_channels(fe_params);
+ if (!single_output_format) {
+ out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
+ if (out_ref_valid_bits < 0)
+ return out_ref_valid_bits;
+ }
break;
default:
/*
@@ -1555,6 +1587,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
return -EINVAL;
}
+ /*
+ * if the output format is the same across all available output formats, choose
+ * that as the reference.
+ */
+ if (single_output_format) {
+ struct sof_ipc4_audio_format *out_fmt;
+
+ out_fmt = &available_fmt->output_pin_fmts[0].audio_fmt;
+ out_ref_valid_bits =
+ SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg);
+ }
+
+ dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n",
+ swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits);
+
output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config,
available_fmt, out_ref_rate,
out_ref_channels, out_ref_valid_bits);
@@ -1664,11 +1711,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
}
/* modify the input params for the next widget */
- fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
- out_sample_valid_bits =
- SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
- snd_mask_none(fmt);
- ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits);
+ ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &copier_data->out_format);
if (ret)
return ret;
@@ -1746,6 +1789,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
gtw_cfg_config_length,
&ipc4_copier->dma_config_tlv, dma_config_tlv_size);
+ /*
+ * Restore gateway config length now that IPC payload is prepared. This avoids
+ * counting the DMA CONFIG TLV multiple times
+ */
+ copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
+
return 0;
}
@@ -1832,37 +1881,58 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_src *src = swidget->private;
struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt;
- struct sof_ipc4_audio_format *in_fmt;
+ struct sof_ipc4_audio_format *out_audio_fmt;
+ struct sof_ipc4_audio_format *in_audio_fmt;
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
- struct snd_interval *rate;
- int ret;
+ int output_format_index, input_format_index;
- ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
- pipeline_params, available_fmt);
- if (ret < 0)
- return ret;
+ input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
+ pipeline_params, available_fmt);
+ if (input_format_index < 0)
+ return input_format_index;
- in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
+ /*
+ * For playback, the SRC sink rate will be configured based on the requested output
+ * format, which is restricted to only deal with DAI's with a single format for now.
+ */
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK && available_fmt->num_output_formats > 1) {
+ dev_err(sdev->dev, "Invalid number of output formats: %d for SRC %s\n",
+ available_fmt->num_output_formats, swidget->widget->name);
+ return -EINVAL;
+ }
- ret = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config, available_fmt,
- out_ref_rate, out_ref_channels, out_ref_valid_bits);
- if (ret < 0) {
+ /*
+ * SRC does not perform format conversion, so the output channels and valid bit depth must
+ * be the same as that of the input.
+ */
+ in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt;
+ out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg);
+ out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg);
+
+ /*
+ * For capture, the SRC module should convert the rate to match the rate requested by the
+ * PCM hw_params. Set the reference params based on the fe_params unconditionally as it
+ * will be ignored for playback anyway.
+ */
+ out_ref_rate = params_rate(fe_params);
+
+ output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config,
+ available_fmt, out_ref_rate,
+ out_ref_channels, out_ref_valid_bits);
+ if (output_format_index < 0) {
dev_err(sdev->dev, "Failed to initialize output format for %s",
swidget->widget->name);
+ return output_format_index;
}
/* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config);
- /* update pipeline_params for sink widgets */
- rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
- rate->min = src->sink_rate;
- rate->max = rate->min;
+ out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt;
+ src->sink_rate = out_audio_fmt->sampling_frequency;
- return 0;
+ /* update pipeline_params for sink widgets */
+ return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt);
}
static int
@@ -2319,6 +2389,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
pipeline->mem_usage = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
ida_free(&pipeline_ida, swidget->instance_id);
+ swidget->instance_id = -EINVAL;
} else {
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 6dcf14886e85..d75f17f4749c 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -144,11 +144,11 @@ struct sof_ipc4_pipeline {
/**
* struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data
* @count: Number of pipelines to be triggered
- * @pipeline_ids: Flexible array of IDs of the pipelines to be triggered
+ * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered
*/
struct ipc4_pipeline_set_state_data {
u32 count;
- DECLARE_FLEX_ARRAY(u32, pipeline_ids);
+ DECLARE_FLEX_ARRAY(u32, pipeline_instance_ids);
} __packed;
/**
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index 3e0ea0e109e2..f587edf9e0a7 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -111,6 +111,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
dev_dbg(dev, "DMA %pR\n", &res);
+ adsp->pa_shared_dram = (phys_addr_t)res.start;
+ adsp->shared_size = resource_size(&res);
+ if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
+ dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
+ (u32)adsp->pa_shared_dram);
+ return -EINVAL;
+ }
+
ret = of_reserved_mem_device_init(dev);
if (ret) {
dev_err(dev, "of_reserved_mem_device_init failed\n");
@@ -244,23 +252,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
{
struct device *dev = &pdev->dev;
struct mtk_adsp_chip_info *adsp = data;
- u32 shared_size;
/* remap shared-dram base to be non-cachable */
- shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL;
- adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size;
- if (adsp->va_dram) {
- adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size;
- } else {
- adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
- shared_size);
- if (!adsp->shared_dram) {
- dev_err(dev, "ioremap failed for shared DRAM\n");
- return -ENOMEM;
- }
+ adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
+ adsp->shared_size);
+ if (!adsp->shared_dram) {
+ dev_err(dev, "failed to ioremap base %pa size %#x\n",
+ adsp->shared_dram, adsp->shared_size);
+ return -ENOMEM;
}
- dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
- adsp->shared_dram, &adsp->pa_shared_dram, shared_size);
+
+ dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
+ adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
return 0;
}
@@ -307,9 +310,12 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
return -ENOMEM;
}
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev,
- priv->adsp->pa_dram,
- priv->adsp->dramsize);
+ priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM];
+
+ sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev,
+ priv->adsp->pa_dram,
+ priv->adsp->dramsize);
+
if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
&priv->adsp->pa_dram, priv->adsp->dramsize);
diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c
index ea21ef176c42..c56a85854d92 100644
--- a/sound/soc/sof/sof-client-probes-ipc4.c
+++ b/sound/soc/sof/sof-client-probes-ipc4.c
@@ -146,6 +146,9 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev)
struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
struct sof_ipc4_msg msg;
+ if (!mentry)
+ return -ENODEV;
+
msg.primary = mentry->id;
msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE);
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
@@ -197,6 +200,9 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev,
struct sof_ipc4_msg msg;
int i, ret;
+ if (!mentry)
+ return -ENODEV;
+
/* The sof_probe_point_desc and sof_ipc4_probe_point structs
* are of same size and even the integers are the same in the
* same order, and similar meaning, but since there is no
@@ -247,6 +253,9 @@ static int ipc4_probes_points_remove(struct sof_client_dev *cdev,
u32 *probe_point_ids;
int i, ret;
+ if (!mentry)
+ return -ENODEV;
+
probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids),
GFP_KERNEL);
if (!probe_point_ids)
diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
index 5530b5d793d0..740b637822db 100644
--- a/sound/soc/sof/sof-client-probes.c
+++ b/sound/soc/sof/sof-client-probes.c
@@ -354,10 +354,14 @@ static const struct file_operations sof_probes_points_remove_fops = {
.owner = THIS_MODULE,
};
+static const struct snd_soc_dai_ops sof_probes_dai_ops = {
+ .compress_new = snd_soc_new_compress,
+};
+
static struct snd_soc_dai_driver sof_probes_dai_drv[] = {
{
.name = "Probe Extraction CPU DAI",
- .compress_new = snd_soc_new_compress,
+ .ops = &sof_probes_dai_ops,
.cops = &sof_probes_compr_ops,
.capture = {
.stream_name = "Probe Extraction",
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 698129dccc7d..a3a3af252259 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1117,10 +1117,11 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
{
struct snd_soc_card *card = scomp->card;
struct snd_soc_pcm_runtime *rtd;
+ const char *sname = w->sname;
struct snd_soc_dai *cpu_dai;
int i, stream;
- if (!w->sname)
+ if (!sname)
return;
if (w->id == snd_soc_dapm_dai_out)
@@ -1133,7 +1134,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
list_for_each_entry(rtd, &card->rtd_list, list) {
/* does stream match DAI link ? */
if (!rtd->dai_link->stream_name ||
- strcmp(w->sname, rtd->dai_link->stream_name))
+ strcmp(sname, rtd->dai_link->stream_name))
continue;
for_each_rtd_cpu_dais(rtd, i, cpu_dai)
@@ -1366,6 +1367,20 @@ err:
return ret;
}
+static int get_w_no_wname_in_long_name(void *elem, void *object, u32 offset)
+{
+ struct snd_soc_tplg_vendor_value_elem *velem = elem;
+ struct snd_soc_dapm_widget *w = object;
+
+ w->no_wname_in_kcontrol_name = !!le32_to_cpu(velem->value);
+ return 0;
+}
+
+static const struct sof_topology_token dapm_widget_tokens[] = {
+ {SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME, SND_SOC_TPLG_TUPLE_TYPE_BOOL,
+ get_w_no_wname_in_long_name, 0}
+};
+
/* external widget init - used for any driver specific init */
static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_dapm_widget *w,
@@ -1396,6 +1411,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
ida_init(&swidget->output_queue_ida);
ida_init(&swidget->input_queue_ida);
+ ret = sof_parse_tokens(scomp, w, dapm_widget_tokens, ARRAY_SIZE(dapm_widget_tokens),
+ priv->array, le32_to_cpu(priv->size));
+ if (ret < 0) {
+ dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n",
+ w->name);
+ goto widget_free;
+ }
+
ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens,
ARRAY_SIZE(comp_pin_tokens), priv->array,
le32_to_cpu(priv->size));
@@ -2157,6 +2180,8 @@ static int sof_complete(struct snd_soc_component *scomp)
struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
struct snd_sof_widget *swidget;
+ pipe_widget->instance_id = -EINVAL;
+
/* Update the scheduler widget's IPC structure */
if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) {
ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget);
diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c
index 705f1420097b..8c117794b028 100644
--- a/sound/soc/starfive/jh7110_tdm.c
+++ b/sound/soc/starfive/jh7110_tdm.c
@@ -463,13 +463,6 @@ static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return 0;
}
-static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = {
- .startup = jh7110_tdm_startup,
- .hw_params = jh7110_tdm_hw_params,
- .trigger = jh7110_tdm_trigger,
- .set_fmt = jh7110_tdm_set_dai_fmt,
-};
-
static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai)
{
struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
@@ -479,6 +472,14 @@ static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = {
+ .probe = jh7110_tdm_dai_probe,
+ .startup = jh7110_tdm_startup,
+ .hw_params = jh7110_tdm_hw_params,
+ .trigger = jh7110_tdm_trigger,
+ .set_fmt = jh7110_tdm_set_dai_fmt,
+};
+
#define JH7110_TDM_RATES SNDRV_PCM_RATE_8000_48000
#define JH7110_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -502,7 +503,6 @@ static struct snd_soc_dai_driver jh7110_tdm_dai = {
.formats = JH7110_TDM_FORMATS,
},
.ops = &jh7110_tdm_dai_ops,
- .probe = jh7110_tdm_dai_probe,
.symmetric_rate = 1,
};
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c
index a4d74d1e3c24..2c21a86421e6 100644
--- a/sound/soc/sti/sti_uniperif.c
+++ b/sound/soc/sti/sti_uniperif.c
@@ -369,10 +369,14 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai)
return sti_uniperiph_dai_create_ctrl(dai);
}
-static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
+static const struct snd_soc_dai_ops sti_uniperiph_dai_ops = {
.probe = sti_uniperiph_dai_probe,
};
+static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
+ .ops = &sti_uniperiph_dai_ops,
+};
+
static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
.name = "sti_cpu_dai",
.suspend = sti_uniperiph_suspend,
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 387130701960..06a42130f5e4 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -953,6 +953,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = {
};
static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = {
+ .probe = stm32_i2s_dai_probe,
.set_sysclk = stm32_i2s_set_sysclk,
.set_fmt = stm32_i2s_set_dai_fmt,
.startup = stm32_i2s_startup,
@@ -1002,7 +1003,6 @@ static int stm32_i2s_dais_init(struct platform_device *pdev,
if (!dai_ptr)
return -ENOMEM;
- dai_ptr->probe = stm32_i2s_dai_probe;
dai_ptr->ops = &stm32_i2s_pcm_dai_ops;
dai_ptr->id = 1;
stm32_i2s_dai_init(&dai_ptr->playback, "playback");
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 39f9b4654fa2..f9b5d5969155 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1222,6 +1222,19 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
}
static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
+ .probe = stm32_sai_dai_probe,
+ .set_sysclk = stm32_sai_set_sysclk,
+ .set_fmt = stm32_sai_set_dai_fmt,
+ .set_tdm_slot = stm32_sai_set_dai_tdm_slot,
+ .startup = stm32_sai_startup,
+ .hw_params = stm32_sai_hw_params,
+ .trigger = stm32_sai_trigger,
+ .shutdown = stm32_sai_shutdown,
+ .pcm_new = stm32_sai_pcm_new,
+};
+
+static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = {
+ .probe = stm32_sai_dai_probe,
.set_sysclk = stm32_sai_set_sysclk,
.set_fmt = stm32_sai_set_dai_fmt,
.set_tdm_slot = stm32_sai_set_dai_tdm_slot,
@@ -1287,8 +1300,6 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
};
static struct snd_soc_dai_driver stm32_sai_playback_dai = {
- .probe = stm32_sai_dai_probe,
- .pcm_new = stm32_sai_pcm_new,
.id = 1, /* avoid call to fmt_single_name() */
.playback = {
.channels_min = 1,
@@ -1306,7 +1317,6 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = {
};
static struct snd_soc_dai_driver stm32_sai_capture_dai = {
- .probe = stm32_sai_dai_probe,
.id = 1, /* avoid call to fmt_single_name() */
.capture = {
.channels_min = 1,
@@ -1320,7 +1330,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = {
SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE,
},
- .ops = &stm32_sai_pcm_dai_ops,
+ .ops = &stm32_sai_pcm_dai_ops2,
};
static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index a4066f271f2d..a359b528b26b 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -856,6 +856,7 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = {
+ .probe = stm32_spdifrx_dai_probe,
.startup = stm32_spdifrx_startup,
.hw_params = stm32_spdifrx_hw_params,
.trigger = stm32_spdifrx_trigger,
@@ -864,7 +865,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = {
static struct snd_soc_dai_driver stm32_spdifrx_dai[] = {
{
- .probe = stm32_spdifrx_dai_probe,
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 55328850aef5..f0a5fd901101 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -1252,9 +1252,12 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops dummy_dai_ops = {
+ .probe = sun4i_codec_dai_probe,
+};
+
static struct snd_soc_dai_driver dummy_cpu_dai = {
.name = "sun4i-codec-cpu-dai",
- .probe = sun4i_codec_dai_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 1,
@@ -1271,6 +1274,7 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
.formats = SUN4I_CODEC_FORMATS,
.sig_bits = 24,
},
+ .ops = &dummy_dai_ops,
};
static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 669d712bbe9f..5124b6c9ceb4 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1081,14 +1081,6 @@ static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
-static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
- .hw_params = sun4i_i2s_hw_params,
- .set_fmt = sun4i_i2s_set_fmt,
- .set_sysclk = sun4i_i2s_set_sysclk,
- .set_tdm_slot = sun4i_i2s_set_tdm_slot,
- .trigger = sun4i_i2s_trigger,
-};
-
static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -1100,12 +1092,20 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
+ .probe = sun4i_i2s_dai_probe,
+ .hw_params = sun4i_i2s_hw_params,
+ .set_fmt = sun4i_i2s_set_fmt,
+ .set_sysclk = sun4i_i2s_set_sysclk,
+ .set_tdm_slot = sun4i_i2s_set_tdm_slot,
+ .trigger = sun4i_i2s_trigger,
+};
+
#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
static struct snd_soc_dai_driver sun4i_i2s_dai = {
- .probe = sun4i_i2s_dai_probe,
.capture = {
.stream_name = "Capture",
.channels_min = 1,
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index ff18d4113aac..b849bb7cf58e 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -508,6 +508,7 @@ static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
+ .probe = sun4i_spdif_soc_dai_probe,
.startup = sun4i_spdif_startup,
.trigger = sun4i_spdif_trigger,
.hw_params = sun4i_spdif_hw_params,
@@ -533,7 +534,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
.rates = SUN4I_RATES,
.formats = SUN4I_FORMATS,
},
- .probe = sun4i_spdif_soc_dai_probe,
.ops = &sun4i_spdif_dai_ops,
.name = "spdif",
};
@@ -718,7 +718,7 @@ static const struct dev_pm_ops sun4i_spdif_pm = {
static struct platform_driver sun4i_spdif_driver = {
.driver = {
.name = "sun4i-spdif",
- .of_match_table = of_match_ptr(sun4i_spdif_of_match),
+ .of_match_table = sun4i_spdif_of_match,
.pm = &sun4i_spdif_pm,
},
.probe = sun4i_spdif_probe,
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
index c10439b9e0a2..2599683a582d 100644
--- a/sound/soc/sunxi/sun50i-dmic.c
+++ b/sound/soc/sunxi/sun50i-dmic.c
@@ -236,6 +236,7 @@ static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = {
+ .probe = sun50i_dmic_soc_dai_probe,
.startup = sun50i_dmic_startup,
.trigger = sun50i_dmic_trigger,
.hw_params = sun50i_dmic_hw_params,
@@ -260,7 +261,6 @@ static struct snd_soc_dai_driver sun50i_dmic_dai = {
.formats = SUN50I_DMIC_FORMATS,
.sig_bits = 21,
},
- .probe = sun50i_dmic_soc_dai_probe,
.ops = &sun50i_dmic_dai_ops,
.name = "dmic",
};
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 60e7df41c64c..e713feca25fa 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -203,10 +203,6 @@ static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
- .trigger = tegra20_ac97_trigger,
-};
-
static int tegra20_ac97_probe(struct snd_soc_dai *dai)
{
struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
@@ -217,9 +213,13 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
+ .probe = tegra20_ac97_probe,
+ .trigger = tegra20_ac97_trigger,
+};
+
static struct snd_soc_dai_driver tegra20_ac97_dai = {
.name = "tegra-ac97-pcm",
- .probe = tegra20_ac97_probe,
.playback = {
.stream_name = "PCM Playback",
.channels_min = 2,
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index d38b58305c6b..f11618e8f13e 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -310,6 +310,7 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
+ .probe = tegra20_i2s_probe,
.set_fmt = tegra20_i2s_set_fmt,
.hw_params = tegra20_i2s_hw_params,
.trigger = tegra20_i2s_trigger,
@@ -317,7 +318,6 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
};
static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
- .probe = tegra20_i2s_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index d034803695a0..b0670aa4d967 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -241,6 +241,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
+ .probe = tegra20_spdif_probe,
.hw_params = tegra20_spdif_hw_params,
.trigger = tegra20_spdif_trigger,
.startup = tegra20_spdif_startup,
@@ -248,7 +249,6 @@ static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
static struct snd_soc_dai_driver tegra20_spdif_dai = {
.name = "tegra20-spdif",
- .probe = tegra20_spdif_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
index 6868508585a0..9f9334e48049 100644
--- a/sound/soc/tegra/tegra210_admaif.c
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -419,11 +419,6 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
}
}
-static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
- .hw_params = tegra_admaif_hw_params,
- .trigger = tegra_admaif_trigger,
-};
-
static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -550,10 +545,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+ .probe = tegra_admaif_dai_probe,
+ .hw_params = tegra_admaif_hw_params,
+ .trigger = tegra_admaif_trigger,
+};
+
#define DAI(dai_name) \
{ \
.name = dai_name, \
- .probe = tegra_admaif_dai_probe, \
.playback = { \
.stream_name = dai_name " Playback", \
.channels_min = 1, \
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 644280603095..81eaece51130 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -304,6 +304,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
+ .probe = tegra30_i2s_probe,
.set_fmt = tegra30_i2s_set_fmt,
.hw_params = tegra30_i2s_hw_params,
.trigger = tegra30_i2s_trigger,
@@ -311,7 +312,6 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
};
static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
- .probe = tegra30_i2s_probe,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index 983d69b951b0..544cb3da50eb 100644
--- a/sound/soc/ti/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -257,18 +257,7 @@ static struct platform_driver davinci_evm_driver = {
},
};
-static int __init evm_init(void)
-{
- return platform_driver_register(&davinci_evm_driver);
-}
-
-static void __exit evm_exit(void)
-{
- platform_driver_unregister(&davinci_evm_driver);
-}
-
-module_init(evm_init);
-module_exit(evm_exit);
+module_platform_driver(davinci_evm_driver);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index 97dd1634b6be..07c8b2259208 100644
--- a/sound/soc/ti/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
@@ -601,16 +601,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
#define DAVINCI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
-static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
- .shutdown = davinci_i2s_shutdown,
- .prepare = davinci_i2s_prepare,
- .trigger = davinci_i2s_trigger,
- .hw_params = davinci_i2s_hw_params,
- .set_fmt = davinci_i2s_set_dai_fmt,
- .set_clkdiv = davinci_i2s_dai_set_clkdiv,
-
-};
-
static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -622,8 +612,18 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+ .probe = davinci_i2s_dai_probe,
+ .shutdown = davinci_i2s_shutdown,
+ .prepare = davinci_i2s_prepare,
+ .trigger = davinci_i2s_trigger,
+ .hw_params = davinci_i2s_hw_params,
+ .set_fmt = davinci_i2s_set_dai_fmt,
+ .set_clkdiv = davinci_i2s_dai_set_clkdiv,
+
+};
+
static struct snd_soc_dai_driver davinci_i2s_dai = {
- .probe = davinci_i2s_dai_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index 172fea764a31..7e7d665a5504 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -1616,18 +1616,6 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
}
}
-static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
- .startup = davinci_mcasp_startup,
- .shutdown = davinci_mcasp_shutdown,
- .trigger = davinci_mcasp_trigger,
- .delay = davinci_mcasp_delay,
- .hw_params = davinci_mcasp_hw_params,
- .set_fmt = davinci_mcasp_set_dai_fmt,
- .set_clkdiv = davinci_mcasp_set_clkdiv,
- .set_sysclk = davinci_mcasp_set_sysclk,
- .set_tdm_slot = davinci_mcasp_set_tdm_slot,
-};
-
static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1716,6 +1704,19 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+ .probe = davinci_mcasp_dai_probe,
+ .startup = davinci_mcasp_startup,
+ .shutdown = davinci_mcasp_shutdown,
+ .trigger = davinci_mcasp_trigger,
+ .delay = davinci_mcasp_delay,
+ .hw_params = davinci_mcasp_hw_params,
+ .set_fmt = davinci_mcasp_set_dai_fmt,
+ .set_clkdiv = davinci_mcasp_set_clkdiv,
+ .set_sysclk = davinci_mcasp_set_sysclk,
+ .set_tdm_slot = davinci_mcasp_set_tdm_slot,
+};
+
#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -1732,7 +1733,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
{
.name = "davinci-mcasp.0",
- .probe = davinci_mcasp_dai_probe,
.playback = {
.stream_name = "IIS Playback",
.channels_min = 1,
@@ -1753,7 +1753,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
},
{
.name = "davinci-mcasp.1",
- .probe = davinci_mcasp_dai_probe,
.playback = {
.stream_name = "DIT Playback",
.channels_min = 1,
diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c
index cb60af36dbc3..5b5eccf303ab 100644
--- a/sound/soc/ti/omap-dmic.c
+++ b/sound/soc/ti/omap-dmic.c
@@ -401,15 +401,6 @@ static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return -EINVAL;
}
-static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
- .startup = omap_dmic_dai_startup,
- .shutdown = omap_dmic_dai_shutdown,
- .hw_params = omap_dmic_dai_hw_params,
- .prepare = omap_dmic_dai_prepare,
- .trigger = omap_dmic_dai_trigger,
- .set_sysclk = omap_dmic_set_dai_sysclk,
-};
-
static int omap_dmic_probe(struct snd_soc_dai *dai)
{
struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
@@ -438,10 +429,19 @@ static int omap_dmic_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
+ .probe = omap_dmic_probe,
+ .remove = omap_dmic_remove,
+ .startup = omap_dmic_dai_startup,
+ .shutdown = omap_dmic_dai_shutdown,
+ .hw_params = omap_dmic_dai_hw_params,
+ .prepare = omap_dmic_dai_prepare,
+ .trigger = omap_dmic_dai_trigger,
+ .set_sysclk = omap_dmic_set_dai_sysclk,
+};
+
static struct snd_soc_dai_driver omap_dmic_dai = {
.name = "omap-dmic",
- .probe = omap_dmic_probe,
- .remove = omap_dmic_remove,
.capture = {
.channels_min = 2,
.channels_max = 6,
diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c
index f9fe96b61852..fdabed5133e8 100644
--- a/sound/soc/ti/omap-mcbsp.c
+++ b/sound/soc/ti/omap-mcbsp.c
@@ -1254,18 +1254,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return err;
}
-static const struct snd_soc_dai_ops mcbsp_dai_ops = {
- .startup = omap_mcbsp_dai_startup,
- .shutdown = omap_mcbsp_dai_shutdown,
- .prepare = omap_mcbsp_dai_prepare,
- .trigger = omap_mcbsp_dai_trigger,
- .delay = omap_mcbsp_dai_delay,
- .hw_params = omap_mcbsp_dai_hw_params,
- .set_fmt = omap_mcbsp_dai_set_dai_fmt,
- .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
- .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
-};
-
static int omap_mcbsp_probe(struct snd_soc_dai *dai)
{
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
@@ -1288,9 +1276,21 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mcbsp_dai_ops = {
+ .probe = omap_mcbsp_probe,
+ .remove = omap_mcbsp_remove,
+ .startup = omap_mcbsp_dai_startup,
+ .shutdown = omap_mcbsp_dai_shutdown,
+ .prepare = omap_mcbsp_dai_prepare,
+ .trigger = omap_mcbsp_dai_trigger,
+ .delay = omap_mcbsp_dai_delay,
+ .hw_params = omap_mcbsp_dai_hw_params,
+ .set_fmt = omap_mcbsp_dai_set_dai_fmt,
+ .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
+ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
+};
+
static struct snd_soc_dai_driver omap_mcbsp_dai = {
- .probe = omap_mcbsp_probe,
- .remove = omap_mcbsp_remove,
.playback = {
.channels_min = 1,
.channels_max = 16,
diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c
index 35deceb73427..d7d9f708f1fd 100644
--- a/sound/soc/ti/omap-mcpdm.c
+++ b/sound/soc/ti/omap-mcpdm.c
@@ -404,13 +404,6 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
- .startup = omap_mcpdm_dai_startup,
- .shutdown = omap_mcpdm_dai_shutdown,
- .hw_params = omap_mcpdm_dai_hw_params,
- .prepare = omap_mcpdm_prepare,
-};
-
static int omap_mcpdm_probe(struct snd_soc_dai *dai)
{
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
@@ -457,6 +450,17 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
+ .probe = omap_mcpdm_probe,
+ .remove = omap_mcpdm_remove,
+ .startup = omap_mcpdm_dai_startup,
+ .shutdown = omap_mcpdm_dai_shutdown,
+ .hw_params = omap_mcpdm_dai_hw_params,
+ .prepare = omap_mcpdm_prepare,
+ .probe_order = SND_SOC_COMP_ORDER_LATE,
+ .remove_order = SND_SOC_COMP_ORDER_EARLY,
+};
+
#ifdef CONFIG_PM_SLEEP
static int omap_mcpdm_suspend(struct snd_soc_component *component)
{
@@ -502,10 +506,6 @@ static int omap_mcpdm_resume(struct snd_soc_component *component)
#define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE
static struct snd_soc_dai_driver omap_mcpdm_dai = {
- .probe = omap_mcpdm_probe,
- .remove = omap_mcpdm_remove,
- .probe_order = SND_SOC_COMP_ORDER_LATE,
- .remove_order = SND_SOC_COMP_ORDER_EARLY,
.playback = {
.channels_min = 1,
.channels_max = 5,
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 4e8d5f7532ba..7c5188477b7c 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -355,30 +355,7 @@ static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
return 0;
}
-const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
- .set_sysclk = uniphier_aio_set_sysclk,
- .set_pll = uniphier_aio_set_pll,
- .set_fmt = uniphier_aio_set_fmt,
- .startup = uniphier_aio_startup,
- .shutdown = uniphier_aio_shutdown,
- .hw_params = uniphier_aio_hw_params,
- .hw_free = uniphier_aio_hw_free,
- .prepare = uniphier_aio_prepare,
-};
-EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
-
-const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
- .set_sysclk = uniphier_aio_set_sysclk,
- .set_pll = uniphier_aio_set_pll,
- .startup = uniphier_aio_startup,
- .shutdown = uniphier_aio_shutdown,
- .hw_params = uniphier_aio_hw_params,
- .hw_free = uniphier_aio_hw_free,
- .prepare = uniphier_aio_prepare,
-};
-EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
-
-int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
+static int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
int i;
@@ -403,9 +380,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
-int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
+static int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
{
struct uniphier_aio *aio = uniphier_priv(dai);
@@ -413,7 +389,138 @@ int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
return 0;
}
-EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
+
+static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = uniphier_aio_dai_probe(dai);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
+{
+ int ret;
+
+ ret = uniphier_aio_dai_probe(dai);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
+ .probe = uniphier_aio_ld11_probe,
+ .remove = uniphier_aio_dai_remove,
+ .set_sysclk = uniphier_aio_set_sysclk,
+ .set_pll = uniphier_aio_set_pll,
+ .set_fmt = uniphier_aio_set_fmt,
+ .startup = uniphier_aio_startup,
+ .shutdown = uniphier_aio_shutdown,
+ .hw_params = uniphier_aio_hw_params,
+ .hw_free = uniphier_aio_hw_free,
+ .prepare = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = {
+ .probe = uniphier_aio_ld11_probe,
+ .remove = uniphier_aio_dai_remove,
+ .set_sysclk = uniphier_aio_set_sysclk,
+ .set_pll = uniphier_aio_set_pll,
+ .startup = uniphier_aio_startup,
+ .shutdown = uniphier_aio_shutdown,
+ .hw_params = uniphier_aio_hw_params,
+ .hw_free = uniphier_aio_hw_free,
+ .prepare = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = {
+ .probe = uniphier_aio_ld11_probe,
+ .remove = uniphier_aio_dai_remove,
+ .set_sysclk = uniphier_aio_set_sysclk,
+ .set_pll = uniphier_aio_set_pll,
+ .startup = uniphier_aio_startup,
+ .shutdown = uniphier_aio_shutdown,
+ .hw_params = uniphier_aio_hw_params,
+ .hw_free = uniphier_aio_hw_free,
+ .prepare = uniphier_aio_prepare,
+ .compress_new = snd_soc_new_compress,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2);
+
+const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = {
+ .probe = uniphier_aio_pxs2_probe,
+ .remove = uniphier_aio_dai_remove,
+ .set_sysclk = uniphier_aio_set_sysclk,
+ .set_pll = uniphier_aio_set_pll,
+ .set_fmt = uniphier_aio_set_fmt,
+ .startup = uniphier_aio_startup,
+ .shutdown = uniphier_aio_shutdown,
+ .hw_params = uniphier_aio_hw_params,
+ .hw_free = uniphier_aio_hw_free,
+ .prepare = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = {
+ .probe = uniphier_aio_pxs2_probe,
+ .remove = uniphier_aio_dai_remove,
+ .set_sysclk = uniphier_aio_set_sysclk,
+ .set_pll = uniphier_aio_set_pll,
+ .startup = uniphier_aio_startup,
+ .shutdown = uniphier_aio_shutdown,
+ .hw_params = uniphier_aio_hw_params,
+ .hw_free = uniphier_aio_hw_free,
+ .prepare = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = {
+ .probe = uniphier_aio_pxs2_probe,
+ .remove = uniphier_aio_dai_remove,
+ .set_sysclk = uniphier_aio_set_sysclk,
+ .set_pll = uniphier_aio_set_pll,
+ .startup = uniphier_aio_startup,
+ .shutdown = uniphier_aio_shutdown,
+ .hw_params = uniphier_aio_hw_params,
+ .hw_free = uniphier_aio_hw_free,
+ .prepare = uniphier_aio_prepare,
+ .compress_new = snd_soc_new_compress,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2);
static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
{
diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c
index 7b3cf5d751f6..15dbded63804 100644
--- a/sound/soc/uniphier/aio-ld11.c
+++ b/sound/soc/uniphier/aio-ld11.c
@@ -188,36 +188,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = {
[AUD_PLL_HSC0] = { .enable = true, },
};
-static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
-{
- int ret;
-
- ret = uniphier_aio_dai_probe(dai);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
- if (ret < 0)
- return ret;
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
- if (ret < 0)
- return ret;
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
{
.name = AUD_GNAME_HDMI,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_PCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -234,12 +207,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_NAME_PCMIN2,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.capture = {
.stream_name = AUD_NAME_PCMIN2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -247,12 +218,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_GNAME_LINE,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_PCMOUT2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -267,12 +236,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_NAME_HPCMOUT1,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_HPCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -280,12 +247,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 8,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_NAME_PCMOUT3,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_PCMOUT3,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -293,12 +258,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_NAME_HIECOUT1,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_HIECOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -306,12 +269,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_spdif_ops,
+ .ops = &uniphier_aio_spdif_ld11_ops,
},
{
.name = AUD_NAME_EPCMOUT2,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_EPCMOUT2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -321,12 +282,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_NAME_EPCMOUT3,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_EPCMOUT3,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -336,19 +295,16 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_ld11_ops,
},
{
.name = AUD_NAME_HIECCOMPOUT1,
- .probe = uniphier_aio_ld11_probe,
- .remove = uniphier_aio_dai_remove,
- .compress_new = snd_soc_new_compress,
.playback = {
.stream_name = AUD_NAME_HIECCOMPOUT1,
.channels_min = 1,
.channels_max = 1,
},
- .ops = &uniphier_aio_spdif_ops,
+ .ops = &uniphier_aio_spdif_ld11_ops2,
},
};
diff --git a/sound/soc/uniphier/aio-pxs2.c b/sound/soc/uniphier/aio-pxs2.c
index 899904f7ffd6..305cb2a1253d 100644
--- a/sound/soc/uniphier/aio-pxs2.c
+++ b/sound/soc/uniphier/aio-pxs2.c
@@ -141,36 +141,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = {
[AUD_PLL_HSC0] = { .enable = true, },
};
-static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
-{
- int ret;
-
- ret = uniphier_aio_dai_probe(dai);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
- if (ret < 0)
- return ret;
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
- if (ret < 0)
- return ret;
- ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
{
.name = AUD_GNAME_HDMI,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_HPCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -178,12 +151,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_pxs2_ops,
},
{
.name = AUD_GNAME_LINE,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_PCMOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -198,12 +169,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_pxs2_ops,
},
{
.name = AUD_GNAME_AUX,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_PCMOUT2,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -218,12 +187,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_i2s_ops,
+ .ops = &uniphier_aio_i2s_pxs2_ops,
},
{
.name = AUD_NAME_HIECOUT1,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_HIECOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -231,12 +198,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_spdif_ops,
+ .ops = &uniphier_aio_spdif_pxs2_ops,
},
{
.name = AUD_NAME_IECOUT1,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
.playback = {
.stream_name = AUD_NAME_IECOUT1,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
@@ -244,31 +209,25 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = &uniphier_aio_spdif_ops,
+ .ops = &uniphier_aio_spdif_pxs2_ops,
},
{
.name = AUD_NAME_HIECCOMPOUT1,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
- .compress_new = snd_soc_new_compress,
.playback = {
.stream_name = AUD_NAME_HIECCOMPOUT1,
.channels_min = 1,
.channels_max = 1,
},
- .ops = &uniphier_aio_spdif_ops,
+ .ops = &uniphier_aio_spdif_pxs2_ops2,
},
{
.name = AUD_NAME_IECCOMPOUT1,
- .probe = uniphier_aio_pxs2_probe,
- .remove = uniphier_aio_dai_remove,
- .compress_new = snd_soc_new_compress,
.playback = {
.stream_name = AUD_NAME_IECCOMPOUT1,
.channels_min = 1,
.channels_max = 1,
},
- .ops = &uniphier_aio_spdif_ops,
+ .ops = &uniphier_aio_spdif_pxs2_ops2,
},
};
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index 0b03571aa9f0..09ccb47337fd 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -306,12 +306,14 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai)
int uniphier_aiodma_soc_register_platform(struct platform_device *pdev);
extern const struct snd_compress_ops uniphier_aio_compress_ops;
-int uniphier_aio_dai_probe(struct snd_soc_dai *dai);
-int uniphier_aio_dai_remove(struct snd_soc_dai *dai);
int uniphier_aio_probe(struct platform_device *pdev);
int uniphier_aio_remove(struct platform_device *pdev);
-extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops;
-extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2;
u64 aio_rb_cnt(struct uniphier_aio_sub *sub);
u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub);
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index 44e88dad8584..cde0dd8e2569 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -683,6 +683,7 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
{
+ .probe = ux500_msp_dai_of_probe,
.set_sysclk = ux500_msp_dai_set_dai_sysclk,
.set_fmt = ux500_msp_dai_set_dai_fmt,
.set_tdm_slot = ux500_msp_dai_set_tdm_slot,
@@ -695,7 +696,6 @@ static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
};
static struct snd_soc_dai_driver ux500_msp_dai_drv = {
- .probe = ux500_msp_dai_of_probe,
.playback.channels_min = UX500_MSP_MIN_CHANNELS,
.playback.channels_max = UX500_MSP_MAX_CHANNELS,
.playback.rates = UX500_I2S_RATES,