summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-09 11:26:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-09 11:26:55 -0400
commite57ccca1ba33e1d92cc3bbf8b6304a46948844b0 (patch)
treea988a1f7d1d3250f57761dbea365482300a7b3b2
parenta2d635decbfa9c1e4ae15cb05b68b2559f7f827c (diff)
parented97c988bdc61ab6fb5d1f5f02a709844557b68f (diff)
Merge tag 'sound-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "The most significant changes at this cycle are the Sound Open Firmware support from Intel for the common DSP framework along with its support for Intel platforms. It's a door opened to a real "free" firmware (in the sense of FOSS), and other parties show interests in it. In addition to SOF, we've got a bunch of updates and fixes as usual. Some highlights are below. ALSA core: - Cleanups and fixes in ALSA timer code to cover some races spotted by syzkaller - Cleanups and fixes in ALSA sequencer code to cover some races, again unsurprisingly, spotted by syzkaller - Optimize the common page allocation helper with alloc_pages_exact() ASoC: - Add SOF core support, as well as Intel SOF platform support - Generic card driver improvements: support for MCLK/sample rate ratio and pin switches - A big set of improvements to TLV320AIC32x4 drivers - New drivers for Freescale audio mixers, several Intel machines, several Mediatek machines, Meson G12A, Spreadtrum compressed audio and DMA devices HD-audio: - A few Realtek codec fixes for reducing pop noises - Quirks for Chromebooks - Workaround for faulty connection report on AMD/Nvidia HDMI Others: - A quirk for Focusrite Scarlett Solo USB-audio - Add support for MOTU 8pre FireWire - 24bit sample format support in aloop - GUS patch format support (finally, over a decade) in native emux synth code" * tag 'sound-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (375 commits) ASoC: SOF: Fix unused variable warnings ALSA: line6: toneport: Fix broken usage of timer for delayed execution ALSA: aica: Fix a long-time build breakage ALSA: hda/realtek - Support low power consumption for ALC256 ASoC: stm32: i2s: update pcm hardware constraints ASoC: codec: hdac_hdmi: no checking monitor in hw_params ASoC: mediatek: mt6358: save PGA for mixer control ASoC: mediatek: mt6358: save output volume for mixer controls ASoC: mediatek: mt6358: initialize setting when ramping volume ASoC: SOF: core: fix undefined nocodec reference ASoC: SOF: xtensa: fix undefined references ASoC: SOF: Propagate sof_get_ctrl_copy_params() error properly ALSA: hdea/realtek - Headset fixup for System76 Gazelle (gaze14) ALSA: hda/intel: add CometLake PCI IDs ALSA: hda/realtek - Support low power consumption for ALC295 ASoC: rockchip: Fix an uninitialized variable compile warning ASoC: SOF: Fix a compile warning with CONFIG_PCI=n ASoC: da7219: Fix a compile warning at CONFIG_COMMON_CLK=n ASoC: sound/soc/sof/: fix kconfig dependency warning ASoC: stm32: spdifrx: change trace level on iec control ...
-rw-r--r--Documentation/devicetree/bindings/sound/adi,axi-i2s.txt7
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt4
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt39
-rw-r--r--Documentation/devicetree/bindings/sound/cs42l51.txt16
-rw-r--r--Documentation/devicetree/bindings/sound/da7219.txt8
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,audmix.txt50
-rw-r--r--Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt43
-rw-r--r--Documentation/devicetree/bindings/sound/mt8183-da7219-max98357.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt8
-rw-r--r--Documentation/devicetree/bindings/sound/rockchip,pdm.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/rt5651.txt5
-rw-r--r--Documentation/devicetree/bindings/sound/simple-amplifier.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/simple-card.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/sprd-mcdt.txt19
-rw-r--r--Documentation/sound/kernel-api/writing-an-alsa-driver.rst4
-rw-r--r--MAINTAINERS15
-rw-r--r--include/sound/core.h16
-rw-r--r--include/sound/da7219.h8
-rw-r--r--include/sound/hdaudio.h7
-rw-r--r--include/sound/memalloc.h4
-rw-r--r--include/sound/seq_kernel.h3
-rw-r--r--include/sound/simple_card_utils.h238
-rw-r--r--include/sound/sof.h100
-rw-r--r--include/sound/sof/control.h158
-rw-r--r--include/sound/sof/dai-intel.h178
-rw-r--r--include/sound/sof/dai.h75
-rw-r--r--include/sound/sof/header.h158
-rw-r--r--include/sound/sof/info.h118
-rw-r--r--include/sound/sof/pm.h48
-rw-r--r--include/sound/sof/stream.h148
-rw-r--r--include/sound/sof/topology.h256
-rw-r--r--include/sound/sof/trace.h67
-rw-r--r--include/sound/sof/xtensa.h44
-rw-r--r--include/uapi/sound/sof/abi.h62
-rw-r--r--include/uapi/sound/sof/eq.h172
-rw-r--r--include/uapi/sound/sof/fw.h78
-rw-r--r--include/uapi/sound/sof/header.h27
-rw-r--r--include/uapi/sound/sof/manifest.h188
-rw-r--r--include/uapi/sound/sof/tokens.h107
-rw-r--r--include/uapi/sound/sof/tone.h21
-rw-r--r--include/uapi/sound/sof/trace.h66
-rw-r--r--sound/core/init.c23
-rw-r--r--sound/core/memalloc.c53
-rw-r--r--sound/core/oss/mixer_oss.c16
-rw-r--r--sound/core/pcm.c14
-rw-r--r--sound/core/seq/oss/seq_oss_device.h10
-rw-r--r--sound/core/seq/oss/seq_oss_rw.c11
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c2
-rw-r--r--sound/core/seq/seq_clientmgr.c109
-rw-r--r--sound/core/seq/seq_clientmgr.h8
-rw-r--r--sound/core/seq/seq_fifo.c14
-rw-r--r--sound/core/seq/seq_memory.c30
-rw-r--r--sound/core/seq/seq_ports.c30
-rw-r--r--sound/core/seq/seq_ports.h5
-rw-r--r--sound/core/sound.c5
-rw-r--r--sound/core/timer.c181
-rw-r--r--sound/drivers/aloop.c4
-rw-r--r--sound/firewire/amdtp-stream.c44
-rw-r--r--sound/firewire/motu/amdtp-motu.c6
-rw-r--r--sound/firewire/motu/motu-protocol-v2.c43
-rw-r--r--sound/firewire/motu/motu.c15
-rw-r--r--sound/firewire/motu/motu.h1
-rw-r--r--sound/hda/ext/hdac_ext_bus.c2
-rw-r--r--sound/hda/hdac_bus.c1
-rw-r--r--sound/isa/gus/gus_mem.c2
-rw-r--r--sound/last.c10
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c16
-rw-r--r--sound/pci/hda/hda_codec.c8
-rw-r--r--sound/pci/hda/hda_intel.c12
-rw-r--r--sound/pci/hda/patch_hdmi.c11
-rw-r--r--sound/pci/hda/patch_realtek.c84
-rw-r--r--sound/ppc/snd_ps3.c4
-rw-r--r--sound/sh/aica.c14
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/adi/axi-i2s.c68
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c68
-rw-r--r--sound/soc/amd/raven/acp3x-pcm-dma.c2
-rw-r--r--sound/soc/atmel/Kconfig14
-rw-r--r--sound/soc/atmel/Makefile2
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c974
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c16
-rw-r--r--sound/soc/codecs/Kconfig15
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c13
-rw-r--r--sound/soc/codecs/cs42l51.c225
-rw-r--r--sound/soc/codecs/cs42l51.h3
-rw-r--r--sound/soc/codecs/cs43130.c2
-rw-r--r--sound/soc/codecs/cs47l24.c4
-rw-r--r--sound/soc/codecs/da7213.c5
-rw-r--r--sound/soc/codecs/da7213.h2
-rw-r--r--sound/soc/codecs/da7219.c542
-rw-r--r--sound/soc/codecs/da7219.h6
-rw-r--r--sound/soc/codecs/es8316.c14
-rw-r--r--sound/soc/codecs/hdac_hda.c6
-rw-r--r--sound/soc/codecs/hdac_hdmi.c24
-rw-r--r--sound/soc/codecs/hdmi-codec.c12
-rw-r--r--sound/soc/codecs/lochnagar-sc.c266
-rw-r--r--sound/soc/codecs/max98090.c12
-rw-r--r--sound/soc/codecs/max98357a.c3
-rw-r--r--sound/soc/codecs/mt6358.c131
-rw-r--r--sound/soc/codecs/nau8810.c25
-rw-r--r--sound/soc/codecs/pcm3168a.c7
-rw-r--r--sound/soc/codecs/rt5645.c17
-rw-r--r--sound/soc/codecs/rt5651.c47
-rw-r--r--sound/soc/codecs/rt5651.h1
-rw-r--r--sound/soc/codecs/rt5677-spi.c43
-rw-r--r--sound/soc/codecs/rt5682.c2
-rw-r--r--sound/soc/codecs/simple-amplifier.c3
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c3
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c61
-rw-r--r--sound/soc/codecs/tlv320aic31xx.h12
-rw-r--r--sound/soc/codecs/tlv320aic32x4-clk.c483
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c14
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c14
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c441
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h13
-rw-r--r--sound/soc/codecs/wcd9335.c1
-rw-r--r--sound/soc/codecs/wm5102.c4
-rw-r--r--sound/soc/codecs/wm5110.c4
-rw-r--r--sound/soc/codecs/wm_adsp.c1032
-rw-r--r--sound/soc/codecs/wm_adsp.h50
-rw-r--r--sound/soc/codecs/wmfw.h30
-rw-r--r--sound/soc/fsl/Kconfig25
-rw-r--r--sound/soc/fsl/Makefile5
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c30
-rw-r--r--sound/soc/fsl/fsl_audmix.c578
-rw-r--r--sound/soc/fsl/fsl_audmix.h102
-rw-r--r--sound/soc/fsl/fsl_dma.c26
-rw-r--r--sound/soc/fsl/fsl_dma.h5
-rw-r--r--sound/soc/fsl/fsl_esai.c23
-rw-r--r--sound/soc/fsl/fsl_micfil.c3
-rw-r--r--sound/soc/fsl/fsl_sai.c26
-rw-r--r--sound/soc/fsl/fsl_utils.c1
-rw-r--r--sound/soc/fsl/imx-audmix.c331
-rw-r--r--sound/soc/fsl/imx-audmux.c26
-rw-r--r--sound/soc/fsl/imx-es8328.c15
-rw-r--r--sound/soc/fsl/imx-mc13783.c22
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c21
-rw-r--r--sound/soc/fsl/imx-pcm.h6
-rw-r--r--sound/soc/fsl/imx-spdif.c13
-rw-r--r--sound/soc/fsl/imx-ssi.c57
-rw-r--r--sound/soc/fsl/imx-ssi.h6
-rw-r--r--sound/soc/fsl/mpc5200_dma.c14
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c16
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c14
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c18
-rw-r--r--sound/soc/fsl/mx27vis-aic32x4.c29
-rw-r--r--sound/soc/fsl/p1022_ds.c18
-rw-r--r--sound/soc/fsl/p1022_rdk.c32
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c18
-rw-r--r--sound/soc/fsl/phycore-ac97.c16
-rw-r--r--sound/soc/fsl/wm1133-ev1.c21
-rw-r--r--sound/soc/generic/audio-graph-card.c429
-rw-r--r--sound/soc/generic/simple-card-utils.c440
-rw-r--r--sound/soc/generic/simple-card.c383
-rw-r--r--sound/soc/intel/Kconfig7
-rw-r--r--sound/soc/intel/boards/Kconfig117
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c4
-rw-r--r--sound/soc/intel/boards/broadwell.c4
-rw-r--r--sound/soc/intel/boards/bytcht_es8316.c42
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c6
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c28
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c2
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98927.c52
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.c22
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_common.h2
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c19
-rw-r--r--sound/soc/intel/boards/sof_rt5682.c563
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-byt-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cht-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cnl-match.c19
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-glk-match.c9
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-icl-match.c6
-rw-r--r--sound/soc/intel/common/sst-firmware.c8
-rw-r--r--sound/soc/intel/haswell/sst-haswell-ipc.c8
-rw-r--r--sound/soc/jz4740/Kconfig2
-rw-r--r--sound/soc/mediatek/Kconfig27
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c51
-rw-r--r--sound/soc/mediatek/common/mtk-btcvsd.c4
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c13
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c16
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c16
-rw-r--r--sound/soc/mediatek/mt8183/Makefile2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-pcm.c18
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c471
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c423
-rw-r--r--sound/soc/meson/axg-fifo.c34
-rw-r--r--sound/soc/meson/axg-fifo.h2
-rw-r--r--sound/soc/meson/axg-frddr.c143
-rw-r--r--sound/soc/meson/axg-tdm-formatter.c6
-rw-r--r--sound/soc/meson/axg-tdm-formatter.h11
-rw-r--r--sound/soc/meson/axg-tdmin.c16
-rw-r--r--sound/soc/meson/axg-tdmout.c29
-rw-r--r--sound/soc/meson/axg-toddr.c53
-rw-r--r--sound/soc/qcom/Kconfig2
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c205
-rw-r--r--sound/soc/rockchip/rockchip_pdm.h12
-rw-r--r--sound/soc/samsung/arndale_rt5631.c17
-rw-r--r--sound/soc/samsung/bells.c15
-rw-r--r--sound/soc/samsung/dma.h8
-rw-r--r--sound/soc/samsung/dmaengine.c22
-rw-r--r--sound/soc/samsung/h1940_uda1380.c22
-rw-r--r--sound/soc/samsung/i2s-regs.h8
-rw-r--r--sound/soc/samsung/i2s.c27
-rw-r--r--sound/soc/samsung/i2s.h8
-rw-r--r--sound/soc/samsung/idma.c20
-rw-r--r--sound/soc/samsung/idma.h9
-rw-r--r--sound/soc/samsung/jive_wm8750.c19
-rw-r--r--sound/soc/samsung/littlemill.c15
-rw-r--r--sound/soc/samsung/lowland.c15
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c25
-rw-r--r--sound/soc/samsung/odroid.c10
-rw-r--r--sound/soc/samsung/pcm.c19
-rw-r--r--sound/soc/samsung/pcm.h8
-rw-r--r--sound/soc/samsung/regs-i2s-v2.h10
-rw-r--r--sound/soc/samsung/regs-iis.h7
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c30
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c26
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.h11
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c28
-rw-r--r--sound/soc/samsung/s3c2412-i2s.h11
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c25
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.h6
-rw-r--r--sound/soc/samsung/s3c24xx_simtec.c11
-rw-r--r--sound/soc/samsung/s3c24xx_simtec.h10
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_hermes.c11
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c11
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c20
-rw-r--r--sound/soc/samsung/smartq_wm8987.c21
-rw-r--r--sound/soc/samsung/smdk_spdif.c16
-rw-r--r--sound/soc/samsung/smdk_wm8580.c15
-rw-r--r--sound/soc/samsung/smdk_wm8994.c9
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c16
-rw-r--r--sound/soc/samsung/snow.c15
-rw-r--r--sound/soc/samsung/spdif.c17
-rw-r--r--sound/soc/samsung/spdif.h8
-rw-r--r--sound/soc/samsung/speyside.c15
-rw-r--r--sound/soc/samsung/tm2_wm5110.c17
-rw-r--r--sound/soc/samsung/tobermory.c15
-rw-r--r--sound/soc/sh/rcar/core.c18
-rw-r--r--sound/soc/sh/rcar/rsnd.h1
-rw-r--r--sound/soc/sh/rcar/ssi.c2
-rw-r--r--sound/soc/soc-core.c18
-rw-r--r--sound/soc/soc-dapm.c5
-rw-r--r--sound/soc/soc-pcm.c14
-rw-r--r--sound/soc/soc-topology.c330
-rw-r--r--sound/soc/sof/Kconfig156
-rw-r--r--sound/soc/sof/Makefile18
-rw-r--r--sound/soc/sof/control.c552
-rw-r--r--sound/soc/sof/core.c508
-rw-r--r--sound/soc/sof/debug.c232
-rw-r--r--sound/soc/sof/intel/Kconfig230
-rw-r--r--sound/soc/sof/intel/Makefile19
-rw-r--r--sound/soc/sof/intel/apl.c113
-rw-r--r--sound/soc/sof/intel/bdw.c713
-rw-r--r--sound/soc/sof/intel/byt.c874
-rw-r--r--sound/soc/sof/intel/cnl.c268
-rw-r--r--sound/soc/sof/intel/hda-bus.c111
-rw-r--r--sound/soc/sof/intel/hda-codec.c171
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c181
-rw-r--r--sound/soc/sof/intel/hda-dai.c356
-rw-r--r--sound/soc/sof/intel/hda-dsp.c471
-rw-r--r--sound/soc/sof/intel/hda-ipc.c455
-rw-r--r--sound/soc/sof/intel/hda-loader.c382
-rw-r--r--sound/soc/sof/intel/hda-pcm.c239
-rw-r--r--sound/soc/sof/intel/hda-stream.c701
-rw-r--r--sound/soc/sof/intel/hda-trace.c94
-rw-r--r--sound/soc/sof/intel/hda.c689
-rw-r--r--sound/soc/sof/intel/hda.h583
-rw-r--r--sound/soc/sof/intel/intel-ipc.c92
-rw-r--r--sound/soc/sof/intel/shim.h185
-rw-r--r--sound/soc/sof/ipc.c846
-rw-r--r--sound/soc/sof/loader.c400
-rw-r--r--sound/soc/sof/nocodec.c109
-rw-r--r--sound/soc/sof/ops.c163
-rw-r--r--sound/soc/sof/ops.h411
-rw-r--r--sound/soc/sof/pcm.c767
-rw-r--r--sound/soc/sof/pm.c388
-rw-r--r--sound/soc/sof/sof-acpi-dev.c312
-rw-r--r--sound/soc/sof/sof-pci-dev.c373
-rw-r--r--sound/soc/sof/sof-priv.h635
-rw-r--r--sound/soc/sof/topology.c3179
-rw-r--r--sound/soc/sof/trace.c297
-rw-r--r--sound/soc/sof/utils.c112
-rw-r--r--sound/soc/sof/xtensa/Kconfig2
-rw-r--r--sound/soc/sof/xtensa/Makefile5
-rw-r--r--sound/soc/sof/xtensa/core.c138
-rw-r--r--sound/soc/sprd/Kconfig9
-rw-r--r--sound/soc/sprd/Makefile6
-rw-r--r--sound/soc/sprd/sprd-mcdt.c1011
-rw-r--r--sound/soc/sprd/sprd-mcdt.h107
-rw-r--r--sound/soc/sprd/sprd-pcm-compress.c674
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c9
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.h43
-rw-r--r--sound/soc/stm/stm32_adfsdm.c2
-rw-r--r--sound/soc/stm/stm32_i2s.c33
-rw-r--r--sound/soc/stm/stm32_sai.c80
-rw-r--r--sound/soc/stm/stm32_sai.h2
-rw-r--r--sound/soc/stm/stm32_sai_sub.c88
-rw-r--r--sound/soc/stm/stm32_spdifrx.c47
-rw-r--r--sound/soc/ti/Kconfig4
-rw-r--r--sound/soc/ti/ams-delta.c2
-rw-r--r--sound/soc/ti/davinci-mcasp.c2
-rw-r--r--sound/soc/ti/edma-pcm.c5
-rw-r--r--sound/soc/ti/sdma-pcm.c9
-rw-r--r--sound/synth/emux/emux_hwdep.c5
-rw-r--r--sound/synth/emux/soundfont.c2
-rw-r--r--sound/usb/line6/toneport.c16
-rw-r--r--sound/usb/mixer.c6
-rw-r--r--sound/usb/quirks-table.h84
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c3
-rw-r--r--sound/usb/usx2y/usb_stream.c20
-rw-r--r--sound/usb/usx2y/usbusx2y.c7
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c6
321 files changed, 30072 insertions, 3180 deletions
diff --git a/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt b/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt
index 4248b662deff..229ad1392cdc 100644
--- a/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt
@@ -1,5 +1,8 @@
1ADI AXI-I2S controller 1ADI AXI-I2S controller
2 2
3The core can be generated with transmit (playback), only receive
4(capture) or both directions enabled.
5
3Required properties: 6Required properties:
4 - compatible : Must be "adi,axi-i2s-1.00.a" 7 - compatible : Must be "adi,axi-i2s-1.00.a"
5 - reg : Must contain I2S core's registers location and length 8 - reg : Must contain I2S core's registers location and length
@@ -9,8 +12,8 @@ Required properties:
9 - clock-names : "axi" for the clock to the AXI interface, "ref" for the sample 12 - clock-names : "axi" for the clock to the AXI interface, "ref" for the sample
10 rate reference clock. 13 rate reference clock.
11 - dmas: Pairs of phandle and specifier for the DMA channels that are used by 14 - dmas: Pairs of phandle and specifier for the DMA channels that are used by
12 the core. The core expects two dma channels, one for transmit and one for 15 the core. The core expects two dma channels if both transmit and receive are
13 receive. 16 enabled, one channel otherwise.
14 - dma-names : "tx" for the transmit channel, "rx" for the receive channel. 17 - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
15 18
16For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties 19For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
index 3dfc2515e5c6..4330fc9dca6d 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt
@@ -2,7 +2,9 @@
2 2
3Required properties: 3Required properties:
4- compatible: 'amlogic,axg-toddr' or 4- compatible: 'amlogic,axg-toddr' or
5 'amlogic,axg-frddr' 5 'amlogic,axg-toddr' or
6 'amlogic,g12a-frddr' or
7 'amlogic,g12a-toddr'
6- reg: physical base address of the controller and length of memory 8- reg: physical base address of the controller and length of memory
7 mapped region. 9 mapped region.
8- interrupts: interrupt specifier for the fifo. 10- interrupts: interrupt specifier for the fifo.
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt
index 5672d0bc5b16..73f473a9365f 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt
@@ -1,7 +1,8 @@
1* Amlogic Audio PDM input 1* Amlogic Audio PDM input
2 2
3Required properties: 3Required properties:
4- compatible: 'amlogic,axg-pdm' 4- compatible: 'amlogic,axg-pdm' or
5 'amlogic,g12a-pdm'
5- reg: physical base address of the controller and length of memory 6- reg: physical base address of the controller and length of memory
6 mapped region. 7 mapped region.
7- clocks: list of clock phandle, one for each entry clock-names. 8- clocks: list of clock phandle, one for each entry clock-names.
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt
index 2e6cb7d9b202..0b82504fa419 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt
@@ -1,7 +1,8 @@
1* Amlogic Audio SPDIF Input 1* Amlogic Audio SPDIF Input
2 2
3Required properties: 3Required properties:
4- compatible: 'amlogic,axg-spdifin' 4- compatible: 'amlogic,axg-spdifin' or
5 'amlogic,g12a-spdifin'
5- interrupts: interrupt specifier for the spdif input. 6- interrupts: interrupt specifier for the spdif input.
6- clocks: list of clock phandle, one for each entry clock-names. 7- clocks: list of clock phandle, one for each entry clock-names.
7- clock-names: should contain the following: 8- clock-names: should contain the following:
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt
index 521c38ad89e7..826152730508 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt
@@ -1,7 +1,8 @@
1* Amlogic Audio SPDIF Output 1* Amlogic Audio SPDIF Output
2 2
3Required properties: 3Required properties:
4- compatible: 'amlogic,axg-spdifout' 4- compatible: 'amlogic,axg-spdifout' or
5 'amlogic,g12a-spdifout'
5- clocks: list of clock phandle, one for each entry clock-names. 6- clocks: list of clock phandle, one for each entry clock-names.
6- clock-names: should contain the following: 7- clock-names: should contain the following:
7 * "pclk" : peripheral clock. 8 * "pclk" : peripheral clock.
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt
index 1c1b7490554e..3b94a715a0b9 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt
@@ -2,7 +2,9 @@
2 2
3Required properties: 3Required properties:
4- compatible: 'amlogic,axg-tdmin' or 4- compatible: 'amlogic,axg-tdmin' or
5 'amlogic,axg-tdmout' 5 'amlogic,axg-tdmout' or
6 'amlogic,g12a-tdmin' or
7 'amlogic,g12a-tdmout'
6- reg: physical base address of the controller and length of memory 8- reg: physical base address of the controller and length of memory
7 mapped region. 9 mapped region.
8- clocks: list of clock phandle, one for each entry clock-names. 10- clocks: list of clock phandle, one for each entry clock-names.
diff --git a/Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt
new file mode 100644
index 000000000000..41ae2699f07a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt
@@ -0,0 +1,39 @@
1Cirrus Logic Lochnagar Audio Development Board
2
3Lochnagar is an evaluation and development board for Cirrus Logic
4Smart CODEC and Amp devices. It allows the connection of most Cirrus
5Logic devices on mini-cards, as well as allowing connection of
6various application processor systems to provide a full evaluation
7platform. Audio system topology, clocking and power can all be
8controlled through the Lochnagar, allowing the device under test
9to be used in a variety of possible use cases.
10
11This binding document describes the binding for the audio portion
12of the driver.
13
14This binding must be part of the Lochnagar MFD binding:
15 [4] ../mfd/cirrus,lochnagar.txt
16
17Required properties:
18
19 - compatible : One of the following strings:
20 "cirrus,lochnagar2-soundcard"
21
22 - #sound-dai-cells : Must be set to 1.
23
24 - clocks : Contains an entry for each entry in clock-names.
25 - clock-names : Must include the following clocks:
26 "mclk" Master clock source for the sound card, should normally
27 be set to LOCHNAGAR_SOUNDCARD_MCLK provided by the Lochnagar
28 clock driver.
29
30Example:
31
32lochnagar-sc {
33 compatible = "cirrus,lochnagar2-soundcard";
34
35 #sound-dai-cells = <1>;
36
37 clocks = <&lochnagar_clk LOCHNAGAR_SOUNDCARD_MCLK>;
38 clock-names = "mclk";
39};
diff --git a/Documentation/devicetree/bindings/sound/cs42l51.txt b/Documentation/devicetree/bindings/sound/cs42l51.txt
index 4b5de33ce377..acbd68ddd2cb 100644
--- a/Documentation/devicetree/bindings/sound/cs42l51.txt
+++ b/Documentation/devicetree/bindings/sound/cs42l51.txt
@@ -1,6 +1,17 @@
1CS42L51 audio CODEC 1CS42L51 audio CODEC
2 2
3Required properties:
4
5 - compatible : "cirrus,cs42l51"
6
7 - reg : the I2C address of the device for I2C.
8
3Optional properties: 9Optional properties:
10 - VL-supply, VD-supply, VA-supply, VAHP-supply: power supplies for the device,
11 as covered in Documentation/devicetree/bindings/regulator/regulator.txt.
12
13 - reset-gpios : GPIO specification for the reset pin. If specified, it will be
14 deasserted before starting the communication with the codec.
4 15
5 - clocks : a list of phandles + clock-specifiers, one for each entry in 16 - clocks : a list of phandles + clock-specifiers, one for each entry in
6 clock-names 17 clock-names
@@ -14,4 +25,9 @@ cs42l51: cs42l51@4a {
14 reg = <0x4a>; 25 reg = <0x4a>;
15 clocks = <&mclk_prov>; 26 clocks = <&mclk_prov>;
16 clock-names = "MCLK"; 27 clock-names = "MCLK";
28 VL-supply = <&reg_audio>;
29 VD-supply = <&reg_audio>;
30 VA-supply = <&reg_audio>;
31 VAHP-supply = <&reg_audio>;
32 reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
17}; 33};
diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt
index e9d0baeb94e2..add1caf26ac2 100644
--- a/Documentation/devicetree/bindings/sound/da7219.txt
+++ b/Documentation/devicetree/bindings/sound/da7219.txt
@@ -23,8 +23,8 @@ Optional properties:
23 interrupt is to be used to wake system, otherwise "irq" should be used. 23 interrupt is to be used to wake system, otherwise "irq" should be used.
24- wakeup-source: Flag to indicate this device can wake system (suspend/resume). 24- wakeup-source: Flag to indicate this device can wake system (suspend/resume).
25 25
26- #clock-cells : Should be set to '<0>', only one clock source provided; 26- #clock-cells : Should be set to '<1>', two clock sources provided;
27- clock-output-names : Name given for DAI clocks output; 27- clock-output-names : Names given for DAI clock outputs (WCLK & BCLK);
28 28
29- clocks : phandle and clock specifier for codec MCLK. 29- clocks : phandle and clock specifier for codec MCLK.
30- clock-names : Clock name string for 'clocks' attribute, should be "mclk". 30- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
@@ -84,8 +84,8 @@ Example:
84 VDDMIC-supply = <&reg_audio>; 84 VDDMIC-supply = <&reg_audio>;
85 VDDIO-supply = <&reg_audio>; 85 VDDIO-supply = <&reg_audio>;
86 86
87 #clock-cells = <0>; 87 #clock-cells = <1>;
88 clock-output-names = "dai-clks"; 88 clock-output-names = "dai-wclk", "dai-bclk";
89 89
90 clocks = <&clks 201>; 90 clocks = <&clks 201>;
91 clock-names = "mclk"; 91 clock-names = "mclk";
diff --git a/Documentation/devicetree/bindings/sound/fsl,audmix.txt b/Documentation/devicetree/bindings/sound/fsl,audmix.txt
new file mode 100644
index 000000000000..840b7e0d6a63
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,audmix.txt
@@ -0,0 +1,50 @@
1NXP Audio Mixer (AUDMIX).
2
3The Audio Mixer is a on-chip functional module that allows mixing of two
4audio streams into a single audio stream. Audio Mixer has two input serial
5audio interfaces. These are driven by two Synchronous Audio interface
6modules (SAI). Each input serial interface carries 8 audio channels in its
7frame in TDM manner. Mixer mixes audio samples of corresponding channels
8from two interfaces into a single sample. Before mixing, audio samples of
9two inputs can be attenuated based on configuration. The output of the
10Audio Mixer is also a serial audio interface. Like input interfaces it has
11the same TDM frame format. This output is used to drive the serial DAC TDM
12interface of audio codec and also sent to the external pins along with the
13receive path of normal audio SAI module for readback by the CPU.
14
15The output of Audio Mixer can be selected from any of the three streams
16 - serial audio input 1
17 - serial audio input 2
18 - mixed audio
19
20Mixing operation is independent of audio sample rate but the two audio
21input streams must have same audio sample rate with same number of channels
22in TDM frame to be eligible for mixing.
23
24Device driver required properties:
25=================================
26 - compatible : Compatible list, contains "fsl,imx8qm-audmix"
27
28 - reg : Offset and length of the register set for the device.
29
30 - clocks : Must contain an entry for each entry in clock-names.
31
32 - clock-names : Must include the "ipg" for register access.
33
34 - power-domains : Must contain the phandle to AUDMIX power domain node
35
36 - dais : Must contain a list of phandles to AUDMIX connected
37 DAIs. The current implementation requires two phandles
38 to SAI interfaces to be provided, the first SAI in the
39 list being used to route the AUDMIX output.
40
41Device driver configuration example:
42======================================
43 audmix: audmix@59840000 {
44 compatible = "fsl,imx8qm-audmix";
45 reg = <0x0 0x59840000 0x0 0x10000>;
46 clocks = <&clk IMX8QXP_AUD_AUDMIX_IPG>;
47 clock-names = "ipg";
48 power-domains = <&pd_audmix>;
49 dais = <&sai4>, <&sai5>;
50 };
diff --git a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt
new file mode 100644
index 000000000000..91ec83a6faed
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt
@@ -0,0 +1,43 @@
1* Microchip I2S Multi-Channel Controller
2
3Required properties:
4- compatible: Should be "microchip,sam9x60-i2smcc".
5- reg: Should be the physical base address of the controller and the
6 length of memory mapped region.
7- interrupts: Should contain the interrupt for the controller.
8- dmas: Should be one per channel name listed in the dma-names property,
9 as described in atmel-dma.txt and dma.txt files.
10- dma-names: Identifier string for each DMA request line in the dmas property.
11 Two dmas have to be defined, "tx" and "rx".
12- clocks: Must contain an entry for each entry in clock-names.
13 Please refer to clock-bindings.txt.
14- clock-names: Should be one of each entry matching the clocks phandles list:
15 - "pclk" (peripheral clock) Required.
16 - "gclk" (generated clock) Optional (1).
17
18Optional properties:
19- pinctrl-0: Should specify pin control groups used for this controller.
20- princtrl-names: Should contain only one value - "default".
21
22
23(1) : Only the peripheral clock is required. The generated clock is optional
24 and should be set mostly when Master Mode is required.
25
26Example:
27
28 i2s@f001c000 {
29 compatible = "microchip,sam9x60-i2smcc";
30 reg = <0xf001c000 0x100>;
31 interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>;
32 dmas = <&dma0
33 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
34 AT91_XDMAC_DT_PERID(36))>,
35 <&dma0
36 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
37 AT91_XDMAC_DT_PERID(37))>;
38 dma-names = "tx", "rx";
39 clocks = <&i2s_clk>, <&i2s_gclk>;
40 clock-names = "pclk", "gclk";
41 pinctrl-names = "default";
42 pinctrl-0 = <&pinctrl_i2s_default>;
43 };
diff --git a/Documentation/devicetree/bindings/sound/mt8183-da7219-max98357.txt b/Documentation/devicetree/bindings/sound/mt8183-da7219-max98357.txt
new file mode 100644
index 000000000000..92ac86f83822
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8183-da7219-max98357.txt
@@ -0,0 +1,15 @@
1MT8183 with MT6358, DA7219 and MAX98357 CODECS
2
3Required properties:
4- compatible : "mediatek,mt8183_da7219_max98357"
5- mediatek,headset-codec: the phandles of da7219 codecs
6- mediatek,platform: the phandle of MT8183 ASoC platform
7
8Example:
9
10 sound {
11 compatible = "mediatek,mt8183_da7219_max98357";
12 mediatek,headset-codec = <&da7219>;
13 mediatek,platform = <&afe>;
14 };
15
diff --git a/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt b/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt
new file mode 100644
index 000000000000..d6d5207fa996
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt
@@ -0,0 +1,15 @@
1MT8183 with MT6358, TS3A227 and MAX98357 CODECS
2
3Required properties:
4- compatible : "mediatek,mt8183_mt6358_ts3a227_max98357"
5- mediatek,headset-codec: the phandles of ts3a227 codecs
6- mediatek,platform: the phandle of MT8183 ASoC platform
7
8Example:
9
10 sound {
11 compatible = "mediatek,mt8183_mt6358_ts3a227_max98357";
12 mediatek,headset-codec = <&ts3a227>;
13 mediatek,platform = <&afe>;
14 };
15
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index 648d43e1b1e9..5c52182f7dcf 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -266,6 +266,7 @@ Required properties:
266 - "renesas,rcar_sound-r8a7743" (RZ/G1M) 266 - "renesas,rcar_sound-r8a7743" (RZ/G1M)
267 - "renesas,rcar_sound-r8a7744" (RZ/G1N) 267 - "renesas,rcar_sound-r8a7744" (RZ/G1N)
268 - "renesas,rcar_sound-r8a7745" (RZ/G1E) 268 - "renesas,rcar_sound-r8a7745" (RZ/G1E)
269 - "renesas,rcar_sound-r8a77470" (RZ/G1C)
269 - "renesas,rcar_sound-r8a774a1" (RZ/G2M) 270 - "renesas,rcar_sound-r8a774a1" (RZ/G2M)
270 - "renesas,rcar_sound-r8a774c0" (RZ/G2E) 271 - "renesas,rcar_sound-r8a774c0" (RZ/G2E)
271 - "renesas,rcar_sound-r8a7778" (R-Car M1A) 272 - "renesas,rcar_sound-r8a7778" (R-Car M1A)
@@ -282,7 +283,12 @@ Required properties:
282- reg : Should contain the register physical address. 283- reg : Should contain the register physical address.
283 required register is 284 required register is
284 SRU/ADG/SSI if generation1 285 SRU/ADG/SSI if generation1
285 SRU/ADG/SSIU/SSI if generation2 286 SRU/ADG/SSIU/SSI/AUDIO-DMAC-periperi if generation2/generation3
287 Select extended AUDIO-DMAC-periperi address if SoC has it,
288 otherwise select normal AUDIO-DMAC-periperi address.
289- reg-names : Should contain the register names.
290 scu/adg/ssi if generation1
291 scu/adg/ssiu/ssi/audmapp if generation2/generation3
286- rcar_sound,ssi : Should contain SSI feature. 292- rcar_sound,ssi : Should contain SSI feature.
287 The number of SSI subnode should be same as HW. 293 The number of SSI subnode should be same as HW.
288 see below for detail. 294 see below for detail.
diff --git a/Documentation/devicetree/bindings/sound/rockchip,pdm.txt b/Documentation/devicetree/bindings/sound/rockchip,pdm.txt
index 47f164fbd1d7..98572a25122f 100644
--- a/Documentation/devicetree/bindings/sound/rockchip,pdm.txt
+++ b/Documentation/devicetree/bindings/sound/rockchip,pdm.txt
@@ -3,6 +3,9 @@
3Required properties: 3Required properties:
4 4
5- compatible: "rockchip,pdm" 5- compatible: "rockchip,pdm"
6 - "rockchip,px30-pdm"
7 - "rockchip,rk1808-pdm"
8 - "rockchip,rk3308-pdm"
6- reg: physical base address of the controller and length of memory mapped 9- reg: physical base address of the controller and length of memory mapped
7 region. 10 region.
8- dmas: DMA specifiers for rx dma. See the DMA client binding, 11- dmas: DMA specifiers for rx dma. See the DMA client binding,
@@ -12,6 +15,8 @@ Required properties:
12- clock-names: should contain following: 15- clock-names: should contain following:
13 - "pdm_hclk": clock for PDM BUS 16 - "pdm_hclk": clock for PDM BUS
14 - "pdm_clk" : clock for PDM controller 17 - "pdm_clk" : clock for PDM controller
18- resets: a list of phandle + reset-specifer paris, one for each entry in reset-names.
19- reset-names: reset names, should include "pdm-m".
15- pinctrl-names: Must contain a "default" entry. 20- pinctrl-names: Must contain a "default" entry.
16- pinctrl-N: One property must exist for each entry in 21- pinctrl-N: One property must exist for each entry in
17 pinctrl-names. See ../pinctrl/pinctrl-bindings.txt 22 pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
diff --git a/Documentation/devicetree/bindings/sound/rt5651.txt b/Documentation/devicetree/bindings/sound/rt5651.txt
index a41199a5cd79..56e736a1cba9 100644
--- a/Documentation/devicetree/bindings/sound/rt5651.txt
+++ b/Documentation/devicetree/bindings/sound/rt5651.txt
@@ -22,6 +22,11 @@ Optional properties:
22 2: Use JD1_2 pin for jack-detect 22 2: Use JD1_2 pin for jack-detect
23 3: Use JD2 pin for jack-detect 23 3: Use JD2 pin for jack-detect
24 24
25- realtek,jack-detect-not-inverted
26 bool. Normal jack-detect switches give an inverted (active-low) signal,
27 set this bool in the rare case you've a jack-detect switch which is not
28 inverted.
29
25- realtek,over-current-threshold-microamp 30- realtek,over-current-threshold-microamp
26 u32, micbias over-current detection threshold in µA, valid values are 31 u32, micbias over-current detection threshold in µA, valid values are
27 600, 1500 and 2000µA. 32 600, 1500 and 2000µA.
diff --git a/Documentation/devicetree/bindings/sound/simple-amplifier.txt b/Documentation/devicetree/bindings/sound/simple-amplifier.txt
index 7182ac4f1e65..b1b097cc9b68 100644
--- a/Documentation/devicetree/bindings/sound/simple-amplifier.txt
+++ b/Documentation/devicetree/bindings/sound/simple-amplifier.txt
@@ -2,9 +2,9 @@ Simple Amplifier Audio Driver
2 2
3Required properties: 3Required properties:
4- compatible : "dioo,dio2125" or "simple-audio-amplifier" 4- compatible : "dioo,dio2125" or "simple-audio-amplifier"
5- enable-gpios : the gpio connected to the enable pin of the simple amplifier
6 5
7Optional properties: 6Optional properties:
7- enable-gpios : the gpio connected to the enable pin of the simple amplifier
8- VCC-supply : power supply for the device, as covered 8- VCC-supply : power supply for the device, as covered
9 in Documentation/devicetree/bindings/regulator/regulator.txt 9 in Documentation/devicetree/bindings/regulator/regulator.txt
10 10
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index 4629c8f8a6b6..79954cd6e37b 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -24,6 +24,8 @@ Optional properties:
24 a microphone is attached. 24 a microphone is attached.
25- simple-audio-card,aux-devs : List of phandles pointing to auxiliary devices, such 25- simple-audio-card,aux-devs : List of phandles pointing to auxiliary devices, such
26 as amplifiers, to be added to the sound card. 26 as amplifiers, to be added to the sound card.
27- simple-audio-card,pin-switches : List of strings containing the widget names for
28 which pin switches must be created.
27 29
28Optional subnodes: 30Optional subnodes:
29 31
diff --git a/Documentation/devicetree/bindings/sound/sprd-mcdt.txt b/Documentation/devicetree/bindings/sound/sprd-mcdt.txt
new file mode 100644
index 000000000000..274ba0acbfd6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sprd-mcdt.txt
@@ -0,0 +1,19 @@
1Spreadtrum Multi-Channel Data Transfer Binding
2
3The Multi-channel data transfer controller is used for sound stream
4transmission between audio subsystem and other AP/CP subsystem. It
5supports 10 DAC channel and 10 ADC channel, and each channel can be
6configured with DMA mode or interrupt mode.
7
8Required properties:
9- compatible: Should be "sprd,sc9860-mcdt".
10- reg: Should contain registers address and length.
11- interrupts: Should contain one interrupt shared by all channel.
12
13Example:
14
15mcdt@41490000 {
16 compatible = "sprd,sc9860-mcdt";
17 reg = <0 0x41490000 0 0x170>;
18 interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
19};
diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
index 6b154dbb02cc..132f5eb9b530 100644
--- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
+++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
@@ -324,7 +324,7 @@ to details explained in the following section.
324 strcpy(card->driver, "My Chip"); 324 strcpy(card->driver, "My Chip");
325 strcpy(card->shortname, "My Own Chip 123"); 325 strcpy(card->shortname, "My Own Chip 123");
326 sprintf(card->longname, "%s at 0x%lx irq %i", 326 sprintf(card->longname, "%s at 0x%lx irq %i",
327 card->shortname, chip->ioport, chip->irq); 327 card->shortname, chip->port, chip->irq);
328 328
329 /* (5) */ 329 /* (5) */
330 .... /* implemented later */ 330 .... /* implemented later */
@@ -437,7 +437,7 @@ Since each component can be properly freed, the single
437 strcpy(card->driver, "My Chip"); 437 strcpy(card->driver, "My Chip");
438 strcpy(card->shortname, "My Own Chip 123"); 438 strcpy(card->shortname, "My Own Chip 123");
439 sprintf(card->longname, "%s at 0x%lx irq %i", 439 sprintf(card->longname, "%s at 0x%lx irq %i",
440 card->shortname, chip->ioport, chip->irq); 440 card->shortname, chip->port, chip->irq);
441 441
442The driver field holds the minimal ID string of the chip. This is used 442The driver field holds the minimal ID string of the chip. This is used
443by alsa-lib's configurator, so keep it simple but unique. Even the 443by alsa-lib's configurator, so keep it simple but unique. Even the
diff --git a/MAINTAINERS b/MAINTAINERS
index cdd21faa0d0f..a225661d6237 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3369,7 +3369,7 @@ F: include/uapi/linux/bsg.h
3369BT87X AUDIO DRIVER 3369BT87X AUDIO DRIVER
3370M: Clemens Ladisch <clemens@ladisch.de> 3370M: Clemens Ladisch <clemens@ladisch.de>
3371L: alsa-devel@alsa-project.org (moderated for non-subscribers) 3371L: alsa-devel@alsa-project.org (moderated for non-subscribers)
3372T: git git://git.alsa-project.org/alsa-kernel.git 3372T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
3373S: Maintained 3373S: Maintained
3374F: Documentation/sound/cards/bt87x.rst 3374F: Documentation/sound/cards/bt87x.rst
3375F: sound/pci/bt87x.c 3375F: sound/pci/bt87x.c
@@ -3422,7 +3422,7 @@ F: drivers/scsi/FlashPoint.*
3422C-MEDIA CMI8788 DRIVER 3422C-MEDIA CMI8788 DRIVER
3423M: Clemens Ladisch <clemens@ladisch.de> 3423M: Clemens Ladisch <clemens@ladisch.de>
3424L: alsa-devel@alsa-project.org (moderated for non-subscribers) 3424L: alsa-devel@alsa-project.org (moderated for non-subscribers)
3425T: git git://git.alsa-project.org/alsa-kernel.git 3425T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
3426S: Maintained 3426S: Maintained
3427F: sound/pci/oxygen/ 3427F: sound/pci/oxygen/
3428 3428
@@ -3818,6 +3818,7 @@ F: drivers/hwmon/lochnagar-hwmon.c
3818F: drivers/mfd/lochnagar-i2c.c 3818F: drivers/mfd/lochnagar-i2c.c
3819F: drivers/pinctrl/cirrus/pinctrl-lochnagar.c 3819F: drivers/pinctrl/cirrus/pinctrl-lochnagar.c
3820F: drivers/regulator/lochnagar-regulator.c 3820F: drivers/regulator/lochnagar-regulator.c
3821F: sound/soc/codecs/lochnagar-sc.c
3821F: include/dt-bindings/clk/lochnagar.h 3822F: include/dt-bindings/clk/lochnagar.h
3822F: include/dt-bindings/pinctrl/lochnagar.h 3823F: include/dt-bindings/pinctrl/lochnagar.h
3823F: include/linux/mfd/lochnagar* 3824F: include/linux/mfd/lochnagar*
@@ -3826,6 +3827,7 @@ F: Documentation/devicetree/bindings/clock/cirrus,lochnagar.txt
3826F: Documentation/devicetree/bindings/hwmon/cirrus,lochnagar.txt 3827F: Documentation/devicetree/bindings/hwmon/cirrus,lochnagar.txt
3827F: Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt 3828F: Documentation/devicetree/bindings/pinctrl/cirrus,lochnagar.txt
3828F: Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt 3829F: Documentation/devicetree/bindings/regulator/cirrus,lochnagar.txt
3830F: Documentation/devicetree/bindings/sound/cirrus,lochnagar.txt
3829F: Documentation/hwmon/lochnagar 3831F: Documentation/hwmon/lochnagar
3830 3832
3831CISCO FCOE HBA DRIVER 3833CISCO FCOE HBA DRIVER
@@ -5770,7 +5772,7 @@ F: drivers/edac/qcom_edac.c
5770EDIROL UA-101/UA-1000 DRIVER 5772EDIROL UA-101/UA-1000 DRIVER
5771M: Clemens Ladisch <clemens@ladisch.de> 5773M: Clemens Ladisch <clemens@ladisch.de>
5772L: alsa-devel@alsa-project.org (moderated for non-subscribers) 5774L: alsa-devel@alsa-project.org (moderated for non-subscribers)
5773T: git git://git.alsa-project.org/alsa-kernel.git 5775T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
5774S: Maintained 5776S: Maintained
5775F: sound/usb/misc/ua101.c 5777F: sound/usb/misc/ua101.c
5776 5778
@@ -6110,7 +6112,7 @@ F: include/linux/f75375s.h
6110FIREWIRE AUDIO DRIVERS 6112FIREWIRE AUDIO DRIVERS
6111M: Clemens Ladisch <clemens@ladisch.de> 6113M: Clemens Ladisch <clemens@ladisch.de>
6112L: alsa-devel@alsa-project.org (moderated for non-subscribers) 6114L: alsa-devel@alsa-project.org (moderated for non-subscribers)
6113T: git git://git.alsa-project.org/alsa-kernel.git 6115T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
6114S: Maintained 6116S: Maintained
6115F: sound/firewire/ 6117F: sound/firewire/
6116 6118
@@ -11700,7 +11702,7 @@ F: Documentation/devicetree/bindings/opp/
11700OPL4 DRIVER 11702OPL4 DRIVER
11701M: Clemens Ladisch <clemens@ladisch.de> 11703M: Clemens Ladisch <clemens@ladisch.de>
11702L: alsa-devel@alsa-project.org (moderated for non-subscribers) 11704L: alsa-devel@alsa-project.org (moderated for non-subscribers)
11703T: git git://git.alsa-project.org/alsa-kernel.git 11705T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
11704S: Maintained 11706S: Maintained
11705F: sound/drivers/opl4/ 11707F: sound/drivers/opl4/
11706 11708
@@ -14610,7 +14612,6 @@ M: Takashi Iwai <tiwai@suse.com>
14610L: alsa-devel@alsa-project.org (moderated for non-subscribers) 14612L: alsa-devel@alsa-project.org (moderated for non-subscribers)
14611W: http://www.alsa-project.org/ 14613W: http://www.alsa-project.org/
14612T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git 14614T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
14613T: git git://git.alsa-project.org/alsa-kernel.git
14614Q: http://patchwork.kernel.org/project/alsa-devel/list/ 14615Q: http://patchwork.kernel.org/project/alsa-devel/list/
14615S: Maintained 14616S: Maintained
14616F: Documentation/sound/ 14617F: Documentation/sound/
@@ -16256,7 +16257,7 @@ F: drivers/usb/storage/
16256USB MIDI DRIVER 16257USB MIDI DRIVER
16257M: Clemens Ladisch <clemens@ladisch.de> 16258M: Clemens Ladisch <clemens@ladisch.de>
16258L: alsa-devel@alsa-project.org (moderated for non-subscribers) 16259L: alsa-devel@alsa-project.org (moderated for non-subscribers)
16259T: git git://git.alsa-project.org/alsa-kernel.git 16260T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
16260S: Maintained 16261S: Maintained
16261F: sound/usb/midi.* 16262F: sound/usb/midi.*
16262 16263
diff --git a/include/sound/core.h b/include/sound/core.h
index e923c23e05dd..c90ebbc8d9c4 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -226,7 +226,6 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
226 226
227/* init.c */ 227/* init.c */
228 228
229extern struct snd_card *snd_cards[SNDRV_CARDS];
230int snd_card_locked(int card); 229int snd_card_locked(int card);
231#if IS_ENABLED(CONFIG_SND_MIXER_OSS) 230#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
232#define SND_MIXER_OSS_NOTIFY_REGISTER 0 231#define SND_MIXER_OSS_NOTIFY_REGISTER 0
@@ -251,7 +250,20 @@ int snd_card_add_dev_attr(struct snd_card *card,
251int snd_component_add(struct snd_card *card, const char *component); 250int snd_component_add(struct snd_card *card, const char *component);
252int snd_card_file_add(struct snd_card *card, struct file *file); 251int snd_card_file_add(struct snd_card *card, struct file *file);
253int snd_card_file_remove(struct snd_card *card, struct file *file); 252int snd_card_file_remove(struct snd_card *card, struct file *file);
254#define snd_card_unref(card) put_device(&(card)->card_dev) 253
254struct snd_card *snd_card_ref(int card);
255
256/**
257 * snd_card_unref - Unreference the card object
258 * @card: the card object to unreference
259 *
260 * Call this function for the card object that was obtained via snd_card_ref()
261 * or snd_lookup_minor_data().
262 */
263static inline void snd_card_unref(struct snd_card *card)
264{
265 put_device(&card->card_dev);
266}
255 267
256#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) 268#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
257 269
diff --git a/include/sound/da7219.h b/include/sound/da7219.h
index 1bfcb16f2d10..4a36954c86c5 100644
--- a/include/sound/da7219.h
+++ b/include/sound/da7219.h
@@ -33,10 +33,16 @@ enum da7219_mic_amp_in_sel {
33 33
34struct da7219_aad_pdata; 34struct da7219_aad_pdata;
35 35
36enum da7219_dai_clks {
37 DA7219_DAI_WCLK_IDX = 0,
38 DA7219_DAI_BCLK_IDX,
39 DA7219_DAI_NUM_CLKS,
40};
41
36struct da7219_pdata { 42struct da7219_pdata {
37 bool wakeup_source; 43 bool wakeup_source;
38 44
39 const char *dai_clks_name; 45 const char *dai_clk_names[DA7219_DAI_NUM_CLKS];
40 46
41 /* Mic */ 47 /* Mic */
42 enum da7219_micbias_voltage micbias_lvl; 48 enum da7219_micbias_voltage micbias_lvl;
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 06f504c10b80..896c3f45503b 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -297,7 +297,7 @@ struct hdac_rb {
297 * @num_streams: streams supported 297 * @num_streams: streams supported
298 * @idx: HDA link index 298 * @idx: HDA link index
299 * @hlink_list: link list of HDA links 299 * @hlink_list: link list of HDA links
300 * @lock: lock for link mgmt 300 * @lock: lock for link and display power mgmt
301 * @cmd_dma_state: state of cmd DMAs: CORB and RIRB 301 * @cmd_dma_state: state of cmd DMAs: CORB and RIRB
302 */ 302 */
303struct hdac_bus { 303struct hdac_bus {
@@ -363,6 +363,7 @@ struct hdac_bus {
363 /* locks */ 363 /* locks */
364 spinlock_t reg_lock; 364 spinlock_t reg_lock;
365 struct mutex cmd_mutex; 365 struct mutex cmd_mutex;
366 struct mutex lock;
366 367
367 /* DRM component interface */ 368 /* DRM component interface */
368 struct drm_audio_component *audio_component; 369 struct drm_audio_component *audio_component;
@@ -373,11 +374,9 @@ struct hdac_bus {
373 int num_streams; 374 int num_streams;
374 int idx; 375 int idx;
375 376
377 /* link management */
376 struct list_head hlink_list; 378 struct list_head hlink_list;
377
378 struct mutex lock;
379 bool cmd_dma_state; 379 bool cmd_dma_state;
380
381}; 380};
382 381
383int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, 382int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index 1ac0dd82a916..4c6f3b5a7cff 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -151,9 +151,5 @@ int snd_dma_alloc_pages_fallback(int type, struct device *dev, size_t size,
151 struct snd_dma_buffer *dmab); 151 struct snd_dma_buffer *dmab);
152void snd_dma_free_pages(struct snd_dma_buffer *dmab); 152void snd_dma_free_pages(struct snd_dma_buffer *dmab);
153 153
154/* basic memory allocation functions */
155void *snd_malloc_pages(size_t size, gfp_t gfp_flags);
156void snd_free_pages(void *ptr, size_t size);
157
158#endif /* __SOUND_MEMALLOC_H */ 154#endif /* __SOUND_MEMALLOC_H */
159 155
diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h
index 4b9ee3009aa0..c7a5433e109a 100644
--- a/include/sound/seq_kernel.h
+++ b/include/sound/seq_kernel.h
@@ -73,7 +73,8 @@ __printf(3, 4)
73int snd_seq_create_kernel_client(struct snd_card *card, int client_index, 73int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
74 const char *name_fmt, ...); 74 const char *name_fmt, ...);
75int snd_seq_delete_kernel_client(int client); 75int snd_seq_delete_kernel_client(int client);
76int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, int atomic, int hop); 76int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
77 struct file *file, bool blocking);
77int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event *ev, int atomic, int hop); 78int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event *ev, int atomic, int hop);
78int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void *arg); 79int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void *arg);
79 80
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 7afe45389972..3429888347e7 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -10,10 +10,10 @@
10 10
11#include <sound/soc.h> 11#include <sound/soc.h>
12 12
13#define asoc_simple_card_init_hp(card, sjack, prefix) \ 13#define asoc_simple_init_hp(card, sjack, prefix) \
14 asoc_simple_card_init_jack(card, sjack, 1, prefix) 14 asoc_simple_init_jack(card, sjack, 1, prefix)
15#define asoc_simple_card_init_mic(card, sjack, prefix) \ 15#define asoc_simple_init_mic(card, sjack, prefix) \
16 asoc_simple_card_init_jack(card, sjack, 0, prefix) 16 asoc_simple_init_jack(card, sjack, 0, prefix)
17 17
18struct asoc_simple_dai { 18struct asoc_simple_dai {
19 const char *name; 19 const char *name;
@@ -26,7 +26,7 @@ struct asoc_simple_dai {
26 struct clk *clk; 26 struct clk *clk;
27}; 27};
28 28
29struct asoc_simple_card_data { 29struct asoc_simple_data {
30 u32 convert_rate; 30 u32 convert_rate;
31 u32 convert_channels; 31 u32 convert_channels;
32}; 32};
@@ -37,96 +37,180 @@ struct asoc_simple_jack {
37 struct snd_soc_jack_gpio gpio; 37 struct snd_soc_jack_gpio gpio;
38}; 38};
39 39
40int asoc_simple_card_parse_daifmt(struct device *dev, 40struct asoc_simple_priv {
41 struct device_node *node, 41 struct snd_soc_card snd_card;
42 struct device_node *codec, 42 struct simple_dai_props {
43 char *prefix, 43 struct asoc_simple_dai *cpu_dai;
44 unsigned int *retfmt); 44 struct asoc_simple_dai *codec_dai;
45 struct snd_soc_dai_link_component codecs; /* single codec */
46 struct snd_soc_dai_link_component platforms;
47 struct asoc_simple_data adata;
48 struct snd_soc_codec_conf *codec_conf;
49 unsigned int mclk_fs;
50 } *dai_props;
51 struct asoc_simple_jack hp_jack;
52 struct asoc_simple_jack mic_jack;
53 struct snd_soc_dai_link *dai_link;
54 struct asoc_simple_dai *dais;
55 struct snd_soc_codec_conf *codec_conf;
56 struct gpio_desc *pa_gpio;
57};
58#define simple_priv_to_card(priv) (&(priv)->snd_card)
59#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
60#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
61#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
62
63struct link_info {
64 int dais; /* number of dai */
65 int link; /* number of link */
66 int conf; /* number of codec_conf */
67 int cpu; /* turn for CPU / Codec */
68};
69
70int asoc_simple_parse_daifmt(struct device *dev,
71 struct device_node *node,
72 struct device_node *codec,
73 char *prefix,
74 unsigned int *retfmt);
45__printf(3, 4) 75__printf(3, 4)
46int asoc_simple_card_set_dailink_name(struct device *dev, 76int asoc_simple_set_dailink_name(struct device *dev,
47 struct snd_soc_dai_link *dai_link, 77 struct snd_soc_dai_link *dai_link,
48 const char *fmt, ...); 78 const char *fmt, ...);
49int asoc_simple_card_parse_card_name(struct snd_soc_card *card, 79int asoc_simple_parse_card_name(struct snd_soc_card *card,
50 char *prefix); 80 char *prefix);
51 81
52#define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai) \ 82#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \
53 asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \ 83 asoc_simple_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
54 dai_link->cpu_dai_name, NULL) 84 dai_link->cpu_dai_name, NULL)
55#define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai) \ 85#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \
56 asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\ 86 asoc_simple_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
57 dai_link->codec_dai_name, dai_link->codecs) 87 dai_link->codec_dai_name, dai_link->codecs)
58int asoc_simple_card_parse_clk(struct device *dev, 88int asoc_simple_parse_clk(struct device *dev,
59 struct device_node *node, 89 struct device_node *node,
60 struct device_node *dai_of_node, 90 struct device_node *dai_of_node,
61 struct asoc_simple_dai *simple_dai, 91 struct asoc_simple_dai *simple_dai,
62 const char *dai_name, 92 const char *dai_name,
63 struct snd_soc_dai_link_component *dlc); 93 struct snd_soc_dai_link_component *dlc);
64int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai); 94int asoc_simple_startup(struct snd_pcm_substream *substream);
65void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); 95void asoc_simple_shutdown(struct snd_pcm_substream *substream);
66 96int asoc_simple_hw_params(struct snd_pcm_substream *substream,
67#define asoc_simple_card_parse_cpu(node, dai_link, \ 97 struct snd_pcm_hw_params *params);
68 list_name, cells_name, is_single_link) \ 98int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd);
69 asoc_simple_card_parse_dai(node, NULL, \ 99int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
70 &dai_link->cpu_of_node, \ 100 struct snd_pcm_hw_params *params);
71 &dai_link->cpu_dai_name, list_name, cells_name, is_single_link) 101
72#define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name) \ 102#define asoc_simple_parse_cpu(node, dai_link, is_single_link) \
73 asoc_simple_card_parse_dai(node, dai_link->codecs, \ 103 asoc_simple_parse_dai(node, NULL, \
104 &dai_link->cpu_of_node, \
105 &dai_link->cpu_dai_name, is_single_link)
106#define asoc_simple_parse_codec(node, dai_link) \
107 asoc_simple_parse_dai(node, dai_link->codecs, \
74 &dai_link->codec_of_node, \ 108 &dai_link->codec_of_node, \
75 &dai_link->codec_dai_name, \ 109 &dai_link->codec_dai_name, NULL)
76 list_name, cells_name, NULL) 110#define asoc_simple_parse_platform(node, dai_link) \
77#define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ 111 asoc_simple_parse_dai(node, dai_link->platforms, \
78 asoc_simple_card_parse_dai(node, dai_link->platforms, \ 112 &dai_link->platform_of_node, NULL, NULL)
79 &dai_link->platform_of_node, \ 113
80 NULL, list_name, cells_name, NULL) 114#define asoc_simple_parse_tdm(np, dai) \
81int asoc_simple_card_parse_dai(struct device_node *node,
82 struct snd_soc_dai_link_component *dlc,
83 struct device_node **endpoint_np,
84 const char **dai_name,
85 const char *list_name,
86 const char *cells_name,
87 int *is_single_links);
88
89#define asoc_simple_card_parse_graph_cpu(ep, dai_link) \
90 asoc_simple_card_parse_graph_dai(ep, NULL, \
91 &dai_link->cpu_of_node, \
92 &dai_link->cpu_dai_name)
93#define asoc_simple_card_parse_graph_codec(ep, dai_link) \
94 asoc_simple_card_parse_graph_dai(ep, dai_link->codecs, \
95 &dai_link->codec_of_node, \
96 &dai_link->codec_dai_name)
97int asoc_simple_card_parse_graph_dai(struct device_node *ep,
98 struct snd_soc_dai_link_component *dlc,
99 struct device_node **endpoint_np,
100 const char **dai_name);
101
102#define asoc_simple_card_of_parse_tdm(np, dai) \
103 snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \ 115 snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \
104 &(dai)->rx_slot_mask, \ 116 &(dai)->rx_slot_mask, \
105 &(dai)->slots, \ 117 &(dai)->slots, \
106 &(dai)->slot_width); 118 &(dai)->slot_width);
107 119
108int asoc_simple_card_init_dai(struct snd_soc_dai *dai, 120void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link);
109 struct asoc_simple_dai *simple_dai); 121void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
110
111void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link);
112void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
113 int is_single_links); 122 int is_single_links);
114 123
115int asoc_simple_card_clean_reference(struct snd_soc_card *card); 124int asoc_simple_clean_reference(struct snd_soc_card *card);
116 125
117void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, 126void asoc_simple_convert_fixup(struct asoc_simple_data *data,
118 struct snd_pcm_hw_params *params); 127 struct snd_pcm_hw_params *params);
119void asoc_simple_card_parse_convert(struct device *dev, 128void asoc_simple_parse_convert(struct device *dev,
120 struct device_node *np, char *prefix, 129 struct device_node *np, char *prefix,
121 struct asoc_simple_card_data *data); 130 struct asoc_simple_data *data);
122 131
123int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, 132int asoc_simple_parse_routing(struct snd_soc_card *card,
124 char *prefix); 133 char *prefix);
125int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card, 134int asoc_simple_parse_widgets(struct snd_soc_card *card,
126 char *prefix); 135 char *prefix);
136int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
137 char *prefix);
127 138
128int asoc_simple_card_init_jack(struct snd_soc_card *card, 139int asoc_simple_init_jack(struct snd_soc_card *card,
129 struct asoc_simple_jack *sjack, 140 struct asoc_simple_jack *sjack,
130 int is_hp, char *prefix); 141 int is_hp, char *prefix);
142int asoc_simple_init_priv(struct asoc_simple_priv *priv,
143 struct link_info *li);
144
145#ifdef DEBUG
146inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
147 char *name,
148 struct asoc_simple_dai *dai)
149{
150 struct device *dev = simple_priv_to_dev(priv);
151
152 if (dai->name)
153 dev_dbg(dev, "%s dai name = %s\n",
154 name, dai->name);
155 if (dai->sysclk)
156 dev_dbg(dev, "%s sysclk = %d\n",
157 name, dai->sysclk);
158
159 dev_dbg(dev, "%s direction = %s\n",
160 name, dai->clk_direction ? "OUT" : "IN");
161
162 if (dai->slots)
163 dev_dbg(dev, "%s slots = %d\n", name, dai->slots);
164 if (dai->slot_width)
165 dev_dbg(dev, "%s slot width = %d\n", name, dai->slot_width);
166 if (dai->tx_slot_mask)
167 dev_dbg(dev, "%s tx slot mask = %d\n", name, dai->tx_slot_mask);
168 if (dai->rx_slot_mask)
169 dev_dbg(dev, "%s rx slot mask = %d\n", name, dai->rx_slot_mask);
170 if (dai->clk)
171 dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk));
172}
173
174inline void asoc_simple_debug_info(struct asoc_simple_priv *priv)
175{
176 struct snd_soc_card *card = simple_priv_to_card(priv);
177 struct device *dev = simple_priv_to_dev(priv);
178
179 int i;
180
181 if (card->name)
182 dev_dbg(dev, "Card Name: %s\n", card->name);
183
184 for (i = 0; i < card->num_links; i++) {
185 struct simple_dai_props *props = simple_priv_to_props(priv, i);
186 struct snd_soc_dai_link *link = simple_priv_to_link(priv, i);
187
188 dev_dbg(dev, "DAI%d\n", i);
189
190 asoc_simple_debug_dai(priv, "cpu", props->cpu_dai);
191 asoc_simple_debug_dai(priv, "codec", props->codec_dai);
192
193 if (link->name)
194 dev_dbg(dev, "dai name = %s\n", link->name);
195
196 dev_dbg(dev, "dai format = %04x\n", link->dai_fmt);
197
198 if (props->adata.convert_rate)
199 dev_dbg(dev, "convert_rate = %d\n",
200 props->adata.convert_rate);
201 if (props->adata.convert_channels)
202 dev_dbg(dev, "convert_channels = %d\n",
203 props->adata.convert_channels);
204 if (props->codec_conf && props->codec_conf->name_prefix)
205 dev_dbg(dev, "name prefix = %s\n",
206 props->codec_conf->name_prefix);
207 if (props->mclk_fs)
208 dev_dbg(dev, "mclk-fs = %d\n",
209 props->mclk_fs);
210 }
211}
212#else
213#define asoc_simple_debug_info(priv)
214#endif /* DEBUG */
131 215
132#endif /* __SIMPLE_CARD_UTILS_H */ 216#endif /* __SIMPLE_CARD_UTILS_H */
diff --git a/include/sound/sof.h b/include/sound/sof.h
new file mode 100644
index 000000000000..4640566b54fe
--- /dev/null
+++ b/include/sound/sof.h
@@ -0,0 +1,100 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 *
8 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 */
10
11#ifndef __INCLUDE_SOUND_SOF_H
12#define __INCLUDE_SOUND_SOF_H
13
14#include <linux/pci.h>
15#include <sound/soc.h>
16#include <sound/soc-acpi.h>
17
18struct snd_sof_dsp_ops;
19
20/*
21 * SOF Platform data.
22 */
23struct snd_sof_pdata {
24 const struct firmware *fw;
25 const char *drv_name;
26 const char *name;
27 const char *platform;
28
29 struct device *dev;
30
31 /*
32 * notification callback used if the hardware initialization
33 * can take time or is handled in a workqueue. This callback
34 * can be used by the caller to e.g. enable runtime_pm
35 * or limit functionality until all low-level inits are
36 * complete.
37 */
38 void (*sof_probe_complete)(struct device *dev);
39
40 /* descriptor */
41 const struct sof_dev_desc *desc;
42
43 /* firmware and topology filenames */
44 const char *fw_filename_prefix;
45 const char *fw_filename;
46 const char *tplg_filename_prefix;
47 const char *tplg_filename;
48
49 /* machine */
50 struct platform_device *pdev_mach;
51 const struct snd_soc_acpi_mach *machine;
52
53 void *hw_pdata;
54};
55
56/*
57 * Descriptor used for setting up SOF platform data. This is used when
58 * ACPI/PCI data is missing or mapped differently.
59 */
60struct sof_dev_desc {
61 /* list of machines using this configuration */
62 struct snd_soc_acpi_mach *machines;
63
64 /* Platform resource indexes in BAR / ACPI resources. */
65 /* Must set to -1 if not used - add new items to end */
66 int resindex_lpe_base;
67 int resindex_pcicfg_base;
68 int resindex_imr_base;
69 int irqindex_host_ipc;
70 int resindex_dma_base;
71
72 /* DMA only valid when resindex_dma_base != -1*/
73 int dma_engine;
74 int dma_size;
75
76 /* IPC timeouts in ms */
77 int ipc_timeout;
78 int boot_timeout;
79
80 /* chip information for dsp */
81 const void *chip_info;
82
83 /* defaults for no codec mode */
84 const char *nocodec_fw_filename;
85 const char *nocodec_tplg_filename;
86
87 /* defaults paths for firmware and topology files */
88 const char *default_fw_path;
89 const char *default_tplg_path;
90
91 const struct snd_sof_dsp_ops *ops;
92 const struct sof_arch_ops *arch_ops;
93};
94
95int sof_nocodec_setup(struct device *dev,
96 struct snd_sof_pdata *sof_pdata,
97 struct snd_soc_acpi_mach *mach,
98 const struct sof_dev_desc *desc,
99 const struct snd_sof_dsp_ops *ops);
100#endif
diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h
new file mode 100644
index 000000000000..bded69e696d4
--- /dev/null
+++ b/include/sound/sof/control.h
@@ -0,0 +1,158 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_CONTROL_H__
10#define __INCLUDE_SOUND_SOF_CONTROL_H__
11
12#include <uapi/sound/sof/header.h>
13#include <sound/sof/header.h>
14
15/*
16 * Component Mixers and Controls
17 */
18
19/* channel positions - uses same values as ALSA */
20enum sof_ipc_chmap {
21 SOF_CHMAP_UNKNOWN = 0,
22 SOF_CHMAP_NA, /**< N/A, silent */
23 SOF_CHMAP_MONO, /**< mono stream */
24 SOF_CHMAP_FL, /**< front left */
25 SOF_CHMAP_FR, /**< front right */
26 SOF_CHMAP_RL, /**< rear left */
27 SOF_CHMAP_RR, /**< rear right */
28 SOF_CHMAP_FC, /**< front centre */
29 SOF_CHMAP_LFE, /**< LFE */
30 SOF_CHMAP_SL, /**< side left */
31 SOF_CHMAP_SR, /**< side right */
32 SOF_CHMAP_RC, /**< rear centre */
33 SOF_CHMAP_FLC, /**< front left centre */
34 SOF_CHMAP_FRC, /**< front right centre */
35 SOF_CHMAP_RLC, /**< rear left centre */
36 SOF_CHMAP_RRC, /**< rear right centre */
37 SOF_CHMAP_FLW, /**< front left wide */
38 SOF_CHMAP_FRW, /**< front right wide */
39 SOF_CHMAP_FLH, /**< front left high */
40 SOF_CHMAP_FCH, /**< front centre high */
41 SOF_CHMAP_FRH, /**< front right high */
42 SOF_CHMAP_TC, /**< top centre */
43 SOF_CHMAP_TFL, /**< top front left */
44 SOF_CHMAP_TFR, /**< top front right */
45 SOF_CHMAP_TFC, /**< top front centre */
46 SOF_CHMAP_TRL, /**< top rear left */
47 SOF_CHMAP_TRR, /**< top rear right */
48 SOF_CHMAP_TRC, /**< top rear centre */
49 SOF_CHMAP_TFLC, /**< top front left centre */
50 SOF_CHMAP_TFRC, /**< top front right centre */
51 SOF_CHMAP_TSL, /**< top side left */
52 SOF_CHMAP_TSR, /**< top side right */
53 SOF_CHMAP_LLFE, /**< left LFE */
54 SOF_CHMAP_RLFE, /**< right LFE */
55 SOF_CHMAP_BC, /**< bottom centre */
56 SOF_CHMAP_BLC, /**< bottom left centre */
57 SOF_CHMAP_BRC, /**< bottom right centre */
58 SOF_CHMAP_LAST = SOF_CHMAP_BRC,
59};
60
61/* control data type and direction */
62enum sof_ipc_ctrl_type {
63 /* per channel data - uses struct sof_ipc_ctrl_value_chan */
64 SOF_CTRL_TYPE_VALUE_CHAN_GET = 0,
65 SOF_CTRL_TYPE_VALUE_CHAN_SET,
66 /* component data - uses struct sof_ipc_ctrl_value_comp */
67 SOF_CTRL_TYPE_VALUE_COMP_GET,
68 SOF_CTRL_TYPE_VALUE_COMP_SET,
69 /* bespoke data - uses struct sof_abi_hdr */
70 SOF_CTRL_TYPE_DATA_GET,
71 SOF_CTRL_TYPE_DATA_SET,
72};
73
74/* control command type */
75enum sof_ipc_ctrl_cmd {
76 SOF_CTRL_CMD_VOLUME = 0, /**< maps to ALSA volume style controls */
77 SOF_CTRL_CMD_ENUM, /**< maps to ALSA enum style controls */
78 SOF_CTRL_CMD_SWITCH, /**< maps to ALSA switch style controls */
79 SOF_CTRL_CMD_BINARY, /**< maps to ALSA binary style controls */
80};
81
82/* generic channel mapped value data */
83struct sof_ipc_ctrl_value_chan {
84 uint32_t channel; /**< channel map - enum sof_ipc_chmap */
85 uint32_t value;
86} __packed;
87
88/* generic component mapped value data */
89struct sof_ipc_ctrl_value_comp {
90 uint32_t index; /**< component source/sink/control index in control */
91 union {
92 uint32_t uvalue;
93 int32_t svalue;
94 };
95} __packed;
96
97/* generic control data */
98struct sof_ipc_ctrl_data {
99 struct sof_ipc_reply rhdr;
100 uint32_t comp_id;
101
102 /* control access and data type */
103 uint32_t type; /**< enum sof_ipc_ctrl_type */
104 uint32_t cmd; /**< enum sof_ipc_ctrl_cmd */
105 uint32_t index; /**< control index for comps > 1 control */
106
107 /* control data - can either be appended or DMAed from host */
108 struct sof_ipc_host_buffer buffer;
109 uint32_t num_elems; /**< in array elems or bytes for data type */
110 uint32_t elems_remaining; /**< elems remaining if sent in parts */
111
112 uint32_t msg_index; /**< for large messages sent in parts */
113
114 /* reserved for future use */
115 uint32_t reserved[6];
116
117 /* control data - add new types if needed */
118 union {
119 /* channel values can be used by volume type controls */
120 struct sof_ipc_ctrl_value_chan chanv[0];
121 /* component values used by routing controls like mux, mixer */
122 struct sof_ipc_ctrl_value_comp compv[0];
123 /* data can be used by binary controls */
124 struct sof_abi_hdr data[0];
125 };
126} __packed;
127
128/** Event type */
129enum sof_ipc_ctrl_event_type {
130 SOF_CTRL_EVENT_GENERIC = 0, /**< generic event */
131 SOF_CTRL_EVENT_GENERIC_METADATA, /**< generic event with metadata */
132 SOF_CTRL_EVENT_KD, /**< keyword detection event */
133 SOF_CTRL_EVENT_VAD, /**< voice activity detection event */
134};
135
136/**
137 * Generic notification data.
138 */
139struct sof_ipc_comp_event {
140 struct sof_ipc_reply rhdr;
141 uint16_t src_comp_type; /**< COMP_TYPE_ */
142 uint32_t src_comp_id; /**< source component id */
143 uint32_t event_type; /**< event type - SOF_CTRL_EVENT_* */
144 uint32_t num_elems; /**< in array elems or bytes for data type */
145
146 /* reserved for future use */
147 uint32_t reserved[8];
148
149 /* control data - add new types if needed */
150 union {
151 /* data can be used by binary controls */
152 struct sof_abi_hdr data[0];
153 /* event specific values */
154 uint32_t event_value;
155 };
156} __packed;
157
158#endif
diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h
new file mode 100644
index 000000000000..4bd83f7adddf
--- /dev/null
+++ b/include/sound/sof/dai-intel.h
@@ -0,0 +1,178 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_DAI_INTEL_H__
10#define __INCLUDE_SOUND_SOF_DAI_INTEL_H__
11
12#include <sound/sof/header.h>
13
14 /* ssc1: TINTE */
15#define SOF_DAI_INTEL_SSP_QUIRK_TINTE (1 << 0)
16 /* ssc1: PINTE */
17#define SOF_DAI_INTEL_SSP_QUIRK_PINTE (1 << 1)
18 /* ssc2: SMTATF */
19#define SOF_DAI_INTEL_SSP_QUIRK_SMTATF (1 << 2)
20 /* ssc2: MMRATF */
21#define SOF_DAI_INTEL_SSP_QUIRK_MMRATF (1 << 3)
22 /* ssc2: PSPSTWFDFD */
23#define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD (1 << 4)
24 /* ssc2: PSPSRWFDFD */
25#define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD (1 << 5)
26/* ssc1: LBM */
27#define SOF_DAI_INTEL_SSP_QUIRK_LBM (1 << 6)
28
29 /* here is the possibility to define others aux macros */
30
31#define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX 38
32#define SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX 31
33
34/* SSP clocks control settings
35 *
36 * Macros for clks_control field in sof_ipc_dai_ssp_params struct.
37 */
38
39/* mclk 0 disable */
40#define SOF_DAI_INTEL_SSP_MCLK_0_DISABLE BIT(0)
41/* mclk 1 disable */
42#define SOF_DAI_INTEL_SSP_MCLK_1_DISABLE BIT(1)
43/* mclk keep active */
44#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_KA BIT(2)
45/* bclk keep active */
46#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_KA BIT(3)
47/* fs keep active */
48#define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4)
49/* bclk idle */
50#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5)
51
52/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */
53struct sof_ipc_dai_ssp_params {
54 struct sof_ipc_hdr hdr;
55 uint16_t reserved1;
56 uint16_t mclk_id;
57
58 uint32_t mclk_rate; /* mclk frequency in Hz */
59 uint32_t fsync_rate; /* fsync frequency in Hz */
60 uint32_t bclk_rate; /* bclk frequency in Hz */
61
62 /* TDM */
63 uint32_t tdm_slots;
64 uint32_t rx_slots;
65 uint32_t tx_slots;
66
67 /* data */
68 uint32_t sample_valid_bits;
69 uint16_t tdm_slot_width;
70 uint16_t reserved2; /* alignment */
71
72 /* MCLK */
73 uint32_t mclk_direction;
74
75 uint16_t frame_pulse_width;
76 uint16_t tdm_per_slot_padding_flag;
77 uint32_t clks_control;
78 uint32_t quirks;
79} __packed;
80
81/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */
82struct sof_ipc_dai_hda_params {
83 struct sof_ipc_hdr hdr;
84 uint32_t link_dma_ch;
85} __packed;
86
87/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */
88
89/* This struct is defined per 2ch PDM controller available in the platform.
90 * Normally it is sufficient to set the used microphone specific enables to 1
91 * and keep other parameters as zero. The customizations are:
92 *
93 * 1. If a device mixes different microphones types with different polarity
94 * and/or the absolute polarity matters the PCM signal from a microphone
95 * can be inverted with the controls.
96 *
97 * 2. If the microphones in a stereo pair do not appear in captured stream
98 * in desired order due to board schematics choises they can be swapped with
99 * the clk_edge parameter.
100 *
101 * 3. If PDM bit errors are seen in capture (poor quality) the skew parameter
102 * that delays the sampling time of data by half cycles of DMIC source clock
103 * can be tried for improvement. However there is no guarantee for this to fix
104 * data integrity problems.
105 */
106struct sof_ipc_dai_dmic_pdm_ctrl {
107 struct sof_ipc_hdr hdr;
108 uint16_t id; /**< PDM controller ID */
109
110 uint16_t enable_mic_a; /**< Use A (left) channel mic (0 or 1)*/
111 uint16_t enable_mic_b; /**< Use B (right) channel mic (0 or 1)*/
112
113 uint16_t polarity_mic_a; /**< Optionally invert mic A signal (0 or 1) */
114 uint16_t polarity_mic_b; /**< Optionally invert mic B signal (0 or 1) */
115
116 uint16_t clk_edge; /**< Optionally swap data clock edge (0 or 1) */
117 uint16_t skew; /**< Adjust PDM data sampling vs. clock (0..15) */
118
119 uint16_t reserved[3]; /**< Make sure the total size is 4 bytes aligned */
120} __packed;
121
122/* This struct contains the global settings for all 2ch PDM controllers. The
123 * version number used in configuration data is checked vs. version used by
124 * device driver src/drivers/dmic.c need to match. It is incremented from
125 * initial value 1 if updates done for the to driver would alter the operation
126 * of the microhone.
127 *
128 * Note: The microphone clock (pdmclk_min, pdmclk_max, duty_min, duty_max)
129 * parameters need to be set as defined in microphone data sheet. E.g. clock
130 * range 1.0 - 3.2 MHz is usually supported microphones. Some microphones are
131 * multi-mode capable and there may be denied mic clock frequencies between
132 * the modes. In such case set the clock range limits of the desired mode to
133 * avoid the driver to set clock to an illegal rate.
134 *
135 * The duty cycle could be set to 48-52% if not known. Generally these
136 * parameters can be altered within data sheet specified limits to match
137 * required audio application performance power.
138 *
139 * The microphone clock needs to be usually about 50-80 times the used audio
140 * sample rate. With highest sample rates above 48 kHz this can relaxed
141 * somewhat.
142 *
143 * The parameter wake_up_time describes how long time the microphone needs
144 * for the data line to produce valid output from mic clock start. The driver
145 * will mute the captured audio for the given time. The min_clock_on_time
146 * parameter is used to prevent too short clock bursts to happen. The driver
147 * will keep the clock active after capture stop if this time is not yet
148 * met. The unit for both is microseconds (us). Exceed of 100 ms will be
149 * treated as an error.
150 */
151struct sof_ipc_dai_dmic_params {
152 struct sof_ipc_hdr hdr;
153 uint32_t driver_ipc_version; /**< Version (1..N) */
154
155 uint32_t pdmclk_min; /**< Minimum microphone clock in Hz (100000..N) */
156 uint32_t pdmclk_max; /**< Maximum microphone clock in Hz (min...N) */
157
158 uint32_t fifo_fs; /**< FIFO sample rate in Hz (8000..96000) */
159 uint32_t reserved_1; /**< Reserved */
160 uint16_t fifo_bits; /**< FIFO word length (16 or 32) */
161 uint16_t reserved_2; /**< Reserved */
162
163 uint16_t duty_min; /**< Min. mic clock duty cycle in % (20..80) */
164 uint16_t duty_max; /**< Max. mic clock duty cycle in % (min..80) */
165
166 uint32_t num_pdm_active; /**< Number of active pdm controllers */
167
168 uint32_t wake_up_time; /**< Time from clock start to data (us) */
169 uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */
170
171 /* reserved for future use */
172 uint32_t reserved[6];
173
174 /**< variable number of pdm controller config */
175 struct sof_ipc_dai_dmic_pdm_ctrl pdm[0];
176} __packed;
177
178#endif
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
new file mode 100644
index 000000000000..3b67c93ff101
--- /dev/null
+++ b/include/sound/sof/dai.h
@@ -0,0 +1,75 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_DAI_H__
10#define __INCLUDE_SOUND_SOF_DAI_H__
11
12#include <sound/sof/header.h>
13#include <sound/sof/dai-intel.h>
14
15/*
16 * DAI Configuration.
17 *
18 * Each different DAI type will have it's own structure and IPC cmd.
19 */
20
21#define SOF_DAI_FMT_I2S 1 /**< I2S mode */
22#define SOF_DAI_FMT_RIGHT_J 2 /**< Right Justified mode */
23#define SOF_DAI_FMT_LEFT_J 3 /**< Left Justified mode */
24#define SOF_DAI_FMT_DSP_A 4 /**< L data MSB after FRM LRC */
25#define SOF_DAI_FMT_DSP_B 5 /**< L data MSB during FRM LRC */
26#define SOF_DAI_FMT_PDM 6 /**< Pulse density modulation */
27
28#define SOF_DAI_FMT_CONT (1 << 4) /**< continuous clock */
29#define SOF_DAI_FMT_GATED (0 << 4) /**< clock is gated */
30
31#define SOF_DAI_FMT_NB_NF (0 << 8) /**< normal bit clock + frame */
32#define SOF_DAI_FMT_NB_IF (2 << 8) /**< normal BCLK + inv FRM */
33#define SOF_DAI_FMT_IB_NF (3 << 8) /**< invert BCLK + nor FRM */
34#define SOF_DAI_FMT_IB_IF (4 << 8) /**< invert BCLK + FRM */
35
36#define SOF_DAI_FMT_CBM_CFM (0 << 12) /**< codec clk & FRM master */
37#define SOF_DAI_FMT_CBS_CFM (2 << 12) /**< codec clk slave & FRM master */
38#define SOF_DAI_FMT_CBM_CFS (3 << 12) /**< codec clk master & frame slave */
39#define SOF_DAI_FMT_CBS_CFS (4 << 12) /**< codec clk & FRM slave */
40
41#define SOF_DAI_FMT_FORMAT_MASK 0x000f
42#define SOF_DAI_FMT_CLOCK_MASK 0x00f0
43#define SOF_DAI_FMT_INV_MASK 0x0f00
44#define SOF_DAI_FMT_MASTER_MASK 0xf000
45
46/** \brief Types of DAI */
47enum sof_ipc_dai_type {
48 SOF_DAI_INTEL_NONE = 0, /**< None */
49 SOF_DAI_INTEL_SSP, /**< Intel SSP */
50 SOF_DAI_INTEL_DMIC, /**< Intel DMIC */
51 SOF_DAI_INTEL_HDA, /**< Intel HD/A */
52};
53
54/* general purpose DAI configuration */
55struct sof_ipc_dai_config {
56 struct sof_ipc_cmd_hdr hdr;
57 uint32_t type; /**< DAI type - enum sof_ipc_dai_type */
58 uint32_t dai_index; /**< index of this type dai */
59
60 /* physical protocol and clocking */
61 uint16_t format; /**< SOF_DAI_FMT_ */
62 uint16_t reserved16; /**< alignment */
63
64 /* reserved for future use */
65 uint32_t reserved[8];
66
67 /* HW specific data */
68 union {
69 struct sof_ipc_dai_ssp_params ssp;
70 struct sof_ipc_dai_dmic_params dmic;
71 struct sof_ipc_dai_hda_params hda;
72 };
73} __packed;
74
75#endif
diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h
new file mode 100644
index 000000000000..ccb6a004b37b
--- /dev/null
+++ b/include/sound/sof/header.h
@@ -0,0 +1,158 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_HEADER_H__
10#define __INCLUDE_SOUND_SOF_HEADER_H__
11
12#include <uapi/sound/sof/abi.h>
13
14/** \addtogroup sof_uapi uAPI
15 * SOF uAPI specification.
16 * @{
17 */
18
19/*
20 * IPC messages have a prefixed 32 bit identifier made up as follows :-
21 *
22 * 0xGCCCNNNN where
23 * G is global cmd type (4 bits)
24 * C is command type (12 bits)
25 * I is the ID number (16 bits) - monotonic and overflows
26 *
27 * This is sent at the start of the IPM message in the mailbox. Messages should
28 * not be sent in the doorbell (special exceptions for firmware .
29 */
30
31/* Global Message - Generic */
32#define SOF_GLB_TYPE_SHIFT 28
33#define SOF_GLB_TYPE_MASK (0xf << SOF_GLB_TYPE_SHIFT)
34#define SOF_GLB_TYPE(x) ((x) << SOF_GLB_TYPE_SHIFT)
35
36/* Command Message - Generic */
37#define SOF_CMD_TYPE_SHIFT 16
38#define SOF_CMD_TYPE_MASK (0xfff << SOF_CMD_TYPE_SHIFT)
39#define SOF_CMD_TYPE(x) ((x) << SOF_CMD_TYPE_SHIFT)
40
41/* Global Message Types */
42#define SOF_IPC_GLB_REPLY SOF_GLB_TYPE(0x1U)
43#define SOF_IPC_GLB_COMPOUND SOF_GLB_TYPE(0x2U)
44#define SOF_IPC_GLB_TPLG_MSG SOF_GLB_TYPE(0x3U)
45#define SOF_IPC_GLB_PM_MSG SOF_GLB_TYPE(0x4U)
46#define SOF_IPC_GLB_COMP_MSG SOF_GLB_TYPE(0x5U)
47#define SOF_IPC_GLB_STREAM_MSG SOF_GLB_TYPE(0x6U)
48#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U)
49#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U)
50#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U)
51
52/*
53 * DSP Command Message Types
54 */
55
56/* topology */
57#define SOF_IPC_TPLG_COMP_NEW SOF_CMD_TYPE(0x001)
58#define SOF_IPC_TPLG_COMP_FREE SOF_CMD_TYPE(0x002)
59#define SOF_IPC_TPLG_COMP_CONNECT SOF_CMD_TYPE(0x003)
60#define SOF_IPC_TPLG_PIPE_NEW SOF_CMD_TYPE(0x010)
61#define SOF_IPC_TPLG_PIPE_FREE SOF_CMD_TYPE(0x011)
62#define SOF_IPC_TPLG_PIPE_CONNECT SOF_CMD_TYPE(0x012)
63#define SOF_IPC_TPLG_PIPE_COMPLETE SOF_CMD_TYPE(0x013)
64#define SOF_IPC_TPLG_BUFFER_NEW SOF_CMD_TYPE(0x020)
65#define SOF_IPC_TPLG_BUFFER_FREE SOF_CMD_TYPE(0x021)
66
67/* PM */
68#define SOF_IPC_PM_CTX_SAVE SOF_CMD_TYPE(0x001)
69#define SOF_IPC_PM_CTX_RESTORE SOF_CMD_TYPE(0x002)
70#define SOF_IPC_PM_CTX_SIZE SOF_CMD_TYPE(0x003)
71#define SOF_IPC_PM_CLK_SET SOF_CMD_TYPE(0x004)
72#define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005)
73#define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006)
74#define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007)
75
76/* component runtime config - multiple different types */
77#define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001)
78#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002)
79#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003)
80#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004)
81
82/* DAI messages */
83#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001)
84#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002)
85
86/* stream */
87#define SOF_IPC_STREAM_PCM_PARAMS SOF_CMD_TYPE(0x001)
88#define SOF_IPC_STREAM_PCM_PARAMS_REPLY SOF_CMD_TYPE(0x002)
89#define SOF_IPC_STREAM_PCM_FREE SOF_CMD_TYPE(0x003)
90#define SOF_IPC_STREAM_TRIG_START SOF_CMD_TYPE(0x004)
91#define SOF_IPC_STREAM_TRIG_STOP SOF_CMD_TYPE(0x005)
92#define SOF_IPC_STREAM_TRIG_PAUSE SOF_CMD_TYPE(0x006)
93#define SOF_IPC_STREAM_TRIG_RELEASE SOF_CMD_TYPE(0x007)
94#define SOF_IPC_STREAM_TRIG_DRAIN SOF_CMD_TYPE(0x008)
95#define SOF_IPC_STREAM_TRIG_XRUN SOF_CMD_TYPE(0x009)
96#define SOF_IPC_STREAM_POSITION SOF_CMD_TYPE(0x00a)
97#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010)
98#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011)
99
100/* trace and debug */
101#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001)
102#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002)
103
104/* Get message component id */
105#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff)
106
107/* maximum message size for mailbox Tx/Rx */
108#define SOF_IPC_MSG_MAX_SIZE 384
109
110/*
111 * Structure Header - Header for all IPC structures except command structs.
112 * The size can be greater than the structure size and that means there is
113 * extended bespoke data beyond the end of the structure including variable
114 * arrays.
115 */
116
117struct sof_ipc_hdr {
118 uint32_t size; /**< size of structure */
119} __packed;
120
121/*
122 * Command Header - Header for all IPC commands. Identifies IPC message.
123 * The size can be greater than the structure size and that means there is
124 * extended bespoke data beyond the end of the structure including variable
125 * arrays.
126 */
127
128struct sof_ipc_cmd_hdr {
129 uint32_t size; /**< size of structure */
130 uint32_t cmd; /**< SOF_IPC_GLB_ + cmd */
131} __packed;
132
133/*
134 * Generic reply message. Some commands override this with their own reply
135 * types that must include this at start.
136 */
137struct sof_ipc_reply {
138 struct sof_ipc_cmd_hdr hdr;
139 int32_t error; /**< negative error numbers */
140} __packed;
141
142/*
143 * Compound commands - SOF_IPC_GLB_COMPOUND.
144 *
145 * Compound commands are sent to the DSP as a single IPC operation. The
146 * commands are split into blocks and each block has a header. This header
147 * identifies the command type and the number of commands before the next
148 * header.
149 */
150
151struct sof_ipc_compound_hdr {
152 struct sof_ipc_cmd_hdr hdr;
153 uint32_t count; /**< count of 0 means end of compound sequence */
154} __packed;
155
156/** @}*/
157
158#endif
diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h
new file mode 100644
index 000000000000..21dae04d8183
--- /dev/null
+++ b/include/sound/sof/info.h
@@ -0,0 +1,118 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_INFO_H__
10#define __INCLUDE_SOUND_SOF_INFO_H__
11
12#include <sound/sof/header.h>
13#include <sound/sof/stream.h>
14
15/*
16 * Firmware boot and version
17 */
18
19#define SOF_IPC_MAX_ELEMS 16
20
21/* extended data types that can be appended onto end of sof_ipc_fw_ready */
22enum sof_ipc_ext_data {
23 SOF_IPC_EXT_DMA_BUFFER = 0,
24 SOF_IPC_EXT_WINDOW,
25};
26
27/* FW version - SOF_IPC_GLB_VERSION */
28struct sof_ipc_fw_version {
29 struct sof_ipc_hdr hdr;
30 uint16_t major;
31 uint16_t minor;
32 uint16_t micro;
33 uint16_t build;
34 uint8_t date[12];
35 uint8_t time[10];
36 uint8_t tag[6];
37 uint32_t abi_version;
38
39 /* reserved for future use */
40 uint32_t reserved[4];
41} __packed;
42
43/* FW ready Message - sent by firmware when boot has completed */
44struct sof_ipc_fw_ready {
45 struct sof_ipc_cmd_hdr hdr;
46 uint32_t dspbox_offset; /* dsp initiated IPC mailbox */
47 uint32_t hostbox_offset; /* host initiated IPC mailbox */
48 uint32_t dspbox_size;
49 uint32_t hostbox_size;
50 struct sof_ipc_fw_version version;
51
52 /* Miscellaneous debug flags showing build/debug features enabled */
53 union {
54 uint64_t reserved;
55 struct {
56 uint64_t build:1;
57 uint64_t locks:1;
58 uint64_t locks_verbose:1;
59 uint64_t gdb:1;
60 } bits;
61 } debug;
62
63 /* reserved for future use */
64 uint32_t reserved[4];
65} __packed;
66
67/*
68 * Extended Firmware data. All optional, depends on platform/arch.
69 */
70enum sof_ipc_region {
71 SOF_IPC_REGION_DOWNBOX = 0,
72 SOF_IPC_REGION_UPBOX,
73 SOF_IPC_REGION_TRACE,
74 SOF_IPC_REGION_DEBUG,
75 SOF_IPC_REGION_STREAM,
76 SOF_IPC_REGION_REGS,
77 SOF_IPC_REGION_EXCEPTION,
78};
79
80struct sof_ipc_ext_data_hdr {
81 struct sof_ipc_cmd_hdr hdr;
82 uint32_t type; /**< SOF_IPC_EXT_ */
83} __packed;
84
85struct sof_ipc_dma_buffer_elem {
86 struct sof_ipc_hdr hdr;
87 uint32_t type; /**< SOF_IPC_REGION_ */
88 uint32_t id; /**< platform specific - used to map to host memory */
89 struct sof_ipc_host_buffer buffer;
90} __packed;
91
92/* extended data DMA buffers for IPC, trace and debug */
93struct sof_ipc_dma_buffer_data {
94 struct sof_ipc_ext_data_hdr ext_hdr;
95 uint32_t num_buffers;
96
97 /* host files in buffer[n].buffer */
98 struct sof_ipc_dma_buffer_elem buffer[];
99} __packed;
100
101struct sof_ipc_window_elem {
102 struct sof_ipc_hdr hdr;
103 uint32_t type; /**< SOF_IPC_REGION_ */
104 uint32_t id; /**< platform specific - used to map to host memory */
105 uint32_t flags; /**< R, W, RW, etc - to define */
106 uint32_t size; /**< size of region in bytes */
107 /* offset in window region as windows can be partitioned */
108 uint32_t offset;
109} __packed;
110
111/* extended data memory windows for IPC, trace and debug */
112struct sof_ipc_window {
113 struct sof_ipc_ext_data_hdr ext_hdr;
114 uint32_t num_windows;
115 struct sof_ipc_window_elem window[];
116} __packed;
117
118#endif
diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h
new file mode 100644
index 000000000000..8ae3ad45bdf7
--- /dev/null
+++ b/include/sound/sof/pm.h
@@ -0,0 +1,48 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_PM_H__
10#define __INCLUDE_SOUND_SOF_PM_H__
11
12#include <sound/sof/header.h>
13
14/*
15 * PM
16 */
17
18/* PM context element */
19struct sof_ipc_pm_ctx_elem {
20 struct sof_ipc_hdr hdr;
21 uint32_t type;
22 uint32_t size;
23 uint64_t addr;
24} __packed;
25
26/*
27 * PM context - SOF_IPC_PM_CTX_SAVE, SOF_IPC_PM_CTX_RESTORE,
28 * SOF_IPC_PM_CTX_SIZE
29 */
30struct sof_ipc_pm_ctx {
31 struct sof_ipc_cmd_hdr hdr;
32 struct sof_ipc_host_buffer buffer;
33 uint32_t num_elems;
34 uint32_t size;
35
36 /* reserved for future use */
37 uint32_t reserved[8];
38
39 struct sof_ipc_pm_ctx_elem elems[];
40} __packed;
41
42/* enable or disable cores - SOF_IPC_PM_CORE_ENABLE */
43struct sof_ipc_pm_core_config {
44 struct sof_ipc_cmd_hdr hdr;
45 uint32_t enable_mask;
46} __packed;
47
48#endif
diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h
new file mode 100644
index 000000000000..643f175cb479
--- /dev/null
+++ b/include/sound/sof/stream.h
@@ -0,0 +1,148 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_STREAM_H__
10#define __INCLUDE_SOUND_SOF_STREAM_H__
11
12#include <sound/sof/header.h>
13
14/*
15 * Stream configuration.
16 */
17
18#define SOF_IPC_MAX_CHANNELS 8
19
20/* common sample rates for use in masks */
21#define SOF_RATE_8000 (1 << 0) /**< 8000Hz */
22#define SOF_RATE_11025 (1 << 1) /**< 11025Hz */
23#define SOF_RATE_12000 (1 << 2) /**< 12000Hz */
24#define SOF_RATE_16000 (1 << 3) /**< 16000Hz */
25#define SOF_RATE_22050 (1 << 4) /**< 22050Hz */
26#define SOF_RATE_24000 (1 << 5) /**< 24000Hz */
27#define SOF_RATE_32000 (1 << 6) /**< 32000Hz */
28#define SOF_RATE_44100 (1 << 7) /**< 44100Hz */
29#define SOF_RATE_48000 (1 << 8) /**< 48000Hz */
30#define SOF_RATE_64000 (1 << 9) /**< 64000Hz */
31#define SOF_RATE_88200 (1 << 10) /**< 88200Hz */
32#define SOF_RATE_96000 (1 << 11) /**< 96000Hz */
33#define SOF_RATE_176400 (1 << 12) /**< 176400Hz */
34#define SOF_RATE_192000 (1 << 13) /**< 192000Hz */
35
36/* continuous and non-standard rates for flexibility */
37#define SOF_RATE_CONTINUOUS (1 << 30) /**< range */
38#define SOF_RATE_KNOT (1 << 31) /**< non-continuous */
39
40/* generic PCM flags for runtime settings */
41#define SOF_PCM_FLAG_XRUN_STOP (1 << 0) /**< Stop on any XRUN */
42
43/* stream PCM frame format */
44enum sof_ipc_frame {
45 SOF_IPC_FRAME_S16_LE = 0,
46 SOF_IPC_FRAME_S24_4LE,
47 SOF_IPC_FRAME_S32_LE,
48 SOF_IPC_FRAME_FLOAT,
49 /* other formats here */
50};
51
52/* stream buffer format */
53enum sof_ipc_buffer_format {
54 SOF_IPC_BUFFER_INTERLEAVED,
55 SOF_IPC_BUFFER_NONINTERLEAVED,
56 /* other formats here */
57};
58
59/* stream direction */
60enum sof_ipc_stream_direction {
61 SOF_IPC_STREAM_PLAYBACK = 0,
62 SOF_IPC_STREAM_CAPTURE,
63};
64
65/* stream ring info */
66struct sof_ipc_host_buffer {
67 struct sof_ipc_hdr hdr;
68 uint32_t phy_addr;
69 uint32_t pages;
70 uint32_t size;
71 uint32_t reserved[3];
72} __packed;
73
74struct sof_ipc_stream_params {
75 struct sof_ipc_hdr hdr;
76 struct sof_ipc_host_buffer buffer;
77 uint32_t direction; /**< enum sof_ipc_stream_direction */
78 uint32_t frame_fmt; /**< enum sof_ipc_frame */
79 uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */
80 uint32_t rate;
81 uint16_t stream_tag;
82 uint16_t channels;
83 uint16_t sample_valid_bytes;
84 uint16_t sample_container_bytes;
85
86 /* for notifying host period has completed - 0 means no period IRQ */
87 uint32_t host_period_bytes;
88
89 uint32_t reserved[2];
90 uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */
91} __packed;
92
93/* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */
94struct sof_ipc_pcm_params {
95 struct sof_ipc_cmd_hdr hdr;
96 uint32_t comp_id;
97 uint32_t flags; /**< generic PCM flags - SOF_PCM_FLAG_ */
98 uint32_t reserved[2];
99 struct sof_ipc_stream_params params;
100} __packed;
101
102/* PCM params info reply - SOF_IPC_STREAM_PCM_PARAMS_REPLY */
103struct sof_ipc_pcm_params_reply {
104 struct sof_ipc_reply rhdr;
105 uint32_t comp_id;
106 uint32_t posn_offset;
107} __packed;
108
109/* free stream - SOF_IPC_STREAM_PCM_PARAMS */
110struct sof_ipc_stream {
111 struct sof_ipc_cmd_hdr hdr;
112 uint32_t comp_id;
113} __packed;
114
115/* flags indicating which time stamps are in sync with each other */
116#define SOF_TIME_HOST_SYNC (1 << 0)
117#define SOF_TIME_DAI_SYNC (1 << 1)
118#define SOF_TIME_WALL_SYNC (1 << 2)
119#define SOF_TIME_STAMP_SYNC (1 << 3)
120
121/* flags indicating which time stamps are valid */
122#define SOF_TIME_HOST_VALID (1 << 8)
123#define SOF_TIME_DAI_VALID (1 << 9)
124#define SOF_TIME_WALL_VALID (1 << 10)
125#define SOF_TIME_STAMP_VALID (1 << 11)
126
127/* flags indicating time stamps are 64bit else 3use low 32bit */
128#define SOF_TIME_HOST_64 (1 << 16)
129#define SOF_TIME_DAI_64 (1 << 17)
130#define SOF_TIME_WALL_64 (1 << 18)
131#define SOF_TIME_STAMP_64 (1 << 19)
132
133struct sof_ipc_stream_posn {
134 struct sof_ipc_reply rhdr;
135 uint32_t comp_id; /**< host component ID */
136 uint32_t flags; /**< SOF_TIME_ */
137 uint32_t wallclock_hz; /**< frequency of wallclock in Hz */
138 uint32_t timestamp_ns; /**< resolution of timestamp in ns */
139 uint64_t host_posn; /**< host DMA position in bytes */
140 uint64_t dai_posn; /**< DAI DMA position in bytes */
141 uint64_t comp_posn; /**< comp position in bytes */
142 uint64_t wallclock; /**< audio wall clock */
143 uint64_t timestamp; /**< system time stamp */
144 uint32_t xrun_comp_id; /**< comp ID of XRUN component */
145 int32_t xrun_size; /**< XRUN size in bytes */
146} __packed;
147
148#endif
diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h
new file mode 100644
index 000000000000..46b2a7e63167
--- /dev/null
+++ b/include/sound/sof/topology.h
@@ -0,0 +1,256 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_TOPOLOGY_H__
10#define __INCLUDE_SOUND_SOF_TOPOLOGY_H__
11
12#include <sound/sof/header.h>
13
14/*
15 * Component
16 */
17
18/* types of component */
19enum sof_comp_type {
20 SOF_COMP_NONE = 0,
21 SOF_COMP_HOST,
22 SOF_COMP_DAI,
23 SOF_COMP_SG_HOST, /**< scatter gather variant */
24 SOF_COMP_SG_DAI, /**< scatter gather variant */
25 SOF_COMP_VOLUME,
26 SOF_COMP_MIXER,
27 SOF_COMP_MUX,
28 SOF_COMP_SRC,
29 SOF_COMP_SPLITTER,
30 SOF_COMP_TONE,
31 SOF_COMP_SWITCH,
32 SOF_COMP_BUFFER,
33 SOF_COMP_EQ_IIR,
34 SOF_COMP_EQ_FIR,
35 SOF_COMP_KEYWORD_DETECT,
36 SOF_COMP_KPB, /* A key phrase buffer component */
37 SOF_COMP_SELECTOR, /**< channel selector component */
38 /* keep FILEREAD/FILEWRITE as the last ones */
39 SOF_COMP_FILEREAD = 10000, /**< host test based file IO */
40 SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */
41};
42
43/* XRUN action for component */
44#define SOF_XRUN_STOP 1 /**< stop stream */
45#define SOF_XRUN_UNDER_ZERO 2 /**< send 0s to sink */
46#define SOF_XRUN_OVER_NULL 4 /**< send data to NULL */
47
48/* create new generic component - SOF_IPC_TPLG_COMP_NEW */
49struct sof_ipc_comp {
50 struct sof_ipc_cmd_hdr hdr;
51 uint32_t id;
52 enum sof_comp_type type;
53 uint32_t pipeline_id;
54
55 /* reserved for future use */
56 uint32_t reserved[2];
57} __packed;
58
59/*
60 * Component Buffers
61 */
62
63/*
64 * SOF memory capabilities, add new ones at the end
65 */
66#define SOF_MEM_CAPS_RAM (1 << 0)
67#define SOF_MEM_CAPS_ROM (1 << 1)
68#define SOF_MEM_CAPS_EXT (1 << 2) /**< external */
69#define SOF_MEM_CAPS_LP (1 << 3) /**< low power */
70#define SOF_MEM_CAPS_HP (1 << 4) /**< high performance */
71#define SOF_MEM_CAPS_DMA (1 << 5) /**< DMA'able */
72#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */
73#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */
74
75/* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */
76struct sof_ipc_buffer {
77 struct sof_ipc_comp comp;
78 uint32_t size; /**< buffer size in bytes */
79 uint32_t caps; /**< SOF_MEM_CAPS_ */
80} __packed;
81
82/* generic component config data - must always be after struct sof_ipc_comp */
83struct sof_ipc_comp_config {
84 struct sof_ipc_cmd_hdr hdr;
85 uint32_t periods_sink; /**< 0 means variable */
86 uint32_t periods_source; /**< 0 means variable */
87 uint32_t reserved1; /**< reserved */
88 uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */
89 uint32_t xrun_action;
90
91 /* reserved for future use */
92 uint32_t reserved[2];
93} __packed;
94
95/* generic host component */
96struct sof_ipc_comp_host {
97 struct sof_ipc_comp comp;
98 struct sof_ipc_comp_config config;
99 uint32_t direction; /**< SOF_IPC_STREAM_ */
100 uint32_t no_irq; /**< don't send periodic IRQ to host/DSP */
101 uint32_t dmac_config; /**< DMA engine specific */
102} __packed;
103
104/* generic DAI component */
105struct sof_ipc_comp_dai {
106 struct sof_ipc_comp comp;
107 struct sof_ipc_comp_config config;
108 uint32_t direction; /**< SOF_IPC_STREAM_ */
109 uint32_t dai_index; /**< index of this type dai */
110 uint32_t type; /**< DAI type - SOF_DAI_ */
111 uint32_t reserved; /**< reserved */
112} __packed;
113
114/* generic mixer component */
115struct sof_ipc_comp_mixer {
116 struct sof_ipc_comp comp;
117 struct sof_ipc_comp_config config;
118} __packed;
119
120/* volume ramping types */
121enum sof_volume_ramp {
122 SOF_VOLUME_LINEAR = 0,
123 SOF_VOLUME_LOG,
124 SOF_VOLUME_LINEAR_ZC,
125 SOF_VOLUME_LOG_ZC,
126};
127
128/* generic volume component */
129struct sof_ipc_comp_volume {
130 struct sof_ipc_comp comp;
131 struct sof_ipc_comp_config config;
132 uint32_t channels;
133 uint32_t min_value;
134 uint32_t max_value;
135 uint32_t ramp; /**< SOF_VOLUME_ */
136 uint32_t initial_ramp; /**< ramp space in ms */
137} __packed;
138
139/* generic SRC component */
140struct sof_ipc_comp_src {
141 struct sof_ipc_comp comp;
142 struct sof_ipc_comp_config config;
143 /* either source or sink rate must be non zero */
144 uint32_t source_rate; /**< source rate or 0 for variable */
145 uint32_t sink_rate; /**< sink rate or 0 for variable */
146 uint32_t rate_mask; /**< SOF_RATE_ supported rates */
147} __packed;
148
149/* generic MUX component */
150struct sof_ipc_comp_mux {
151 struct sof_ipc_comp comp;
152 struct sof_ipc_comp_config config;
153} __packed;
154
155/* generic tone generator component */
156struct sof_ipc_comp_tone {
157 struct sof_ipc_comp comp;
158 struct sof_ipc_comp_config config;
159 int32_t sample_rate;
160 int32_t frequency;
161 int32_t amplitude;
162 int32_t freq_mult;
163 int32_t ampl_mult;
164 int32_t length;
165 int32_t period;
166 int32_t repeats;
167 int32_t ramp_step;
168} __packed;
169
170/** \brief Types of processing components */
171enum sof_ipc_process_type {
172 SOF_PROCESS_NONE = 0, /**< None */
173 SOF_PROCESS_EQFIR, /**< Intel FIR */
174 SOF_PROCESS_EQIIR, /**< Intel IIR */
175 SOF_PROCESS_KEYWORD_DETECT, /**< Keyword Detection */
176 SOF_PROCESS_KPB, /**< KeyPhrase Buffer Manager */
177 SOF_PROCESS_CHAN_SELECTOR, /**< Channel Selector */
178};
179
180/* generic "effect", "codec" or proprietary processing component */
181struct sof_ipc_comp_process {
182 struct sof_ipc_comp comp;
183 struct sof_ipc_comp_config config;
184 uint32_t size; /**< size of bespoke data section in bytes */
185 uint32_t type; /**< sof_ipc_process_type */
186
187 /* reserved for future use */
188 uint32_t reserved[7];
189
190 unsigned char data[0];
191} __packed;
192
193/* frees components, buffers and pipelines
194 * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE
195 */
196struct sof_ipc_free {
197 struct sof_ipc_cmd_hdr hdr;
198 uint32_t id;
199} __packed;
200
201struct sof_ipc_comp_reply {
202 struct sof_ipc_reply rhdr;
203 uint32_t id;
204 uint32_t offset;
205} __packed;
206
207/*
208 * Pipeline
209 */
210
211/** \brief Types of pipeline scheduling time domains */
212enum sof_ipc_pipe_sched_time_domain {
213 SOF_TIME_DOMAIN_DMA = 0, /**< DMA interrupt */
214 SOF_TIME_DOMAIN_TIMER, /**< Timer interrupt */
215};
216
217/* new pipeline - SOF_IPC_TPLG_PIPE_NEW */
218struct sof_ipc_pipe_new {
219 struct sof_ipc_cmd_hdr hdr;
220 uint32_t comp_id; /**< component id for pipeline */
221 uint32_t pipeline_id; /**< pipeline id */
222 uint32_t sched_id; /**< Scheduling component id */
223 uint32_t core; /**< core we run on */
224 uint32_t period; /**< execution period in us*/
225 uint32_t priority; /**< priority level 0 (low) to 10 (max) */
226 uint32_t period_mips; /**< worst case instruction count per period */
227 uint32_t frames_per_sched;/**< output frames of pipeline, 0 is variable */
228 uint32_t xrun_limit_usecs; /**< report xruns greater than limit */
229 uint32_t time_domain; /**< scheduling time domain */
230} __packed;
231
232/* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */
233struct sof_ipc_pipe_ready {
234 struct sof_ipc_cmd_hdr hdr;
235 uint32_t comp_id;
236} __packed;
237
238struct sof_ipc_pipe_free {
239 struct sof_ipc_cmd_hdr hdr;
240 uint32_t comp_id;
241} __packed;
242
243/* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */
244struct sof_ipc_pipe_comp_connect {
245 struct sof_ipc_cmd_hdr hdr;
246 uint32_t source_id;
247 uint32_t sink_id;
248} __packed;
249
250/* external events */
251enum sof_event_types {
252 SOF_EVENT_NONE = 0,
253 SOF_KEYWORD_DETECT_DAPM_EVENT,
254};
255
256#endif
diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h
new file mode 100644
index 000000000000..7d211f319a92
--- /dev/null
+++ b/include/sound/sof/trace.h
@@ -0,0 +1,67 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_TRACE_H__
10#define __INCLUDE_SOUND_SOF_TRACE_H__
11
12#include <sound/sof/header.h>
13#include <sound/sof/stream.h>
14
15/*
16 * DMA for Trace
17 */
18
19#define SOF_TRACE_FILENAME_SIZE 32
20
21/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */
22struct sof_ipc_dma_trace_params {
23 struct sof_ipc_cmd_hdr hdr;
24 struct sof_ipc_host_buffer buffer;
25 uint32_t stream_tag;
26} __packed;
27
28/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */
29struct sof_ipc_dma_trace_posn {
30 struct sof_ipc_reply rhdr;
31 uint32_t host_offset; /* Offset of DMA host buffer */
32 uint32_t overflow; /* overflow bytes if any */
33 uint32_t messages; /* total trace messages */
34} __packed;
35
36/*
37 * Commom debug
38 */
39
40/*
41 * SOF panic codes
42 */
43#define SOF_IPC_PANIC_MAGIC 0x0dead000
44#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000
45#define SOF_IPC_PANIC_CODE_MASK 0x00000fff
46#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0)
47#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1)
48#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2)
49#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3)
50#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4)
51#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5)
52#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6)
53#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7)
54#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8)
55#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9)
56#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa)
57#define SOF_IPC_PANIC_ASSERT (SOF_IPC_PANIC_MAGIC | 0xb)
58
59/* panic info include filename and line number */
60struct sof_ipc_panic_info {
61 struct sof_ipc_hdr hdr;
62 uint32_t code; /* SOF_IPC_PANIC_ */
63 char filename[SOF_TRACE_FILENAME_SIZE];
64 uint32_t linenum;
65} __packed;
66
67#endif
diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h
new file mode 100644
index 000000000000..a7189984000d
--- /dev/null
+++ b/include/sound/sof/xtensa.h
@@ -0,0 +1,44 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_SOUND_SOF_XTENSA_H__
10#define __INCLUDE_SOUND_SOF_XTENSA_H__
11
12#include <sound/sof/header.h>
13
14/*
15 * Architecture specific debug
16 */
17
18/* Xtensa Firmware Oops data */
19struct sof_ipc_dsp_oops_xtensa {
20 struct sof_ipc_hdr hdr;
21 uint32_t exccause;
22 uint32_t excvaddr;
23 uint32_t ps;
24 uint32_t epc1;
25 uint32_t epc2;
26 uint32_t epc3;
27 uint32_t epc4;
28 uint32_t epc5;
29 uint32_t epc6;
30 uint32_t epc7;
31 uint32_t eps2;
32 uint32_t eps3;
33 uint32_t eps4;
34 uint32_t eps5;
35 uint32_t eps6;
36 uint32_t eps7;
37 uint32_t depc;
38 uint32_t intenable;
39 uint32_t interrupt;
40 uint32_t sar;
41 uint32_t stack;
42} __packed;
43
44#endif
diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h
new file mode 100644
index 000000000000..37e0a90dc9e6
--- /dev/null
+++ b/include/uapi/sound/sof/abi.h
@@ -0,0 +1,62 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9/**
10 * SOF ABI versioning is based on Semantic Versioning where we have a given
11 * MAJOR.MINOR.PATCH version number. See https://semver.org/
12 *
13 * Rules for incrementing or changing version :-
14 *
15 * 1) Increment MAJOR version if you make incompatible API changes. MINOR and
16 * PATCH should be reset to 0.
17 *
18 * 2) Increment MINOR version if you add backwards compatible features or
19 * changes. PATCH should be reset to 0.
20 *
21 * 3) Increment PATCH version if you add backwards compatible bug fixes.
22 */
23
24#ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__
25#define __INCLUDE_UAPI_SOUND_SOF_ABI_H__
26
27/* SOF ABI version major, minor and patch numbers */
28#define SOF_ABI_MAJOR 3
29#define SOF_ABI_MINOR 4
30#define SOF_ABI_PATCH 0
31
32/* SOF ABI version number. Format within 32bit word is MMmmmppp */
33#define SOF_ABI_MAJOR_SHIFT 24
34#define SOF_ABI_MAJOR_MASK 0xff
35#define SOF_ABI_MINOR_SHIFT 12
36#define SOF_ABI_MINOR_MASK 0xfff
37#define SOF_ABI_PATCH_SHIFT 0
38#define SOF_ABI_PATCH_MASK 0xfff
39
40#define SOF_ABI_VER(major, minor, patch) \
41 (((major) << SOF_ABI_MAJOR_SHIFT) | \
42 ((minor) << SOF_ABI_MINOR_SHIFT) | \
43 ((patch) << SOF_ABI_PATCH_SHIFT))
44
45#define SOF_ABI_VERSION_MAJOR(version) \
46 (((version) >> SOF_ABI_MAJOR_SHIFT) & SOF_ABI_MAJOR_MASK)
47#define SOF_ABI_VERSION_MINOR(version) \
48 (((version) >> SOF_ABI_MINOR_SHIFT) & SOF_ABI_MINOR_MASK)
49#define SOF_ABI_VERSION_PATCH(version) \
50 (((version) >> SOF_ABI_PATCH_SHIFT) & SOF_ABI_PATCH_MASK)
51
52#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \
53 (SOF_ABI_VERSION_MAJOR((sof_ver)) != \
54 SOF_ABI_VERSION_MAJOR((client_ver)) \
55 )
56
57#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH)
58
59/* SOF ABI magic number "SOF\0". */
60#define SOF_ABI_MAGIC 0x00464F53
61
62#endif
diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h
new file mode 100644
index 000000000000..666c2b6a3229
--- /dev/null
+++ b/include/uapi/sound/sof/eq.h
@@ -0,0 +1,172 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__
10#define __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__
11
12/* FIR EQ type */
13
14#define SOF_EQ_FIR_IDX_SWITCH 0
15
16#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */
17
18#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */
19
20#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */
21
22/*
23 * eq_fir_configuration data structure contains this information
24 * uint32_t size
25 * This is the number of bytes need to store the received EQ
26 * configuration.
27 * uint16_t channels_in_config
28 * This describes the number of channels in this EQ config data. It
29 * can be different from PLATFORM_MAX_CHANNELS.
30 * uint16_t number_of_responses
31 * 0=no responses, 1=one response defined, 2=two responses defined, etc.
32 * int16_t data[]
33 * assign_response[channels_in_config]
34 * 0 = use first response, 1 = use 2nd response, etc.
35 * E.g. {0, 0, 0, 0, 1, 1, 1, 1} would apply to channels 0-3 the
36 * same first defined response and for to channels 4-7 the second.
37 * coef_data[]
38 * Repeated data
39 * { filter_length, output_shift, h[] }
40 * for every EQ response defined where vector h has filter_length
41 * number of coefficients. Coefficients in h[] are in Q1.15 format.
42 * E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts.
43 *
44 * NOTE: The channels_in_config must be even to have coef_data aligned to
45 * 32 bit word in RAM. Therefore a mono EQ assign must be duplicated to 2ch
46 * even if it would never used. Similarly a 5ch EQ assign must be increased
47 * to 6ch. EQ init will return an error if this is not met.
48 *
49 * NOTE: The filter_length must be multiple of four. Therefore the filter must
50 * be padded from the end with zeros have this condition met.
51 */
52
53struct sof_eq_fir_config {
54 uint32_t size;
55 uint16_t channels_in_config;
56 uint16_t number_of_responses;
57
58 /* reserved */
59 uint32_t reserved[4];
60
61 int16_t data[];
62} __packed;
63
64struct sof_eq_fir_coef_data {
65 int16_t length; /* Number of FIR taps */
66 int16_t out_shift; /* Amount of right shifts at output */
67
68 /* reserved */
69 uint32_t reserved[4];
70
71 int16_t coef[]; /* FIR coefficients */
72} __packed;
73
74/* In the struct above there's two 16 bit words (length, shift) and four
75 * reserved 32 bit words before the actual FIR coefficients. This information
76 * is used in parsing of the configuration blob.
77 */
78#define SOF_EQ_FIR_COEF_NHEADER \
79 (sizeof(struct sof_eq_fir_coef_data) / sizeof(int16_t))
80
81/* IIR EQ type */
82
83#define SOF_EQ_IIR_IDX_SWITCH 0
84
85#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */
86
87#define SOF_EQ_IIR_MAX_RESPONSES 8 /* A blob can define max 8 IIR EQs */
88
89/* eq_iir_configuration
90 * uint32_t channels_in_config
91 * This describes the number of channels in this EQ config data. It
92 * can be different from PLATFORM_MAX_CHANNELS.
93 * uint32_t number_of_responses_defined
94 * 0=no responses, 1=one response defined, 2=two responses defined, etc.
95 * int32_t data[]
96 * Data consist of two parts. First is the response assign vector that
97 * has length of channels_in_config. The latter part is coefficient
98 * data.
99 * uint32_t assign_response[channels_in_config]
100 * -1 = not defined, 0 = use first response, 1 = use 2nd, etc.
101 * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the
102 * same first defined response and leave channels 4-7 unequalized.
103 * coefficient_data[]
104 * <1st EQ>
105 * uint32_t num_biquads
106 * uint32_t num_biquads_in_series
107 * <1st biquad>
108 * int32_t coef_a2 Q2.30 format
109 * int32_t coef_a1 Q2.30 format
110 * int32_t coef_b2 Q2.30 format
111 * int32_t coef_b1 Q2.30 format
112 * int32_t coef_b0 Q2.30 format
113 * int32_t output_shift number of shifts right, shift left is negative
114 * int32_t output_gain Q2.14 format
115 * <2nd biquad>
116 * ...
117 * <2nd EQ>
118 *
119 * Note: A flat response biquad can be made with a section set to
120 * b0 = 1.0, gain = 1.0, and other parameters set to 0
121 * {0, 0, 0, 0, 1073741824, 0, 16484}
122 */
123
124struct sof_eq_iir_config {
125 uint32_t size;
126 uint32_t channels_in_config;
127 uint32_t number_of_responses;
128
129 /* reserved */
130 uint32_t reserved[4];
131
132 int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */
133} __packed;
134
135struct sof_eq_iir_header_df2t {
136 uint32_t num_sections;
137 uint32_t num_sections_in_series;
138
139 /* reserved */
140 uint32_t reserved[4];
141
142 int32_t biquads[]; /* Repeated biquad coefficients */
143} __packed;
144
145struct sof_eq_iir_biquad_df2t {
146 int32_t a2; /* Q2.30 */
147 int32_t a1; /* Q2.30 */
148 int32_t b2; /* Q2.30 */
149 int32_t b1; /* Q2.30 */
150 int32_t b0; /* Q2.30 */
151 int32_t output_shift; /* Number of right shifts */
152 int32_t output_gain; /* Q2.14 */
153} __packed;
154
155/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in
156 * in the 0 - 20 kHz bandwidth.
157 */
158#define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11
159
160/* The number of int32_t words in sof_eq_iir_header_df2t:
161 * num_sections, num_sections_in_series, reserved[4]
162 */
163#define SOF_EQ_IIR_NHEADER_DF2T \
164 (sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t))
165
166/* The number of int32_t words in sof_eq_iir_biquad_df2t:
167 * a2, a1, b2, b1, b0, output_shift, output_gain
168 */
169#define SOF_EQ_IIR_NBIQUAD_DF2T \
170 (sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t))
171
172#endif
diff --git a/include/uapi/sound/sof/fw.h b/include/uapi/sound/sof/fw.h
new file mode 100644
index 000000000000..1afca973eb09
--- /dev/null
+++ b/include/uapi/sound/sof/fw.h
@@ -0,0 +1,78 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9/*
10 * Firmware file format .
11 */
12
13#ifndef __INCLUDE_UAPI_SOF_FW_H__
14#define __INCLUDE_UAPI_SOF_FW_H__
15
16#define SND_SOF_FW_SIG_SIZE 4
17#define SND_SOF_FW_ABI 1
18#define SND_SOF_FW_SIG "Reef"
19
20/*
21 * Firmware module is made up of 1 . N blocks of different types. The
22 * Block header is used to determine where and how block is to be copied in the
23 * DSP/host memory space.
24 */
25enum snd_sof_fw_blk_type {
26 SOF_FW_BLK_TYPE_INVALID = -1,
27 SOF_FW_BLK_TYPE_START = 0,
28 SOF_FW_BLK_TYPE_RSRVD0 = SOF_FW_BLK_TYPE_START,
29 SOF_FW_BLK_TYPE_IRAM = 1, /* local instruction RAM */
30 SOF_FW_BLK_TYPE_DRAM = 2, /* local data RAM */
31 SOF_FW_BLK_TYPE_SRAM = 3, /* system RAM */
32 SOF_FW_BLK_TYPE_ROM = 4,
33 SOF_FW_BLK_TYPE_IMR = 5,
34 SOF_FW_BLK_TYPE_RSRVD6 = 6,
35 SOF_FW_BLK_TYPE_RSRVD7 = 7,
36 SOF_FW_BLK_TYPE_RSRVD8 = 8,
37 SOF_FW_BLK_TYPE_RSRVD9 = 9,
38 SOF_FW_BLK_TYPE_RSRVD10 = 10,
39 SOF_FW_BLK_TYPE_RSRVD11 = 11,
40 SOF_FW_BLK_TYPE_RSRVD12 = 12,
41 SOF_FW_BLK_TYPE_RSRVD13 = 13,
42 SOF_FW_BLK_TYPE_RSRVD14 = 14,
43 /* use SOF_FW_BLK_TYPE_RSVRDX for new block types */
44 SOF_FW_BLK_TYPE_NUM
45};
46
47struct snd_sof_blk_hdr {
48 enum snd_sof_fw_blk_type type;
49 uint32_t size; /* bytes minus this header */
50 uint32_t offset; /* offset from base */
51} __packed;
52
53/*
54 * Firmware file is made up of 1 .. N different modules types. The module
55 * type is used to determine how to load and parse the module.
56 */
57enum snd_sof_fw_mod_type {
58 SOF_FW_BASE = 0, /* base firmware image */
59 SOF_FW_MODULE = 1, /* firmware module */
60};
61
62struct snd_sof_mod_hdr {
63 enum snd_sof_fw_mod_type type;
64 uint32_t size; /* bytes minus this header */
65 uint32_t num_blocks; /* number of blocks */
66} __packed;
67
68/*
69 * Firmware file header.
70 */
71struct snd_sof_fw_header {
72 unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */
73 uint32_t file_size; /* size of file minus this header */
74 uint32_t num_modules; /* number of modules */
75 uint32_t abi; /* version of header format */
76} __packed;
77
78#endif
diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h
new file mode 100644
index 000000000000..7868990b0d6f
--- /dev/null
+++ b/include/uapi/sound/sof/header.h
@@ -0,0 +1,27 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__
10#define __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__
11
12/*
13 * Header for all non IPC ABI data.
14 *
15 * Identifies data type, size and ABI.
16 * Used by any bespoke component data structures or binary blobs.
17 */
18struct sof_abi_hdr {
19 uint32_t magic; /**< 'S', 'O', 'F', '\0' */
20 uint32_t type; /**< component specific type */
21 uint32_t size; /**< size in bytes of data excl. this struct */
22 uint32_t abi; /**< SOF ABI version */
23 uint32_t reserved[4]; /**< reserved for future use */
24 uint32_t data[0]; /**< Component data - opaque to core */
25} __packed;
26
27#endif
diff --git a/include/uapi/sound/sof/manifest.h b/include/uapi/sound/sof/manifest.h
new file mode 100644
index 000000000000..2009ee30fad0
--- /dev/null
+++ b/include/uapi/sound/sof/manifest.h
@@ -0,0 +1,188 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__
10#define __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__
11
12/* start offset for base FW module */
13#define SOF_MAN_ELF_TEXT_OFFSET 0x2000
14
15/* FW Extended Manifest Header id = $AE1 */
16#define SOF_MAN_EXT_HEADER_MAGIC 0x31454124
17
18/* module type load type */
19#define SOF_MAN_MOD_TYPE_BUILTIN 0
20#define SOF_MAN_MOD_TYPE_MODULE 1
21
22struct sof_man_module_type {
23 uint32_t load_type:4; /* SOF_MAN_MOD_TYPE_ */
24 uint32_t auto_start:1;
25 uint32_t domain_ll:1;
26 uint32_t domain_dp:1;
27 uint32_t rsvd_:25;
28};
29
30/* segment flags.type */
31#define SOF_MAN_SEGMENT_TEXT 0
32#define SOF_MAN_SEGMENT_RODATA 1
33#define SOF_MAN_SEGMENT_DATA 1
34#define SOF_MAN_SEGMENT_BSS 2
35#define SOF_MAN_SEGMENT_EMPTY 15
36
37union sof_man_segment_flags {
38 uint32_t ul;
39 struct {
40 uint32_t contents:1;
41 uint32_t alloc:1;
42 uint32_t load:1;
43 uint32_t readonly:1;
44 uint32_t code:1;
45 uint32_t data:1;
46 uint32_t _rsvd0:2;
47 uint32_t type:4; /* MAN_SEGMENT_ */
48 uint32_t _rsvd1:4;
49 uint32_t length:16; /* of segment in pages */
50 } r;
51} __packed;
52
53/*
54 * Module segment descriptor. Used by ROM - Immutable.
55 */
56struct sof_man_segment_desc {
57 union sof_man_segment_flags flags;
58 uint32_t v_base_addr;
59 uint32_t file_offset;
60} __packed;
61
62/*
63 * The firmware binary can be split into several modules.
64 */
65
66#define SOF_MAN_MOD_ID_LEN 4
67#define SOF_MAN_MOD_NAME_LEN 8
68#define SOF_MAN_MOD_SHA256_LEN 32
69#define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'}
70
71/*
72 * Each module has an entry in the FW header. Used by ROM - Immutable.
73 */
74struct sof_man_module {
75 uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */
76 uint8_t name[SOF_MAN_MOD_NAME_LEN];
77 uint8_t uuid[16];
78 struct sof_man_module_type type;
79 uint8_t hash[SOF_MAN_MOD_SHA256_LEN];
80 uint32_t entry_point;
81 uint16_t cfg_offset;
82 uint16_t cfg_count;
83 uint32_t affinity_mask;
84 uint16_t instance_max_count; /* max number of instances */
85 uint16_t instance_bss_size; /* instance (pages) */
86 struct sof_man_segment_desc segment[3];
87} __packed;
88
89/*
90 * Each module has a configuration in the FW header. Used by ROM - Immutable.
91 */
92struct sof_man_mod_config {
93 uint32_t par[4]; /* module parameters */
94 uint32_t is_pages; /* actual size of instance .bss (pages) */
95 uint32_t cps; /* cycles per second */
96 uint32_t ibs; /* input buffer size (bytes) */
97 uint32_t obs; /* output buffer size (bytes) */
98 uint32_t module_flags; /* flags, reserved for future use */
99 uint32_t cpc; /* cycles per single run */
100 uint32_t obls; /* output block size, reserved for future use */
101} __packed;
102
103/*
104 * FW Manifest Header
105 */
106
107#define SOF_MAN_FW_HDR_FW_NAME_LEN 8
108#define SOF_MAN_FW_HDR_ID {'$', 'A', 'M', '1'}
109#define SOF_MAN_FW_HDR_NAME "ADSPFW"
110#define SOF_MAN_FW_HDR_FLAGS 0x0
111#define SOF_MAN_FW_HDR_FEATURES 0xff
112
113/*
114 * The firmware has a standard header that is checked by the ROM on firmware
115 * loading. preload_page_count is used by DMA code loader and is entire
116 * image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata
117 * Used by ROM - Immutable.
118 */
119struct sof_man_fw_header {
120 uint8_t header_id[4];
121 uint32_t header_len;
122 uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN];
123 /* number of pages of preloaded image loaded by driver */
124 uint32_t preload_page_count;
125 uint32_t fw_image_flags;
126 uint32_t feature_mask;
127 uint16_t major_version;
128 uint16_t minor_version;
129 uint16_t hotfix_version;
130 uint16_t build_version;
131 uint32_t num_module_entries;
132 uint32_t hw_buf_base_addr;
133 uint32_t hw_buf_length;
134 /* target address for binary loading as offset in IMR - must be == base offset */
135 uint32_t load_offset;
136} __packed;
137
138/*
139 * Firmware manifest descriptor. This can contain N modules and N module
140 * configs. Used by ROM - Immutable.
141 */
142struct sof_man_fw_desc {
143 struct sof_man_fw_header header;
144
145 /* Warning - hack for module arrays. For some unknown reason the we
146 * have a variable size array of struct man_module followed by a
147 * variable size array of struct mod_config. These should have been
148 * merged into a variable array of a parent structure. We have to hack
149 * around this in many places....
150 *
151 * struct sof_man_module man_module[];
152 * struct sof_man_mod_config mod_config[];
153 */
154
155} __packed;
156
157/*
158 * Component Descriptor. Used by ROM - Immutable.
159 */
160struct sof_man_component_desc {
161 uint32_t reserved[2]; /* all 0 */
162 uint32_t version;
163 uint8_t hash[SOF_MAN_MOD_SHA256_LEN];
164 uint32_t base_offset;
165 uint32_t limit_offset;
166 uint32_t attributes[4];
167} __packed;
168
169/*
170 * Audio DSP extended metadata. Used by ROM - Immutable.
171 */
172struct sof_man_adsp_meta_file_ext {
173 uint32_t ext_type; /* always 17 for ADSP extension */
174 uint32_t ext_len;
175 uint32_t imr_type;
176 uint8_t reserved[16]; /* all 0 */
177 struct sof_man_component_desc comp_desc[1];
178} __packed;
179
180/*
181 * Module Manifest for rimage module metadata. Not used by ROM.
182 */
183struct sof_man_module_manifest {
184 struct sof_man_module module;
185 uint32_t text_size;
186} __packed;
187
188#endif
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
new file mode 100644
index 000000000000..53ea94bf1c08
--- /dev/null
+++ b/include/uapi/sound/sof/tokens.h
@@ -0,0 +1,107 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
8 * Keyon Jie <yang.jie@linux.intel.com>
9 */
10
11/*
12 * Topology IDs and tokens.
13 *
14 * ** MUST BE ALIGNED WITH TOPOLOGY CONFIGURATION TOKEN VALUES **
15 */
16
17#ifndef __INCLUDE_UAPI_SOF_TOPOLOGY_H__
18#define __INCLUDE_UAPI_SOF_TOPOLOGY_H__
19
20/*
21 * Kcontrol IDs
22 */
23#define SOF_TPLG_KCTL_VOL_ID 256
24#define SOF_TPLG_KCTL_ENUM_ID 257
25#define SOF_TPLG_KCTL_BYTES_ID 258
26#define SOF_TPLG_KCTL_SWITCH_ID 259
27
28/*
29 * Tokens - must match values in topology configurations
30 */
31
32/* buffers */
33#define SOF_TKN_BUF_SIZE 100
34#define SOF_TKN_BUF_CAPS 101
35
36/* DAI */
37/* Token retired with ABI 3.2, do not use for new capabilities
38 * #define SOF_TKN_DAI_DMAC_CONFIG 153
39 */
40#define SOF_TKN_DAI_TYPE 154
41#define SOF_TKN_DAI_INDEX 155
42#define SOF_TKN_DAI_DIRECTION 156
43
44/* scheduling */
45#define SOF_TKN_SCHED_PERIOD 200
46#define SOF_TKN_SCHED_PRIORITY 201
47#define SOF_TKN_SCHED_MIPS 202
48#define SOF_TKN_SCHED_CORE 203
49#define SOF_TKN_SCHED_FRAMES 204
50#define SOF_TKN_SCHED_TIME_DOMAIN 205
51
52/* volume */
53#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250
54#define SOF_TKN_VOLUME_RAMP_STEP_MS 251
55
56/* SRC */
57#define SOF_TKN_SRC_RATE_IN 300
58#define SOF_TKN_SRC_RATE_OUT 301
59
60/* PCM */
61#define SOF_TKN_PCM_DMAC_CONFIG 353
62
63/* Generic components */
64#define SOF_TKN_COMP_PERIOD_SINK_COUNT 400
65#define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401
66#define SOF_TKN_COMP_FORMAT 402
67/* Token retired with ABI 3.2, do not use for new capabilities
68 * #define SOF_TKN_COMP_PRELOAD_COUNT 403
69 */
70
71/* SSP */
72#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
73#define SOF_TKN_INTEL_SSP_MCLK_ID 501
74#define SOF_TKN_INTEL_SSP_SAMPLE_BITS 502
75#define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503
76#define SOF_TKN_INTEL_SSP_QUIRKS 504
77#define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505
78
79/* DMIC */
80#define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600
81#define SOF_TKN_INTEL_DMIC_CLK_MIN 601
82#define SOF_TKN_INTEL_DMIC_CLK_MAX 602
83#define SOF_TKN_INTEL_DMIC_DUTY_MIN 603
84#define SOF_TKN_INTEL_DMIC_DUTY_MAX 604
85#define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605
86#define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608
87#define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609
88
89/* DMIC PDM */
90#define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700
91#define SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable 701
92#define SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable 702
93#define SOF_TKN_INTEL_DMIC_PDM_POLARITY_A 703
94#define SOF_TKN_INTEL_DMIC_PDM_POLARITY_B 704
95#define SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE 705
96#define SOF_TKN_INTEL_DMIC_PDM_SKEW 706
97
98/* Tone */
99#define SOF_TKN_TONE_SAMPLE_RATE 800
100
101/* Processing Components */
102#define SOF_TKN_PROCESS_TYPE 900
103
104/* for backward compatibility */
105#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE
106
107#endif
diff --git a/include/uapi/sound/sof/tone.h b/include/uapi/sound/sof/tone.h
new file mode 100644
index 000000000000..d7c6e5d8317e
--- /dev/null
+++ b/include/uapi/sound/sof/tone.h
@@ -0,0 +1,21 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3* This file is provided under a dual BSD/GPLv2 license. When using or
4* redistributing this file, you may do so under either license.
5*
6* Copyright(c) 2018 Intel Corporation. All rights reserved.
7*/
8
9#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__
10#define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__
11
12#define SOF_TONE_IDX_FREQUENCY 0
13#define SOF_TONE_IDX_AMPLITUDE 1
14#define SOF_TONE_IDX_FREQ_MULT 2
15#define SOF_TONE_IDX_AMPL_MULT 3
16#define SOF_TONE_IDX_LENGTH 4
17#define SOF_TONE_IDX_PERIOD 5
18#define SOF_TONE_IDX_REPEATS 6
19#define SOF_TONE_IDX_LIN_RAMP_STEP 7
20
21#endif
diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h
new file mode 100644
index 000000000000..ffa7288a0f16
--- /dev/null
+++ b/include/uapi/sound/sof/trace.h
@@ -0,0 +1,66 @@
1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 */
8
9#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__
10#define __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__
11
12/*
13 * Host system time.
14 *
15 * This property is used by the driver to pass down information about
16 * current system time. It is expressed in us.
17 * FW translates timestamps (in log entries, probe pockets) to this time
18 * domain.
19 *
20 * (cavs: SystemTime).
21 */
22struct system_time {
23 uint32_t val_l; /* Lower dword of current host time value */
24 uint32_t val_u; /* Upper dword of current host time value */
25} __packed;
26
27#define LOG_ENABLE 1 /* Enable logging */
28#define LOG_DISABLE 0 /* Disable logging */
29
30#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */
31#define LOG_LEVEL_VERBOSE 2
32
33/*
34 * Layout of a log fifo.
35 */
36struct log_buffer_layout {
37 uint32_t read_ptr; /*read pointer */
38 uint32_t write_ptr; /* write pointer */
39 uint32_t buffer[0]; /* buffer */
40} __packed;
41
42/*
43 * Log buffer status reported by FW.
44 */
45struct log_buffer_status {
46 uint32_t core_id; /* ID of core that logged to other half */
47} __packed;
48
49#define TRACE_ID_LENGTH 12
50
51/*
52 * Log entry header.
53 *
54 * The header is followed by an array of arguments (uint32_t[]).
55 * Number of arguments is specified by the params_num field of log_entry
56 */
57struct log_entry_header {
58 uint32_t id_0 : TRACE_ID_LENGTH; /* e.g. Pipeline ID */
59 uint32_t id_1 : TRACE_ID_LENGTH; /* e.g. Component ID */
60 uint32_t core_id : 8; /* Reporting core's id */
61
62 uint64_t timestamp; /* Timestamp (in dsp ticks) */
63 uint32_t log_entry_address; /* Address of log entry in ELF */
64} __packed;
65
66#endif
diff --git a/sound/core/init.c b/sound/core/init.c
index 079c12d64b0e..d64416f0a281 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -49,8 +49,7 @@ static const struct file_operations snd_shutdown_f_ops;
49 49
50/* locked for registering/using */ 50/* locked for registering/using */
51static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS); 51static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
52struct snd_card *snd_cards[SNDRV_CARDS]; 52static struct snd_card *snd_cards[SNDRV_CARDS];
53EXPORT_SYMBOL(snd_cards);
54 53
55static DEFINE_MUTEX(snd_card_mutex); 54static DEFINE_MUTEX(snd_card_mutex);
56 55
@@ -268,6 +267,26 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
268} 267}
269EXPORT_SYMBOL(snd_card_new); 268EXPORT_SYMBOL(snd_card_new);
270 269
270/**
271 * snd_card_ref - Get the card object from the index
272 * @idx: the card index
273 *
274 * Returns a card object corresponding to the given index or NULL if not found.
275 * Release the object via snd_card_unref().
276 */
277struct snd_card *snd_card_ref(int idx)
278{
279 struct snd_card *card;
280
281 mutex_lock(&snd_card_mutex);
282 card = snd_cards[idx];
283 if (card)
284 get_device(&card->card_dev);
285 mutex_unlock(&snd_card_mutex);
286 return card;
287}
288EXPORT_SYMBOL_GPL(snd_card_ref);
289
271/* return non-zero if a card is already locked */ 290/* return non-zero if a card is already locked */
272int snd_card_locked(int card) 291int snd_card_locked(int card)
273{ 292{
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index eb974235c92b..9f48e1d3a257 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -32,53 +32,6 @@
32 32
33/* 33/*
34 * 34 *
35 * Generic memory allocators
36 *
37 */
38
39/**
40 * snd_malloc_pages - allocate pages with the given size
41 * @size: the size to allocate in bytes
42 * @gfp_flags: the allocation conditions, GFP_XXX
43 *
44 * Allocates the physically contiguous pages with the given size.
45 *
46 * Return: The pointer of the buffer, or %NULL if no enough memory.
47 */
48void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
49{
50 int pg;
51
52 if (WARN_ON(!size))
53 return NULL;
54 if (WARN_ON(!gfp_flags))
55 return NULL;
56 gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */
57 pg = get_order(size);
58 return (void *) __get_free_pages(gfp_flags, pg);
59}
60EXPORT_SYMBOL(snd_malloc_pages);
61
62/**
63 * snd_free_pages - release the pages
64 * @ptr: the buffer pointer to release
65 * @size: the allocated buffer size
66 *
67 * Releases the buffer allocated via snd_malloc_pages().
68 */
69void snd_free_pages(void *ptr, size_t size)
70{
71 int pg;
72
73 if (ptr == NULL)
74 return;
75 pg = get_order(size);
76 free_pages((unsigned long) ptr, pg);
77}
78EXPORT_SYMBOL(snd_free_pages);
79
80/*
81 *
82 * Bus-specific memory allocators 35 * Bus-specific memory allocators
83 * 36 *
84 */ 37 */
@@ -190,8 +143,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
190 dmab->bytes = 0; 143 dmab->bytes = 0;
191 switch (type) { 144 switch (type) {
192 case SNDRV_DMA_TYPE_CONTINUOUS: 145 case SNDRV_DMA_TYPE_CONTINUOUS:
193 dmab->area = snd_malloc_pages(size, 146 dmab->area = alloc_pages_exact(size,
194 (__force gfp_t)(unsigned long)device); 147 (__force gfp_t)(unsigned long)device);
195 dmab->addr = 0; 148 dmab->addr = 0;
196 break; 149 break;
197#ifdef CONFIG_HAS_DMA 150#ifdef CONFIG_HAS_DMA
@@ -275,7 +228,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
275{ 228{
276 switch (dmab->dev.type) { 229 switch (dmab->dev.type) {
277 case SNDRV_DMA_TYPE_CONTINUOUS: 230 case SNDRV_DMA_TYPE_CONTINUOUS:
278 snd_free_pages(dmab->area, dmab->bytes); 231 free_pages_exact(dmab->area, dmab->bytes);
279 break; 232 break;
280#ifdef CONFIG_HAS_DMA 233#ifdef CONFIG_HAS_DMA
281#ifdef CONFIG_GENERIC_ALLOCATOR 234#ifdef CONFIG_GENERIC_ALLOCATOR
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 64d904bee8bb..c8618678649c 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1403,24 +1403,32 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1403 1403
1404static int __init alsa_mixer_oss_init(void) 1404static int __init alsa_mixer_oss_init(void)
1405{ 1405{
1406 struct snd_card *card;
1406 int idx; 1407 int idx;
1407 1408
1408 snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; 1409 snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1409 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1410 for (idx = 0; idx < SNDRV_CARDS; idx++) {
1410 if (snd_cards[idx]) 1411 card = snd_card_ref(idx);
1411 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); 1412 if (card) {
1413 snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_REGISTER);
1414 snd_card_unref(card);
1415 }
1412 } 1416 }
1413 return 0; 1417 return 0;
1414} 1418}
1415 1419
1416static void __exit alsa_mixer_oss_exit(void) 1420static void __exit alsa_mixer_oss_exit(void)
1417{ 1421{
1422 struct snd_card *card;
1418 int idx; 1423 int idx;
1419 1424
1420 snd_mixer_oss_notify_callback = NULL; 1425 snd_mixer_oss_notify_callback = NULL;
1421 for (idx = 0; idx < SNDRV_CARDS; idx++) { 1426 for (idx = 0; idx < SNDRV_CARDS; idx++) {
1422 if (snd_cards[idx]) 1427 card = snd_card_ref(idx);
1423 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); 1428 if (card) {
1429 snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_FREE);
1430 snd_card_unref(card);
1431 }
1424 } 1432 }
1425} 1433}
1426 1434
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 7b63aee124af..998e477522fd 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -959,22 +959,22 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
959 return -ENOMEM; 959 return -ENOMEM;
960 960
961 size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)); 961 size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
962 runtime->status = snd_malloc_pages(size, GFP_KERNEL); 962 runtime->status = alloc_pages_exact(size, GFP_KERNEL);
963 if (runtime->status == NULL) { 963 if (runtime->status == NULL) {
964 kfree(runtime); 964 kfree(runtime);
965 return -ENOMEM; 965 return -ENOMEM;
966 } 966 }
967 memset((void*)runtime->status, 0, size); 967 memset(runtime->status, 0, size);
968 968
969 size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)); 969 size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
970 runtime->control = snd_malloc_pages(size, GFP_KERNEL); 970 runtime->control = alloc_pages_exact(size, GFP_KERNEL);
971 if (runtime->control == NULL) { 971 if (runtime->control == NULL) {
972 snd_free_pages((void*)runtime->status, 972 free_pages_exact(runtime->status,
973 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))); 973 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
974 kfree(runtime); 974 kfree(runtime);
975 return -ENOMEM; 975 return -ENOMEM;
976 } 976 }
977 memset((void*)runtime->control, 0, size); 977 memset(runtime->control, 0, size);
978 978
979 init_waitqueue_head(&runtime->sleep); 979 init_waitqueue_head(&runtime->sleep);
980 init_waitqueue_head(&runtime->tsleep); 980 init_waitqueue_head(&runtime->tsleep);
@@ -1000,9 +1000,9 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
1000 runtime = substream->runtime; 1000 runtime = substream->runtime;
1001 if (runtime->private_free != NULL) 1001 if (runtime->private_free != NULL)
1002 runtime->private_free(runtime); 1002 runtime->private_free(runtime);
1003 snd_free_pages((void*)runtime->status, 1003 free_pages_exact(runtime->status,
1004 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))); 1004 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
1005 snd_free_pages((void*)runtime->control, 1005 free_pages_exact(runtime->control,
1006 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); 1006 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
1007 kfree(runtime->hw_constraints.rules); 1007 kfree(runtime->hw_constraints.rules);
1008 /* Avoid concurrent access to runtime via PCM timer interface */ 1008 /* Avoid concurrent access to runtime via PCM timer interface */
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index 2d0e9eaf13aa..77eb1fe1155c 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -30,6 +30,7 @@
30#include <sound/rawmidi.h> 30#include <sound/rawmidi.h>
31#include <sound/seq_kernel.h> 31#include <sound/seq_kernel.h>
32#include <sound/info.h> 32#include <sound/info.h>
33#include "../seq_clientmgr.h"
33 34
34/* max. applications */ 35/* max. applications */
35#define SNDRV_SEQ_OSS_MAX_CLIENTS 16 36#define SNDRV_SEQ_OSS_MAX_CLIENTS 16
@@ -150,11 +151,16 @@ snd_seq_oss_dispatch(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int a
150 return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop); 151 return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
151} 152}
152 153
153/* ioctl */ 154/* ioctl for writeq */
154static inline int 155static inline int
155snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg) 156snd_seq_oss_control(struct seq_oss_devinfo *dp, unsigned int type, void *arg)
156{ 157{
157 return snd_seq_kernel_client_ctl(dp->cseq, type, arg); 158 int err;
159
160 snd_seq_client_ioctl_lock(dp->cseq);
161 err = snd_seq_kernel_client_ctl(dp->cseq, type, arg);
162 snd_seq_client_ioctl_unlock(dp->cseq);
163 return err;
158} 164}
159 165
160/* fill the addresses in header */ 166/* fill the addresses in header */
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
index 30886f5fb100..eb1ef12181f3 100644
--- a/sound/core/seq/oss/seq_oss_rw.c
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -180,14 +180,11 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
180 return 0; /* invalid event - no need to insert queue */ 180 return 0; /* invalid event - no need to insert queue */
181 181
182 event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer); 182 event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
183 if (dp->timer->realtime || !dp->timer->running) { 183 if (dp->timer->realtime || !dp->timer->running)
184 snd_seq_oss_dispatch(dp, &event, 0, 0); 184 snd_seq_oss_dispatch(dp, &event, 0, 0);
185 } else { 185 else
186 if (is_nonblock_mode(dp->file_mode)) 186 rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt,
187 rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0); 187 !is_nonblock_mode(dp->file_mode));
188 else
189 rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0);
190 }
191 return rc; 188 return rc;
192} 189}
193 190
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
index 5e04f4df10e4..b2f69617591f 100644
--- a/sound/core/seq/oss/seq_oss_writeq.c
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -116,7 +116,7 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
116 rec->t.code = SEQ_SYNCTIMER; 116 rec->t.code = SEQ_SYNCTIMER;
117 rec->t.time = time; 117 rec->t.time = time;
118 q->sync_event_put = 1; 118 q->sync_event_put = 1;
119 snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0); 119 snd_seq_kernel_client_enqueue(dp->cseq, &ev, NULL, true);
120 } 120 }
121 121
122 wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ); 122 wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index a11bdc0350fc..b3f593ee752e 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -179,6 +179,41 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
179 return client; 179 return client;
180} 180}
181 181
182/* Take refcount and perform ioctl_mutex lock on the given client;
183 * used only for OSS sequencer
184 * Unlock via snd_seq_client_ioctl_unlock() below
185 */
186bool snd_seq_client_ioctl_lock(int clientid)
187{
188 struct snd_seq_client *client;
189
190 client = snd_seq_client_use_ptr(clientid);
191 if (!client)
192 return false;
193 mutex_lock(&client->ioctl_mutex);
194 /* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */
195 return true;
196}
197EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock);
198
199/* Unlock and unref the given client; for OSS sequencer use only */
200void snd_seq_client_ioctl_unlock(int clientid)
201{
202 struct snd_seq_client *client;
203
204 client = snd_seq_client_use_ptr(clientid);
205 if (WARN_ON(!client))
206 return;
207 mutex_unlock(&client->ioctl_mutex);
208 /* The doubly unrefs below are intentional; the first one releases the
209 * leftover from snd_seq_client_ioctl_lock() above, and the second one
210 * is for releasing snd_seq_client_use_ptr() in this function
211 */
212 snd_seq_client_unlock(client);
213 snd_seq_client_unlock(client);
214}
215EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock);
216
182static void usage_alloc(struct snd_seq_usage *res, int num) 217static void usage_alloc(struct snd_seq_usage *res, int num)
183{ 218{
184 res->cur += num; 219 res->cur += num;
@@ -203,7 +238,6 @@ int __init client_init_data(void)
203 238
204static struct snd_seq_client *seq_create_client1(int client_index, int poolsize) 239static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
205{ 240{
206 unsigned long flags;
207 int c; 241 int c;
208 struct snd_seq_client *client; 242 struct snd_seq_client *client;
209 243
@@ -224,7 +258,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
224 mutex_init(&client->ioctl_mutex); 258 mutex_init(&client->ioctl_mutex);
225 259
226 /* find free slot in the client table */ 260 /* find free slot in the client table */
227 spin_lock_irqsave(&clients_lock, flags); 261 spin_lock_irq(&clients_lock);
228 if (client_index < 0) { 262 if (client_index < 0) {
229 for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN; 263 for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
230 c < SNDRV_SEQ_MAX_CLIENTS; 264 c < SNDRV_SEQ_MAX_CLIENTS;
@@ -232,17 +266,17 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
232 if (clienttab[c] || clienttablock[c]) 266 if (clienttab[c] || clienttablock[c])
233 continue; 267 continue;
234 clienttab[client->number = c] = client; 268 clienttab[client->number = c] = client;
235 spin_unlock_irqrestore(&clients_lock, flags); 269 spin_unlock_irq(&clients_lock);
236 return client; 270 return client;
237 } 271 }
238 } else { 272 } else {
239 if (clienttab[client_index] == NULL && !clienttablock[client_index]) { 273 if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
240 clienttab[client->number = client_index] = client; 274 clienttab[client->number = client_index] = client;
241 spin_unlock_irqrestore(&clients_lock, flags); 275 spin_unlock_irq(&clients_lock);
242 return client; 276 return client;
243 } 277 }
244 } 278 }
245 spin_unlock_irqrestore(&clients_lock, flags); 279 spin_unlock_irq(&clients_lock);
246 snd_seq_pool_delete(&client->pool); 280 snd_seq_pool_delete(&client->pool);
247 kfree(client); 281 kfree(client);
248 return NULL; /* no free slot found or busy, return failure code */ 282 return NULL; /* no free slot found or busy, return failure code */
@@ -251,23 +285,21 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
251 285
252static int seq_free_client1(struct snd_seq_client *client) 286static int seq_free_client1(struct snd_seq_client *client)
253{ 287{
254 unsigned long flags;
255
256 if (!client) 288 if (!client)
257 return 0; 289 return 0;
258 spin_lock_irqsave(&clients_lock, flags); 290 spin_lock_irq(&clients_lock);
259 clienttablock[client->number] = 1; 291 clienttablock[client->number] = 1;
260 clienttab[client->number] = NULL; 292 clienttab[client->number] = NULL;
261 spin_unlock_irqrestore(&clients_lock, flags); 293 spin_unlock_irq(&clients_lock);
262 snd_seq_delete_all_ports(client); 294 snd_seq_delete_all_ports(client);
263 snd_seq_queue_client_leave(client->number); 295 snd_seq_queue_client_leave(client->number);
264 snd_use_lock_sync(&client->use_lock); 296 snd_use_lock_sync(&client->use_lock);
265 snd_seq_queue_client_termination(client->number); 297 snd_seq_queue_client_termination(client->number);
266 if (client->pool) 298 if (client->pool)
267 snd_seq_pool_delete(&client->pool); 299 snd_seq_pool_delete(&client->pool);
268 spin_lock_irqsave(&clients_lock, flags); 300 spin_lock_irq(&clients_lock);
269 clienttablock[client->number] = 0; 301 clienttablock[client->number] = 0;
270 spin_unlock_irqrestore(&clients_lock, flags); 302 spin_unlock_irq(&clients_lock);
271 return 0; 303 return 0;
272} 304}
273 305
@@ -1900,20 +1932,14 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
1900 int result; 1932 int result;
1901 struct snd_seq_client *sender = NULL; 1933 struct snd_seq_client *sender = NULL;
1902 struct snd_seq_client_port *sport = NULL; 1934 struct snd_seq_client_port *sport = NULL;
1903 struct snd_seq_subscribers *p;
1904 1935
1905 result = -EINVAL; 1936 result = -EINVAL;
1906 if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL) 1937 if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
1907 goto __end; 1938 goto __end;
1908 if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL) 1939 if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
1909 goto __end; 1940 goto __end;
1910 p = snd_seq_port_get_subscription(&sport->c_src, &subs->dest); 1941 result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
1911 if (p) { 1942 subs);
1912 result = 0;
1913 *subs = p->info;
1914 } else
1915 result = -ENOENT;
1916
1917 __end: 1943 __end:
1918 if (sport) 1944 if (sport)
1919 snd_seq_port_unlock(sport); 1945 snd_seq_port_unlock(sport);
@@ -2227,12 +2253,13 @@ int snd_seq_delete_kernel_client(int client)
2227} 2253}
2228EXPORT_SYMBOL(snd_seq_delete_kernel_client); 2254EXPORT_SYMBOL(snd_seq_delete_kernel_client);
2229 2255
2230/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue 2256/*
2231 * and snd_seq_kernel_client_enqueue_blocking 2257 * exported, called by kernel clients to enqueue events (w/o blocking)
2258 *
2259 * RETURN VALUE: zero if succeed, negative if error
2232 */ 2260 */
2233static int kernel_client_enqueue(int client, struct snd_seq_event *ev, 2261int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
2234 struct file *file, int blocking, 2262 struct file *file, bool blocking)
2235 int atomic, int hop)
2236{ 2263{
2237 struct snd_seq_client *cptr; 2264 struct snd_seq_client *cptr;
2238 int result; 2265 int result;
@@ -2255,41 +2282,21 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
2255 if (cptr == NULL) 2282 if (cptr == NULL)
2256 return -EINVAL; 2283 return -EINVAL;
2257 2284
2258 if (! cptr->accept_output) 2285 if (!cptr->accept_output) {
2259 result = -EPERM; 2286 result = -EPERM;
2260 else /* send it */ 2287 } else { /* send it */
2288 mutex_lock(&cptr->ioctl_mutex);
2261 result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, 2289 result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
2262 atomic, hop, NULL); 2290 false, 0,
2291 &cptr->ioctl_mutex);
2292 mutex_unlock(&cptr->ioctl_mutex);
2293 }
2263 2294
2264 snd_seq_client_unlock(cptr); 2295 snd_seq_client_unlock(cptr);
2265 return result; 2296 return result;
2266} 2297}
2267
2268/*
2269 * exported, called by kernel clients to enqueue events (w/o blocking)
2270 *
2271 * RETURN VALUE: zero if succeed, negative if error
2272 */
2273int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
2274 int atomic, int hop)
2275{
2276 return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
2277}
2278EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); 2298EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
2279 2299
2280/*
2281 * exported, called by kernel clients to enqueue events (with blocking)
2282 *
2283 * RETURN VALUE: zero if succeed, negative if error
2284 */
2285int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
2286 struct file *file,
2287 int atomic, int hop)
2288{
2289 return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
2290}
2291EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
2292
2293/* 2300/*
2294 * exported, called by kernel clients to dispatch events directly to other 2301 * exported, called by kernel clients to dispatch events directly to other
2295 * clients, bypassing the queues. Event time-stamp will be updated. 2302 * clients, bypassing the queues. Event time-stamp will be updated.
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index 0611e1e0ed5b..28a51dcc0190 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -93,14 +93,14 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid);
93/* dispatch event to client(s) */ 93/* dispatch event to client(s) */
94int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop); 94int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop);
95 95
96/* exported to other modules */
97int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev, int atomic, int hop);
98int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev,
99 struct file *file, int atomic, int hop);
100int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait); 96int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait);
101int snd_seq_client_notify_subscription(int client, int port, 97int snd_seq_client_notify_subscription(int client, int port,
102 struct snd_seq_port_subscribe *info, int evtype); 98 struct snd_seq_port_subscribe *info, int evtype);
103 99
100/* only for OSS sequencer */
101bool snd_seq_client_ioctl_lock(int clientid);
102void snd_seq_client_ioctl_unlock(int clientid);
103
104extern int seq_client_load[15]; 104extern int seq_client_load[15];
105 105
106#endif 106#endif
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 72c0302a55d2..97ee89cb6426 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -98,18 +98,17 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f);
98void snd_seq_fifo_clear(struct snd_seq_fifo *f) 98void snd_seq_fifo_clear(struct snd_seq_fifo *f)
99{ 99{
100 struct snd_seq_event_cell *cell; 100 struct snd_seq_event_cell *cell;
101 unsigned long flags;
102 101
103 /* clear overflow flag */ 102 /* clear overflow flag */
104 atomic_set(&f->overflow, 0); 103 atomic_set(&f->overflow, 0);
105 104
106 snd_use_lock_sync(&f->use_lock); 105 snd_use_lock_sync(&f->use_lock);
107 spin_lock_irqsave(&f->lock, flags); 106 spin_lock_irq(&f->lock);
108 /* drain the fifo */ 107 /* drain the fifo */
109 while ((cell = fifo_cell_out(f)) != NULL) { 108 while ((cell = fifo_cell_out(f)) != NULL) {
110 snd_seq_cell_free(cell); 109 snd_seq_cell_free(cell);
111 } 110 }
112 spin_unlock_irqrestore(&f->lock, flags); 111 spin_unlock_irq(&f->lock);
113} 112}
114 113
115 114
@@ -195,9 +194,9 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,
195 } 194 }
196 set_current_state(TASK_INTERRUPTIBLE); 195 set_current_state(TASK_INTERRUPTIBLE);
197 add_wait_queue(&f->input_sleep, &wait); 196 add_wait_queue(&f->input_sleep, &wait);
198 spin_unlock_irq(&f->lock); 197 spin_unlock_irqrestore(&f->lock, flags);
199 schedule(); 198 schedule();
200 spin_lock_irq(&f->lock); 199 spin_lock_irqsave(&f->lock, flags);
201 remove_wait_queue(&f->input_sleep, &wait); 200 remove_wait_queue(&f->input_sleep, &wait);
202 if (signal_pending(current)) { 201 if (signal_pending(current)) {
203 spin_unlock_irqrestore(&f->lock, flags); 202 spin_unlock_irqrestore(&f->lock, flags);
@@ -239,7 +238,6 @@ int snd_seq_fifo_poll_wait(struct snd_seq_fifo *f, struct file *file,
239/* change the size of pool; all old events are removed */ 238/* change the size of pool; all old events are removed */
240int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) 239int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
241{ 240{
242 unsigned long flags;
243 struct snd_seq_pool *newpool, *oldpool; 241 struct snd_seq_pool *newpool, *oldpool;
244 struct snd_seq_event_cell *cell, *next, *oldhead; 242 struct snd_seq_event_cell *cell, *next, *oldhead;
245 243
@@ -255,7 +253,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
255 return -ENOMEM; 253 return -ENOMEM;
256 } 254 }
257 255
258 spin_lock_irqsave(&f->lock, flags); 256 spin_lock_irq(&f->lock);
259 /* remember old pool */ 257 /* remember old pool */
260 oldpool = f->pool; 258 oldpool = f->pool;
261 oldhead = f->head; 259 oldhead = f->head;
@@ -265,7 +263,7 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
265 f->tail = NULL; 263 f->tail = NULL;
266 f->cells = 0; 264 f->cells = 0;
267 /* NOTE: overflow flag is not cleared */ 265 /* NOTE: overflow flag is not cleared */
268 spin_unlock_irqrestore(&f->lock, flags); 266 spin_unlock_irq(&f->lock);
269 267
270 /* close the old pool and wait until all users are gone */ 268 /* close the old pool and wait until all users are gone */
271 snd_seq_pool_mark_closing(oldpool); 269 snd_seq_pool_mark_closing(oldpool);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 5b0388202bac..19b718e871c5 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -24,7 +24,7 @@
24#include <linux/export.h> 24#include <linux/export.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/sched/signal.h> 26#include <linux/sched/signal.h>
27#include <linux/vmalloc.h> 27#include <linux/mm.h>
28#include <sound/core.h> 28#include <sound/core.h>
29 29
30#include <sound/seq_kernel.h> 30#include <sound/seq_kernel.h>
@@ -244,13 +244,13 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
244 244
245 set_current_state(TASK_INTERRUPTIBLE); 245 set_current_state(TASK_INTERRUPTIBLE);
246 add_wait_queue(&pool->output_sleep, &wait); 246 add_wait_queue(&pool->output_sleep, &wait);
247 spin_unlock_irq(&pool->lock); 247 spin_unlock_irqrestore(&pool->lock, flags);
248 if (mutexp) 248 if (mutexp)
249 mutex_unlock(mutexp); 249 mutex_unlock(mutexp);
250 schedule(); 250 schedule();
251 if (mutexp) 251 if (mutexp)
252 mutex_lock(mutexp); 252 mutex_lock(mutexp);
253 spin_lock_irq(&pool->lock); 253 spin_lock_irqsave(&pool->lock, flags);
254 remove_wait_queue(&pool->output_sleep, &wait); 254 remove_wait_queue(&pool->output_sleep, &wait);
255 /* interrupted? */ 255 /* interrupted? */
256 if (signal_pending(current)) { 256 if (signal_pending(current)) {
@@ -384,21 +384,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
384{ 384{
385 int cell; 385 int cell;
386 struct snd_seq_event_cell *cellptr; 386 struct snd_seq_event_cell *cellptr;
387 unsigned long flags;
388 387
389 if (snd_BUG_ON(!pool)) 388 if (snd_BUG_ON(!pool))
390 return -EINVAL; 389 return -EINVAL;
391 390
392 cellptr = vmalloc(array_size(sizeof(struct snd_seq_event_cell), 391 cellptr = kvmalloc_array(sizeof(struct snd_seq_event_cell), pool->size,
393 pool->size)); 392 GFP_KERNEL);
394 if (!cellptr) 393 if (!cellptr)
395 return -ENOMEM; 394 return -ENOMEM;
396 395
397 /* add new cells to the free cell list */ 396 /* add new cells to the free cell list */
398 spin_lock_irqsave(&pool->lock, flags); 397 spin_lock_irq(&pool->lock);
399 if (pool->ptr) { 398 if (pool->ptr) {
400 spin_unlock_irqrestore(&pool->lock, flags); 399 spin_unlock_irq(&pool->lock);
401 vfree(cellptr); 400 kvfree(cellptr);
402 return 0; 401 return 0;
403 } 402 }
404 403
@@ -416,7 +415,7 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
416 /* init statistics */ 415 /* init statistics */
417 pool->max_used = 0; 416 pool->max_used = 0;
418 pool->total_elements = pool->size; 417 pool->total_elements = pool->size;
419 spin_unlock_irqrestore(&pool->lock, flags); 418 spin_unlock_irq(&pool->lock);
420 return 0; 419 return 0;
421} 420}
422 421
@@ -435,7 +434,6 @@ void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
435/* remove events */ 434/* remove events */
436int snd_seq_pool_done(struct snd_seq_pool *pool) 435int snd_seq_pool_done(struct snd_seq_pool *pool)
437{ 436{
438 unsigned long flags;
439 struct snd_seq_event_cell *ptr; 437 struct snd_seq_event_cell *ptr;
440 438
441 if (snd_BUG_ON(!pool)) 439 if (snd_BUG_ON(!pool))
@@ -449,18 +447,18 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
449 schedule_timeout_uninterruptible(1); 447 schedule_timeout_uninterruptible(1);
450 448
451 /* release all resources */ 449 /* release all resources */
452 spin_lock_irqsave(&pool->lock, flags); 450 spin_lock_irq(&pool->lock);
453 ptr = pool->ptr; 451 ptr = pool->ptr;
454 pool->ptr = NULL; 452 pool->ptr = NULL;
455 pool->free = NULL; 453 pool->free = NULL;
456 pool->total_elements = 0; 454 pool->total_elements = 0;
457 spin_unlock_irqrestore(&pool->lock, flags); 455 spin_unlock_irq(&pool->lock);
458 456
459 vfree(ptr); 457 kvfree(ptr);
460 458
461 spin_lock_irqsave(&pool->lock, flags); 459 spin_lock_irq(&pool->lock);
462 pool->closing = 0; 460 pool->closing = 0;
463 spin_unlock_irqrestore(&pool->lock, flags); 461 spin_unlock_irq(&pool->lock);
464 462
465 return 0; 463 return 0;
466} 464}
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 24d90abfc64d..ac7556ab531c 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -128,7 +128,6 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
128struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, 128struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
129 int port) 129 int port)
130{ 130{
131 unsigned long flags;
132 struct snd_seq_client_port *new_port, *p; 131 struct snd_seq_client_port *new_port, *p;
133 int num = -1; 132 int num = -1;
134 133
@@ -157,7 +156,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
157 156
158 num = port >= 0 ? port : 0; 157 num = port >= 0 ? port : 0;
159 mutex_lock(&client->ports_mutex); 158 mutex_lock(&client->ports_mutex);
160 write_lock_irqsave(&client->ports_lock, flags); 159 write_lock_irq(&client->ports_lock);
161 list_for_each_entry(p, &client->ports_list_head, list) { 160 list_for_each_entry(p, &client->ports_list_head, list) {
162 if (p->addr.port > num) 161 if (p->addr.port > num)
163 break; 162 break;
@@ -169,7 +168,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
169 client->num_ports++; 168 client->num_ports++;
170 new_port->addr.port = num; /* store the port number in the port */ 169 new_port->addr.port = num; /* store the port number in the port */
171 sprintf(new_port->name, "port-%d", num); 170 sprintf(new_port->name, "port-%d", num);
172 write_unlock_irqrestore(&client->ports_lock, flags); 171 write_unlock_irq(&client->ports_lock);
173 mutex_unlock(&client->ports_mutex); 172 mutex_unlock(&client->ports_mutex);
174 173
175 return new_port; 174 return new_port;
@@ -283,11 +282,10 @@ static int port_delete(struct snd_seq_client *client,
283/* delete a port with the given port id */ 282/* delete a port with the given port id */
284int snd_seq_delete_port(struct snd_seq_client *client, int port) 283int snd_seq_delete_port(struct snd_seq_client *client, int port)
285{ 284{
286 unsigned long flags;
287 struct snd_seq_client_port *found = NULL, *p; 285 struct snd_seq_client_port *found = NULL, *p;
288 286
289 mutex_lock(&client->ports_mutex); 287 mutex_lock(&client->ports_mutex);
290 write_lock_irqsave(&client->ports_lock, flags); 288 write_lock_irq(&client->ports_lock);
291 list_for_each_entry(p, &client->ports_list_head, list) { 289 list_for_each_entry(p, &client->ports_list_head, list) {
292 if (p->addr.port == port) { 290 if (p->addr.port == port) {
293 /* ok found. delete from the list at first */ 291 /* ok found. delete from the list at first */
@@ -297,7 +295,7 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
297 break; 295 break;
298 } 296 }
299 } 297 }
300 write_unlock_irqrestore(&client->ports_lock, flags); 298 write_unlock_irq(&client->ports_lock);
301 mutex_unlock(&client->ports_mutex); 299 mutex_unlock(&client->ports_mutex);
302 if (found) 300 if (found)
303 return port_delete(client, found); 301 return port_delete(client, found);
@@ -308,7 +306,6 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
308/* delete the all ports belonging to the given client */ 306/* delete the all ports belonging to the given client */
309int snd_seq_delete_all_ports(struct snd_seq_client *client) 307int snd_seq_delete_all_ports(struct snd_seq_client *client)
310{ 308{
311 unsigned long flags;
312 struct list_head deleted_list; 309 struct list_head deleted_list;
313 struct snd_seq_client_port *port, *tmp; 310 struct snd_seq_client_port *port, *tmp;
314 311
@@ -316,7 +313,7 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
316 * clear the port list in the client data. 313 * clear the port list in the client data.
317 */ 314 */
318 mutex_lock(&client->ports_mutex); 315 mutex_lock(&client->ports_mutex);
319 write_lock_irqsave(&client->ports_lock, flags); 316 write_lock_irq(&client->ports_lock);
320 if (! list_empty(&client->ports_list_head)) { 317 if (! list_empty(&client->ports_list_head)) {
321 list_add(&deleted_list, &client->ports_list_head); 318 list_add(&deleted_list, &client->ports_list_head);
322 list_del_init(&client->ports_list_head); 319 list_del_init(&client->ports_list_head);
@@ -324,7 +321,7 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client)
324 INIT_LIST_HEAD(&deleted_list); 321 INIT_LIST_HEAD(&deleted_list);
325 } 322 }
326 client->num_ports = 0; 323 client->num_ports = 0;
327 write_unlock_irqrestore(&client->ports_lock, flags); 324 write_unlock_irq(&client->ports_lock);
328 325
329 /* remove each port in deleted_list */ 326 /* remove each port in deleted_list */
330 list_for_each_entry_safe(port, tmp, &deleted_list, list) { 327 list_for_each_entry_safe(port, tmp, &deleted_list, list) {
@@ -550,10 +547,10 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
550 list_del_init(list); 547 list_del_init(list);
551 grp->exclusive = 0; 548 grp->exclusive = 0;
552 write_unlock_irq(&grp->list_lock); 549 write_unlock_irq(&grp->list_lock);
553 up_write(&grp->list_mutex);
554 550
555 if (!empty) 551 if (!empty)
556 unsubscribe_port(client, port, grp, &subs->info, ack); 552 unsubscribe_port(client, port, grp, &subs->info, ack);
553 up_write(&grp->list_mutex);
557} 554}
558 555
559/* connect two ports */ 556/* connect two ports */
@@ -635,20 +632,23 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
635 632
636 633
637/* get matched subscriber */ 634/* get matched subscriber */
638struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, 635int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
639 struct snd_seq_addr *dest_addr) 636 struct snd_seq_addr *dest_addr,
637 struct snd_seq_port_subscribe *subs)
640{ 638{
641 struct snd_seq_subscribers *s, *found = NULL; 639 struct snd_seq_subscribers *s;
640 int err = -ENOENT;
642 641
643 down_read(&src_grp->list_mutex); 642 down_read(&src_grp->list_mutex);
644 list_for_each_entry(s, &src_grp->list_head, src_list) { 643 list_for_each_entry(s, &src_grp->list_head, src_list) {
645 if (addr_match(dest_addr, &s->info.dest)) { 644 if (addr_match(dest_addr, &s->info.dest)) {
646 found = s; 645 *subs = s->info;
646 err = 0;
647 break; 647 break;
648 } 648 }
649 } 649 }
650 up_read(&src_grp->list_mutex); 650 up_read(&src_grp->list_mutex);
651 return found; 651 return err;
652} 652}
653 653
654/* 654/*
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
index 26bd71f36c41..06003b36652e 100644
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -135,7 +135,8 @@ int snd_seq_port_subscribe(struct snd_seq_client_port *port,
135 struct snd_seq_port_subscribe *info); 135 struct snd_seq_port_subscribe *info);
136 136
137/* get matched subscriber */ 137/* get matched subscriber */
138struct snd_seq_subscribers *snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, 138int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
139 struct snd_seq_addr *dest_addr); 139 struct snd_seq_addr *dest_addr,
140 struct snd_seq_port_subscribe *subs);
140 141
141#endif 142#endif
diff --git a/sound/core/sound.c b/sound/core/sound.c
index b30f027eb0fe..a9ad4379523b 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -134,8 +134,11 @@ static struct snd_minor *autoload_device(unsigned int minor)
134 if (dev == SNDRV_MINOR_CONTROL) { 134 if (dev == SNDRV_MINOR_CONTROL) {
135 /* /dev/aloadC? */ 135 /* /dev/aloadC? */
136 int card = SNDRV_MINOR_CARD(minor); 136 int card = SNDRV_MINOR_CARD(minor);
137 if (snd_cards[card] == NULL) 137 struct snd_card *ref = snd_card_ref(card);
138 if (!ref)
138 snd_request_card(card); 139 snd_request_card(card);
140 else
141 snd_card_unref(ref);
139 } else if (dev == SNDRV_MINOR_GLOBAL) { 142 } else if (dev == SNDRV_MINOR_GLOBAL) {
140 /* /dev/aloadSEQ */ 143 /* /dev/aloadSEQ */
141 snd_request_other(minor); 144 snd_request_other(minor);
diff --git a/sound/core/timer.c b/sound/core/timer.c
index b842b61f66c2..e3973957b392 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -38,6 +38,7 @@
38 38
39/* internal flags */ 39/* internal flags */
40#define SNDRV_TIMER_IFLG_PAUSED 0x00010000 40#define SNDRV_TIMER_IFLG_PAUSED 0x00010000
41#define SNDRV_TIMER_IFLG_DEAD 0x00020000
41 42
42#if IS_ENABLED(CONFIG_SND_HRTIMER) 43#if IS_ENABLED(CONFIG_SND_HRTIMER)
43#define DEFAULT_TIMER_LIMIT 4 44#define DEFAULT_TIMER_LIMIT 4
@@ -254,19 +255,20 @@ int snd_timer_open(struct snd_timer_instance **ti,
254 struct snd_timer_instance *timeri = NULL; 255 struct snd_timer_instance *timeri = NULL;
255 int err; 256 int err;
256 257
258 mutex_lock(&register_mutex);
257 if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { 259 if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
258 /* open a slave instance */ 260 /* open a slave instance */
259 if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE || 261 if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
260 tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) { 262 tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
261 pr_debug("ALSA: timer: invalid slave class %i\n", 263 pr_debug("ALSA: timer: invalid slave class %i\n",
262 tid->dev_sclass); 264 tid->dev_sclass);
263 return -EINVAL; 265 err = -EINVAL;
266 goto unlock;
264 } 267 }
265 mutex_lock(&register_mutex);
266 timeri = snd_timer_instance_new(owner, NULL); 268 timeri = snd_timer_instance_new(owner, NULL);
267 if (!timeri) { 269 if (!timeri) {
268 mutex_unlock(&register_mutex); 270 err = -ENOMEM;
269 return -ENOMEM; 271 goto unlock;
270 } 272 }
271 timeri->slave_class = tid->dev_sclass; 273 timeri->slave_class = tid->dev_sclass;
272 timeri->slave_id = tid->device; 274 timeri->slave_id = tid->device;
@@ -277,13 +279,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
277 snd_timer_close_locked(timeri); 279 snd_timer_close_locked(timeri);
278 timeri = NULL; 280 timeri = NULL;
279 } 281 }
280 mutex_unlock(&register_mutex); 282 goto unlock;
281 *ti = timeri;
282 return err;
283 } 283 }
284 284
285 /* open a master instance */ 285 /* open a master instance */
286 mutex_lock(&register_mutex);
287 timer = snd_timer_find(tid); 286 timer = snd_timer_find(tid);
288#ifdef CONFIG_MODULES 287#ifdef CONFIG_MODULES
289 if (!timer) { 288 if (!timer) {
@@ -294,25 +293,26 @@ int snd_timer_open(struct snd_timer_instance **ti,
294 } 293 }
295#endif 294#endif
296 if (!timer) { 295 if (!timer) {
297 mutex_unlock(&register_mutex); 296 err = -ENODEV;
298 return -ENODEV; 297 goto unlock;
299 } 298 }
300 if (!list_empty(&timer->open_list_head)) { 299 if (!list_empty(&timer->open_list_head)) {
301 timeri = list_entry(timer->open_list_head.next, 300 timeri = list_entry(timer->open_list_head.next,
302 struct snd_timer_instance, open_list); 301 struct snd_timer_instance, open_list);
303 if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { 302 if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
304 mutex_unlock(&register_mutex); 303 err = -EBUSY;
305 return -EBUSY; 304 timeri = NULL;
305 goto unlock;
306 } 306 }
307 } 307 }
308 if (timer->num_instances >= timer->max_instances) { 308 if (timer->num_instances >= timer->max_instances) {
309 mutex_unlock(&register_mutex); 309 err = -EBUSY;
310 return -EBUSY; 310 goto unlock;
311 } 311 }
312 timeri = snd_timer_instance_new(owner, timer); 312 timeri = snd_timer_instance_new(owner, timer);
313 if (!timeri) { 313 if (!timeri) {
314 mutex_unlock(&register_mutex); 314 err = -ENOMEM;
315 return -ENOMEM; 315 goto unlock;
316 } 316 }
317 /* take a card refcount for safe disconnection */ 317 /* take a card refcount for safe disconnection */
318 if (timer->card) 318 if (timer->card)
@@ -321,16 +321,16 @@ int snd_timer_open(struct snd_timer_instance **ti,
321 timeri->slave_id = slave_id; 321 timeri->slave_id = slave_id;
322 322
323 if (list_empty(&timer->open_list_head) && timer->hw.open) { 323 if (list_empty(&timer->open_list_head) && timer->hw.open) {
324 int err = timer->hw.open(timer); 324 err = timer->hw.open(timer);
325 if (err) { 325 if (err) {
326 kfree(timeri->owner); 326 kfree(timeri->owner);
327 kfree(timeri); 327 kfree(timeri);
328 timeri = NULL;
328 329
329 if (timer->card) 330 if (timer->card)
330 put_device(&timer->card->card_dev); 331 put_device(&timer->card->card_dev);
331 module_put(timer->module); 332 module_put(timer->module);
332 mutex_unlock(&register_mutex); 333 goto unlock;
333 return err;
334 } 334 }
335 } 335 }
336 336
@@ -341,6 +341,8 @@ int snd_timer_open(struct snd_timer_instance **ti,
341 snd_timer_close_locked(timeri); 341 snd_timer_close_locked(timeri);
342 timeri = NULL; 342 timeri = NULL;
343 } 343 }
344
345 unlock:
344 mutex_unlock(&register_mutex); 346 mutex_unlock(&register_mutex);
345 *ti = timeri; 347 *ti = timeri;
346 return err; 348 return err;
@@ -353,15 +355,20 @@ EXPORT_SYMBOL(snd_timer_open);
353 */ 355 */
354static int snd_timer_close_locked(struct snd_timer_instance *timeri) 356static int snd_timer_close_locked(struct snd_timer_instance *timeri)
355{ 357{
356 struct snd_timer *timer = NULL; 358 struct snd_timer *timer = timeri->timer;
357 struct snd_timer_instance *slave, *tmp; 359 struct snd_timer_instance *slave, *tmp;
358 360
361 if (timer) {
362 spin_lock_irq(&timer->lock);
363 timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
364 spin_unlock_irq(&timer->lock);
365 }
366
359 list_del(&timeri->open_list); 367 list_del(&timeri->open_list);
360 368
361 /* force to stop the timer */ 369 /* force to stop the timer */
362 snd_timer_stop(timeri); 370 snd_timer_stop(timeri);
363 371
364 timer = timeri->timer;
365 if (timer) { 372 if (timer) {
366 timer->num_instances--; 373 timer->num_instances--;
367 /* wait, until the active callback is finished */ 374 /* wait, until the active callback is finished */
@@ -497,6 +504,10 @@ static int snd_timer_start1(struct snd_timer_instance *timeri,
497 return -EINVAL; 504 return -EINVAL;
498 505
499 spin_lock_irqsave(&timer->lock, flags); 506 spin_lock_irqsave(&timer->lock, flags);
507 if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
508 result = -EINVAL;
509 goto unlock;
510 }
500 if (timer->card && timer->card->shutdown) { 511 if (timer->card && timer->card->shutdown) {
501 result = -ENODEV; 512 result = -ENODEV;
502 goto unlock; 513 goto unlock;
@@ -541,11 +552,16 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
541 bool start) 552 bool start)
542{ 553{
543 unsigned long flags; 554 unsigned long flags;
555 int err;
544 556
545 spin_lock_irqsave(&slave_active_lock, flags); 557 spin_lock_irqsave(&slave_active_lock, flags);
558 if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
559 err = -EINVAL;
560 goto unlock;
561 }
546 if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { 562 if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
547 spin_unlock_irqrestore(&slave_active_lock, flags); 563 err = -EBUSY;
548 return -EBUSY; 564 goto unlock;
549 } 565 }
550 timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; 566 timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
551 if (timeri->master && timeri->timer) { 567 if (timeri->master && timeri->timer) {
@@ -556,8 +572,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri,
556 SNDRV_TIMER_EVENT_CONTINUE); 572 SNDRV_TIMER_EVENT_CONTINUE);
557 spin_unlock(&timeri->timer->lock); 573 spin_unlock(&timeri->timer->lock);
558 } 574 }
575 err = 1; /* delayed start */
576 unlock:
559 spin_unlock_irqrestore(&slave_active_lock, flags); 577 spin_unlock_irqrestore(&slave_active_lock, flags);
560 return 1; /* delayed start */ 578 return err;
561} 579}
562 580
563/* stop/pause a master timer */ 581/* stop/pause a master timer */
@@ -720,6 +738,46 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
720 timer->sticks = ticks; 738 timer->sticks = ticks;
721} 739}
722 740
741/* call callbacks in timer ack list */
742static void snd_timer_process_callbacks(struct snd_timer *timer,
743 struct list_head *head)
744{
745 struct snd_timer_instance *ti;
746 unsigned long resolution, ticks;
747
748 while (!list_empty(head)) {
749 ti = list_first_entry(head, struct snd_timer_instance,
750 ack_list);
751
752 /* remove from ack_list and make empty */
753 list_del_init(&ti->ack_list);
754
755 if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) {
756 ticks = ti->pticks;
757 ti->pticks = 0;
758 resolution = ti->resolution;
759 ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
760 spin_unlock(&timer->lock);
761 if (ti->callback)
762 ti->callback(ti, resolution, ticks);
763 spin_lock(&timer->lock);
764 ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
765 }
766 }
767}
768
769/* clear pending instances from ack list */
770static void snd_timer_clear_callbacks(struct snd_timer *timer,
771 struct list_head *head)
772{
773 unsigned long flags;
774
775 spin_lock_irqsave(&timer->lock, flags);
776 while (!list_empty(head))
777 list_del_init(head->next);
778 spin_unlock_irqrestore(&timer->lock, flags);
779}
780
723/* 781/*
724 * timer tasklet 782 * timer tasklet
725 * 783 *
@@ -727,34 +785,15 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
727static void snd_timer_tasklet(unsigned long arg) 785static void snd_timer_tasklet(unsigned long arg)
728{ 786{
729 struct snd_timer *timer = (struct snd_timer *) arg; 787 struct snd_timer *timer = (struct snd_timer *) arg;
730 struct snd_timer_instance *ti;
731 struct list_head *p;
732 unsigned long resolution, ticks;
733 unsigned long flags; 788 unsigned long flags;
734 789
735 if (timer->card && timer->card->shutdown) 790 if (timer->card && timer->card->shutdown) {
791 snd_timer_clear_callbacks(timer, &timer->sack_list_head);
736 return; 792 return;
793 }
737 794
738 spin_lock_irqsave(&timer->lock, flags); 795 spin_lock_irqsave(&timer->lock, flags);
739 /* now process all callbacks */ 796 snd_timer_process_callbacks(timer, &timer->sack_list_head);
740 while (!list_empty(&timer->sack_list_head)) {
741 p = timer->sack_list_head.next; /* get first item */
742 ti = list_entry(p, struct snd_timer_instance, ack_list);
743
744 /* remove from ack_list and make empty */
745 list_del_init(p);
746
747 ticks = ti->pticks;
748 ti->pticks = 0;
749 resolution = ti->resolution;
750
751 ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
752 spin_unlock(&timer->lock);
753 if (ti->callback)
754 ti->callback(ti, resolution, ticks);
755 spin_lock(&timer->lock);
756 ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
757 }
758 spin_unlock_irqrestore(&timer->lock, flags); 797 spin_unlock_irqrestore(&timer->lock, flags);
759} 798}
760 799
@@ -767,16 +806,18 @@ static void snd_timer_tasklet(unsigned long arg)
767void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) 806void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
768{ 807{
769 struct snd_timer_instance *ti, *ts, *tmp; 808 struct snd_timer_instance *ti, *ts, *tmp;
770 unsigned long resolution, ticks; 809 unsigned long resolution;
771 struct list_head *p, *ack_list_head; 810 struct list_head *ack_list_head;
772 unsigned long flags; 811 unsigned long flags;
773 int use_tasklet = 0; 812 int use_tasklet = 0;
774 813
775 if (timer == NULL) 814 if (timer == NULL)
776 return; 815 return;
777 816
778 if (timer->card && timer->card->shutdown) 817 if (timer->card && timer->card->shutdown) {
818 snd_timer_clear_callbacks(timer, &timer->ack_list_head);
779 return; 819 return;
820 }
780 821
781 spin_lock_irqsave(&timer->lock, flags); 822 spin_lock_irqsave(&timer->lock, flags);
782 823
@@ -790,6 +831,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
790 */ 831 */
791 list_for_each_entry_safe(ti, tmp, &timer->active_list_head, 832 list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
792 active_list) { 833 active_list) {
834 if (ti->flags & SNDRV_TIMER_IFLG_DEAD)
835 continue;
793 if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) 836 if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
794 continue; 837 continue;
795 ti->pticks += ticks_left; 838 ti->pticks += ticks_left;
@@ -839,23 +882,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
839 } 882 }
840 883
841 /* now process all fast callbacks */ 884 /* now process all fast callbacks */
842 while (!list_empty(&timer->ack_list_head)) { 885 snd_timer_process_callbacks(timer, &timer->ack_list_head);
843 p = timer->ack_list_head.next; /* get first item */
844 ti = list_entry(p, struct snd_timer_instance, ack_list);
845
846 /* remove from ack_list and make empty */
847 list_del_init(p);
848
849 ticks = ti->pticks;
850 ti->pticks = 0;
851
852 ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
853 spin_unlock(&timer->lock);
854 if (ti->callback)
855 ti->callback(ti, resolution, ticks);
856 spin_lock(&timer->lock);
857 ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
858 }
859 886
860 /* do we have any slow callbacks? */ 887 /* do we have any slow callbacks? */
861 use_tasklet = !list_empty(&timer->sack_list_head); 888 use_tasklet = !list_empty(&timer->sack_list_head);
@@ -1882,7 +1909,10 @@ static int snd_timer_user_start(struct file *file)
1882 snd_timer_stop(tu->timeri); 1909 snd_timer_stop(tu->timeri);
1883 tu->timeri->lost = 0; 1910 tu->timeri->lost = 0;
1884 tu->last_resolution = 0; 1911 tu->last_resolution = 0;
1885 return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0; 1912 err = snd_timer_start(tu->timeri, tu->ticks);
1913 if (err < 0)
1914 return err;
1915 return 0;
1886} 1916}
1887 1917
1888static int snd_timer_user_stop(struct file *file) 1918static int snd_timer_user_stop(struct file *file)
@@ -1893,7 +1923,10 @@ static int snd_timer_user_stop(struct file *file)
1893 tu = file->private_data; 1923 tu = file->private_data;
1894 if (!tu->timeri) 1924 if (!tu->timeri)
1895 return -EBADFD; 1925 return -EBADFD;
1896 return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0; 1926 err = snd_timer_stop(tu->timeri);
1927 if (err < 0)
1928 return err;
1929 return 0;
1897} 1930}
1898 1931
1899static int snd_timer_user_continue(struct file *file) 1932static int snd_timer_user_continue(struct file *file)
@@ -1908,7 +1941,10 @@ static int snd_timer_user_continue(struct file *file)
1908 if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED)) 1941 if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
1909 return snd_timer_user_start(file); 1942 return snd_timer_user_start(file);
1910 tu->timeri->lost = 0; 1943 tu->timeri->lost = 0;
1911 return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; 1944 err = snd_timer_continue(tu->timeri);
1945 if (err < 0)
1946 return err;
1947 return 0;
1912} 1948}
1913 1949
1914static int snd_timer_user_pause(struct file *file) 1950static int snd_timer_user_pause(struct file *file)
@@ -1919,7 +1955,10 @@ static int snd_timer_user_pause(struct file *file)
1919 tu = file->private_data; 1955 tu = file->private_data;
1920 if (!tu->timeri) 1956 if (!tu->timeri)
1921 return -EBADFD; 1957 return -EBADFD;
1922 return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; 1958 err = snd_timer_pause(tu->timeri);
1959 if (err < 0)
1960 return err;
1961 return 0;
1923} 1962}
1924 1963
1925enum { 1964enum {
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 8c3fbe1276be..c14e57b2a135 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -337,7 +337,7 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
337 337
338 loopback_timer_stop_sync(dpcm); 338 loopback_timer_stop_sync(dpcm);
339 339
340 salign = (snd_pcm_format_width(runtime->format) * 340 salign = (snd_pcm_format_physical_width(runtime->format) *
341 runtime->channels) / 8; 341 runtime->channels) / 8;
342 bps = salign * runtime->rate; 342 bps = salign * runtime->rate;
343 if (bps <= 0 || salign <= 0) 343 if (bps <= 0 || salign <= 0)
@@ -562,6 +562,8 @@ static const struct snd_pcm_hardware loopback_pcm_hardware =
562 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | 562 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
563 SNDRV_PCM_INFO_RESUME), 563 SNDRV_PCM_INFO_RESUME),
564 .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | 564 .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
565 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |
566 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
565 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | 567 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
566 SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), 568 SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
567 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, 569 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 3ada55ed5381..43f28b813386 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -56,8 +56,9 @@
56#define INTERRUPT_INTERVAL 16 56#define INTERRUPT_INTERVAL 16
57#define QUEUE_LENGTH 48 57#define QUEUE_LENGTH 48
58 58
59#define IN_PACKET_HEADER_SIZE 4 59#define IR_HEADER_SIZE 8 // For header and timestamp.
60#define OUT_PACKET_HEADER_SIZE 0 60#define OUT_PACKET_HEADER_SIZE 0
61#define HEADER_TSTAMP_MASK 0x0000ffff
61 62
62static void pcm_period_tasklet(unsigned long data); 63static void pcm_period_tasklet(unsigned long data);
63 64
@@ -456,7 +457,7 @@ static inline int queue_out_packet(struct amdtp_stream *s,
456 457
457static inline int queue_in_packet(struct amdtp_stream *s) 458static inline int queue_in_packet(struct amdtp_stream *s)
458{ 459{
459 return queue_packet(s, IN_PACKET_HEADER_SIZE, s->max_payload_length); 460 return queue_packet(s, IR_HEADER_SIZE, s->max_payload_length);
460} 461}
461 462
462static int handle_out_packet(struct amdtp_stream *s, 463static int handle_out_packet(struct amdtp_stream *s,
@@ -701,13 +702,6 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
701 return cycle; 702 return cycle;
702} 703}
703 704
704static inline u32 decrement_cycle_count(u32 cycle, unsigned int subtrahend)
705{
706 if (cycle < subtrahend)
707 cycle += 8 * CYCLES_PER_SECOND;
708 return cycle - subtrahend;
709}
710
711static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, 705static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
712 size_t header_length, void *header, 706 size_t header_length, void *header,
713 void *private_data) 707 void *private_data)
@@ -745,29 +739,26 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
745 struct amdtp_stream *s = private_data; 739 struct amdtp_stream *s = private_data;
746 unsigned int i, packets; 740 unsigned int i, packets;
747 unsigned int payload_length, max_payload_length; 741 unsigned int payload_length, max_payload_length;
748 __be32 *headers = header; 742 __be32 *ctx_header = header;
749 u32 cycle;
750 743
751 if (s->packet_index < 0) 744 if (s->packet_index < 0)
752 return; 745 return;
753 746
754 /* The number of packets in buffer */ 747 /* The number of packets in buffer */
755 packets = header_length / IN_PACKET_HEADER_SIZE; 748 packets = header_length / IR_HEADER_SIZE;
756
757 cycle = compute_cycle_count(tstamp);
758
759 /* Align to actual cycle count for the last packet. */
760 cycle = decrement_cycle_count(cycle, packets);
761 749
762 /* For buffer-over-run prevention. */ 750 /* For buffer-over-run prevention. */
763 max_payload_length = s->max_payload_length; 751 max_payload_length = s->max_payload_length;
764 752
765 for (i = 0; i < packets; i++) { 753 for (i = 0; i < packets; i++) {
766 cycle = increment_cycle_count(cycle, 1); 754 u32 iso_header = be32_to_cpu(ctx_header[0]);
755 unsigned int cycle;
756
757 tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
758 cycle = compute_cycle_count(tstamp);
767 759
768 /* The number of bytes in this packet */ 760 /* The number of bytes in this packet */
769 payload_length = 761 payload_length = iso_header >> ISO_DATA_LENGTH_SHIFT;
770 (be32_to_cpu(headers[i]) >> ISO_DATA_LENGTH_SHIFT);
771 if (payload_length > max_payload_length) { 762 if (payload_length > max_payload_length) {
772 dev_err(&s->unit->device, 763 dev_err(&s->unit->device,
773 "Detect jumbo payload: %04x %04x\n", 764 "Detect jumbo payload: %04x %04x\n",
@@ -777,6 +768,8 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
777 768
778 if (s->handle_packet(s, payload_length, cycle, i) < 0) 769 if (s->handle_packet(s, payload_length, cycle, i) < 0)
779 break; 770 break;
771
772 ctx_header += IR_HEADER_SIZE / sizeof(__be32);
780 } 773 }
781 774
782 /* Queueing error or detecting invalid payload. */ 775 /* Queueing error or detecting invalid payload. */
@@ -797,6 +790,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
797 void *header, void *private_data) 790 void *header, void *private_data)
798{ 791{
799 struct amdtp_stream *s = private_data; 792 struct amdtp_stream *s = private_data;
793 __be32 *ctx_header = header;
800 u32 cycle; 794 u32 cycle;
801 unsigned int packets; 795 unsigned int packets;
802 796
@@ -807,11 +801,10 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
807 s->callbacked = true; 801 s->callbacked = true;
808 wake_up(&s->callback_wait); 802 wake_up(&s->callback_wait);
809 803
810 cycle = compute_cycle_count(tstamp);
811
812 if (s->direction == AMDTP_IN_STREAM) { 804 if (s->direction == AMDTP_IN_STREAM) {
813 packets = header_length / IN_PACKET_HEADER_SIZE; 805 tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
814 cycle = decrement_cycle_count(cycle, packets); 806 cycle = compute_cycle_count(tstamp);
807
815 context->callback.sc = in_stream_callback; 808 context->callback.sc = in_stream_callback;
816 if (s->flags & CIP_NO_HEADER) 809 if (s->flags & CIP_NO_HEADER)
817 s->handle_packet = handle_in_packet_without_header; 810 s->handle_packet = handle_in_packet_without_header;
@@ -819,6 +812,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
819 s->handle_packet = handle_in_packet; 812 s->handle_packet = handle_in_packet;
820 } else { 813 } else {
821 packets = header_length / 4; 814 packets = header_length / 4;
815 cycle = compute_cycle_count(tstamp);
822 cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets); 816 cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
823 context->callback.sc = out_stream_callback; 817 context->callback.sc = out_stream_callback;
824 if (s->flags & CIP_NO_HEADER) 818 if (s->flags & CIP_NO_HEADER)
@@ -880,7 +874,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
880 if (s->direction == AMDTP_IN_STREAM) { 874 if (s->direction == AMDTP_IN_STREAM) {
881 dir = DMA_FROM_DEVICE; 875 dir = DMA_FROM_DEVICE;
882 type = FW_ISO_CONTEXT_RECEIVE; 876 type = FW_ISO_CONTEXT_RECEIVE;
883 header_size = IN_PACKET_HEADER_SIZE; 877 header_size = IR_HEADER_SIZE;
884 } else { 878 } else {
885 dir = DMA_TO_DEVICE; 879 dir = DMA_TO_DEVICE;
886 type = FW_ISO_CONTEXT_TRANSMIT; 880 type = FW_ISO_CONTEXT_TRANSMIT;
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c
index 6c9b743ea74b..cb0c967dea63 100644
--- a/sound/firewire/motu/amdtp-motu.c
+++ b/sound/firewire/motu/amdtp-motu.c
@@ -412,6 +412,12 @@ int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
412 CIP_HEADER_WITHOUT_EOH; 412 CIP_HEADER_WITHOUT_EOH;
413 fmt = CIP_FMT_MOTU_TX_V3; 413 fmt = CIP_FMT_MOTU_TX_V3;
414 } 414 }
415
416 if (protocol == &snd_motu_protocol_v2) {
417 // 8pre has some quirks.
418 flags |= CIP_WRONG_DBS |
419 CIP_SKIP_DBC_ZERO_CHECK;
420 }
415 } else { 421 } else {
416 process_data_blocks = process_rx_data_blocks; 422 process_data_blocks = process_rx_data_blocks;
417 flags |= CIP_DBC_IS_END_EVENT; 423 flags |= CIP_DBC_IS_END_EVENT;
diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c
index 453fc29fade7..848fffe7387e 100644
--- a/sound/firewire/motu/motu-protocol-v2.c
+++ b/sound/firewire/motu/motu-protocol-v2.c
@@ -15,6 +15,8 @@
15#define V2_CLOCK_SRC_SHIFT 0 15#define V2_CLOCK_SRC_SHIFT 0
16#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000 16#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000
17#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000 17#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000
18#define V2_CLOCK_8PRE_FETCH_DISABLE 0x02000000
19#define V2_CLOCK_8PRE_FETCH_ENABLE 0x00000000
18 20
19#define V2_IN_OUT_CONF_OFFSET 0x0c04 21#define V2_IN_OUT_CONF_OFFSET 0x0c04
20#define V2_OPT_OUT_IFACE_MASK 0x00000c00 22#define V2_OPT_OUT_IFACE_MASK 0x00000c00
@@ -132,20 +134,31 @@ static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
132 u32 data; 134 u32 data;
133 int err = 0; 135 int err = 0;
134 136
135 if (motu->spec == &snd_motu_spec_traveler) { 137 if (motu->spec == &snd_motu_spec_traveler ||
138 motu->spec == &snd_motu_spec_8pre) {
136 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, 139 err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
137 &reg, sizeof(reg)); 140 &reg, sizeof(reg));
138 if (err < 0) 141 if (err < 0)
139 return err; 142 return err;
140 data = be32_to_cpu(reg); 143 data = be32_to_cpu(reg);
141 144
142 data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE | 145 if (motu->spec == &snd_motu_spec_traveler) {
143 V2_CLOCK_TRAVELER_FETCH_ENABLE); 146 data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
144 147 V2_CLOCK_TRAVELER_FETCH_ENABLE);
145 if (enable) 148
146 data |= V2_CLOCK_TRAVELER_FETCH_ENABLE; 149 if (enable)
147 else 150 data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
148 data |= V2_CLOCK_TRAVELER_FETCH_DISABLE; 151 else
152 data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
153 } else if (motu->spec == &snd_motu_spec_8pre) {
154 data &= ~(V2_CLOCK_8PRE_FETCH_DISABLE |
155 V2_CLOCK_8PRE_FETCH_ENABLE);
156
157 if (enable)
158 data |= V2_CLOCK_8PRE_FETCH_DISABLE;
159 else
160 data |= V2_CLOCK_8PRE_FETCH_ENABLE;
161 }
149 162
150 reg = cpu_to_be32(data); 163 reg = cpu_to_be32(data);
151 err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, 164 err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
@@ -220,10 +233,16 @@ static void calculate_differed_part(struct snd_motu_packet_format *formats,
220 * interfaces. 233 * interfaces.
221 */ 234 */
222 data = (data & mask) >> shift; 235 data = (data & mask) >> shift;
223 if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && 236 if (data == V2_OPT_IFACE_MODE_ADAT) {
224 data == V2_OPT_IFACE_MODE_ADAT) { 237 if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) {
225 pcm_chunks[0] += 8; 238 pcm_chunks[0] += 8;
226 pcm_chunks[1] += 4; 239 pcm_chunks[1] += 4;
240 }
241 // 8pre has two sets of optical interface and doesn't reduce
242 // chunks for ADAT signals.
243 if (flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) {
244 pcm_chunks[1] += 4;
245 }
227 } 246 }
228 247
229 /* At mode x4, no data chunks are supported in this part. */ 248 /* At mode x4, no data chunks are supported in this part. */
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index 513291ba0ab0..201539d4488c 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -203,6 +203,20 @@ const struct snd_motu_spec snd_motu_spec_traveler = {
203 .analog_out_ports = 8, 203 .analog_out_ports = 8,
204}; 204};
205 205
206const struct snd_motu_spec snd_motu_spec_8pre = {
207 .name = "8pre",
208 .protocol = &snd_motu_protocol_v2,
209 // In tx, use coax chunks for mix-return 1/2. In rx, use coax chunks for
210 // dummy 1/2.
211 .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
212 SND_MOTU_SPEC_HAS_OPT_IFACE_A |
213 SND_MOTU_SPEC_HAS_OPT_IFACE_B |
214 SND_MOTU_SPEC_RX_MIDI_2ND_Q |
215 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
216 .analog_in_ports = 8,
217 .analog_out_ports = 2,
218};
219
206static const struct snd_motu_spec motu_828mk3 = { 220static const struct snd_motu_spec motu_828mk3 = {
207 .name = "828mk3", 221 .name = "828mk3",
208 .protocol = &snd_motu_protocol_v3, 222 .protocol = &snd_motu_protocol_v3,
@@ -248,6 +262,7 @@ static const struct snd_motu_spec motu_audio_express = {
248static const struct ieee1394_device_id motu_id_table[] = { 262static const struct ieee1394_device_id motu_id_table[] = {
249 SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2), 263 SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2),
250 SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler), 264 SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler),
265 SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre),
251 SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */ 266 SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */
252 SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */ 267 SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */
253 SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express), 268 SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express),
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index fd5327d30ab1..1cd112be7dad 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -130,6 +130,7 @@ extern const struct snd_motu_protocol snd_motu_protocol_v2;
130extern const struct snd_motu_protocol snd_motu_protocol_v3; 130extern const struct snd_motu_protocol snd_motu_protocol_v3;
131 131
132extern const struct snd_motu_spec snd_motu_spec_traveler; 132extern const struct snd_motu_spec snd_motu_spec_traveler;
133extern const struct snd_motu_spec snd_motu_spec_8pre;
133 134
134int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit, 135int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
135 enum amdtp_stream_direction dir, 136 enum amdtp_stream_direction dir,
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index ec7715c6b0c0..c203af71a099 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -104,9 +104,7 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
104 return ret; 104 return ret;
105 105
106 bus->ext_ops = ext_ops; 106 bus->ext_ops = ext_ops;
107 INIT_LIST_HEAD(&bus->hlink_list);
108 bus->idx = idx++; 107 bus->idx = idx++;
109
110 bus->cmd_dma_state = true; 108 bus->cmd_dma_state = true;
111 109
112 return 0; 110 return 0;
diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c
index ad8eee08013f..10e5d261fde1 100644
--- a/sound/hda/hdac_bus.c
+++ b/sound/hda/hdac_bus.c
@@ -39,6 +39,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
39 spin_lock_init(&bus->reg_lock); 39 spin_lock_init(&bus->reg_lock);
40 mutex_init(&bus->cmd_mutex); 40 mutex_init(&bus->cmd_mutex);
41 mutex_init(&bus->lock); 41 mutex_init(&bus->lock);
42 INIT_LIST_HEAD(&bus->hlink_list);
42 bus->irq = -1; 43 bus->irq = -1;
43 return 0; 44 return 0;
44} 45}
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index 4ac76f46dd76..d708ae1525e4 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -306,7 +306,7 @@ static void snd_gf1_mem_info_read(struct snd_info_entry *entry,
306 used = 0; 306 used = 0;
307 for (block = alloc->first, i = 0; block; block = block->next, i++) { 307 for (block = alloc->first, i = 0; block; block = block->next, i++) {
308 used += block->size; 308 used += block->size;
309 snd_iprintf(buffer, "Block %i at 0x%lx onboard 0x%x size %i (0x%x):\n", i, (long) block, block->ptr, block->size, block->size); 309 snd_iprintf(buffer, "Block %i onboard 0x%x size %i (0x%x):\n", i, block->ptr, block->size, block->size);
310 if (block->share || 310 if (block->share ||
311 block->share_id[0] || block->share_id[1] || 311 block->share_id[0] || block->share_id[1] ||
312 block->share_id[2] || block->share_id[3]) 312 block->share_id[2] || block->share_id[3])
diff --git a/sound/last.c b/sound/last.c
index 43f222825038..4f5a624ab438 100644
--- a/sound/last.c
+++ b/sound/last.c
@@ -24,14 +24,18 @@
24 24
25static int __init alsa_sound_last_init(void) 25static int __init alsa_sound_last_init(void)
26{ 26{
27 struct snd_card *card;
27 int idx, ok = 0; 28 int idx, ok = 0;
28 29
29 printk(KERN_INFO "ALSA device list:\n"); 30 printk(KERN_INFO "ALSA device list:\n");
30 for (idx = 0; idx < SNDRV_CARDS; idx++) 31 for (idx = 0; idx < SNDRV_CARDS; idx++) {
31 if (snd_cards[idx] != NULL) { 32 card = snd_card_ref(idx);
32 printk(KERN_INFO " #%i: %s\n", idx, snd_cards[idx]->longname); 33 if (card) {
34 printk(KERN_INFO " #%i: %s\n", idx, card->longname);
35 snd_card_unref(card);
33 ok++; 36 ok++;
34 } 37 }
38 }
35 if (ok == 0) 39 if (ok == 0)
36 printk(KERN_INFO " No soundcards found.\n"); 40 printk(KERN_INFO " No soundcards found.\n");
37 return 0; 41 return 0;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 61f85ff91cd9..0419c75bdf5a 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1882,22 +1882,8 @@ int snd_emu10k1_create(struct snd_card *card,
1882 c->name, pci->vendor, pci->device, 1882 c->name, pci->vendor, pci->device,
1883 emu->serial); 1883 emu->serial);
1884 1884
1885 if (!*card->id && c->id) { 1885 if (!*card->id && c->id)
1886 int i, n = 0;
1887 strlcpy(card->id, c->id, sizeof(card->id)); 1886 strlcpy(card->id, c->id, sizeof(card->id));
1888 for (;;) {
1889 for (i = 0; i < snd_ecards_limit; i++) {
1890 if (snd_cards[i] && !strcmp(snd_cards[i]->id, card->id))
1891 break;
1892 }
1893 if (i >= snd_ecards_limit)
1894 break;
1895 n++;
1896 if (n >= SNDRV_CARDS)
1897 break;
1898 snprintf(card->id, sizeof(card->id), "%s_%d", c->id, n);
1899 }
1900 }
1901 1887
1902 is_audigy = emu->audigy = c->emu10k2_chip; 1888 is_audigy = emu->audigy = c->emu10k2_chip;
1903 1889
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 701a69d856f5..b20eb7fc83eb 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -832,7 +832,13 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
832 struct hda_codec *codec = device->device_data; 832 struct hda_codec *codec = device->device_data;
833 833
834 codec->in_freeing = 1; 834 codec->in_freeing = 1;
835 snd_hdac_device_unregister(&codec->core); 835 /*
836 * snd_hda_codec_device_new() is used by legacy HDA and ASoC driver.
837 * We can't unregister ASoC device since it will be unregistered in
838 * snd_hdac_ext_bus_device_remove().
839 */
840 if (codec->core.type == HDA_DEV_LEGACY)
841 snd_hdac_device_unregister(&codec->core);
836 codec_display_power(codec, false); 842 codec_display_power(codec, false);
837 put_device(hda_codec_dev(codec)); 843 put_device(hda_codec_dev(codec));
838 return 0; 844 return 0;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 2ec91085fa3e..0741eae23f10 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1788,9 +1788,6 @@ static int azx_first_init(struct azx *chip)
1788 chip->msi = 0; 1788 chip->msi = 0;
1789 } 1789 }
1790 1790
1791 if (azx_acquire_irq(chip, 0) < 0)
1792 return -EBUSY;
1793
1794 pci_set_master(pci); 1791 pci_set_master(pci);
1795 synchronize_irq(bus->irq); 1792 synchronize_irq(bus->irq);
1796 1793
@@ -1904,6 +1901,9 @@ static int azx_first_init(struct azx *chip)
1904 return -ENODEV; 1901 return -ENODEV;
1905 } 1902 }
1906 1903
1904 if (azx_acquire_irq(chip, 0) < 0)
1905 return -EBUSY;
1906
1907 strcpy(card->driver, "HDA-Intel"); 1907 strcpy(card->driver, "HDA-Intel");
1908 strlcpy(card->shortname, driver_short_names[chip->driver_type], 1908 strlcpy(card->shortname, driver_short_names[chip->driver_type],
1909 sizeof(card->shortname)); 1909 sizeof(card->shortname));
@@ -2378,6 +2378,12 @@ static const struct pci_device_id azx_ids[] = {
2378 /* Cannonlake */ 2378 /* Cannonlake */
2379 { PCI_DEVICE(0x8086, 0x9dc8), 2379 { PCI_DEVICE(0x8086, 0x9dc8),
2380 .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, 2380 .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
2381 /* CometLake-LP */
2382 { PCI_DEVICE(0x8086, 0x02C8),
2383 .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
2384 /* CometLake-H */
2385 { PCI_DEVICE(0x8086, 0x06C8),
2386 .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
2381 /* Icelake */ 2387 /* Icelake */
2382 { PCI_DEVICE(0x8086, 0x34c8), 2388 { PCI_DEVICE(0x8086, 0x34c8),
2383 .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, 2389 .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8b3ac690efa3..0c61c05503f5 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1551,9 +1551,11 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
1551 ret = !repoll || !eld->monitor_present || eld->eld_valid; 1551 ret = !repoll || !eld->monitor_present || eld->eld_valid;
1552 1552
1553 jack = snd_hda_jack_tbl_get(codec, pin_nid); 1553 jack = snd_hda_jack_tbl_get(codec, pin_nid);
1554 if (jack) 1554 if (jack) {
1555 jack->block_report = !ret; 1555 jack->block_report = !ret;
1556 1556 jack->pin_sense = (eld->monitor_present && eld->eld_valid) ?
1557 AC_PINSENSE_PRESENCE : 0;
1558 }
1557 mutex_unlock(&per_pin->lock); 1559 mutex_unlock(&per_pin->lock);
1558 return ret; 1560 return ret;
1559} 1561}
@@ -1663,6 +1665,11 @@ static void hdmi_repoll_eld(struct work_struct *work)
1663 container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work); 1665 container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
1664 struct hda_codec *codec = per_pin->codec; 1666 struct hda_codec *codec = per_pin->codec;
1665 struct hdmi_spec *spec = codec->spec; 1667 struct hdmi_spec *spec = codec->spec;
1668 struct hda_jack_tbl *jack;
1669
1670 jack = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
1671 if (jack)
1672 jack->jack_dirty = 1;
1666 1673
1667 if (per_pin->repoll_count++ > 6) 1674 if (per_pin->repoll_count++ > 6)
1668 per_pin->repoll_count = 0; 1675 per_pin->repoll_count = 0;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 42cd3945e0de..c53ca589c930 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -119,6 +119,7 @@ struct alc_spec {
119 unsigned int no_depop_delay:1; 119 unsigned int no_depop_delay:1;
120 unsigned int done_hp_init:1; 120 unsigned int done_hp_init:1;
121 unsigned int no_shutup_pins:1; 121 unsigned int no_shutup_pins:1;
122 unsigned int ultra_low_power:1;
122 123
123 /* for PLL fix */ 124 /* for PLL fix */
124 hda_nid_t pll_nid; 125 hda_nid_t pll_nid;
@@ -803,11 +804,10 @@ static int alc_init(struct hda_codec *codec)
803 if (spec->init_hook) 804 if (spec->init_hook)
804 spec->init_hook(codec); 805 spec->init_hook(codec);
805 806
807 snd_hda_gen_init(codec);
806 alc_fix_pll(codec); 808 alc_fix_pll(codec);
807 alc_auto_init_amp(codec, spec->init_amp); 809 alc_auto_init_amp(codec, spec->init_amp);
808 810
809 snd_hda_gen_init(codec);
810
811 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); 811 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
812 812
813 return 0; 813 return 0;
@@ -3197,7 +3197,7 @@ static void alc256_init(struct hda_codec *codec)
3197 bool hp_pin_sense; 3197 bool hp_pin_sense;
3198 3198
3199 if (!hp_pin) 3199 if (!hp_pin)
3200 return; 3200 hp_pin = 0x21;
3201 3201
3202 msleep(30); 3202 msleep(30);
3203 3203
@@ -3207,17 +3207,25 @@ static void alc256_init(struct hda_codec *codec)
3207 msleep(2); 3207 msleep(2);
3208 3208
3209 alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ 3209 alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
3210 if (spec->ultra_low_power) {
3211 alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
3212 alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
3213 alc_update_coef_idx(codec, 0x08, 7<<4, 0);
3214 alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
3215 alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
3216 msleep(30);
3217 }
3210 3218
3211 snd_hda_codec_write(codec, hp_pin, 0, 3219 snd_hda_codec_write(codec, hp_pin, 0,
3212 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 3220 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3213 3221
3214 if (hp_pin_sense) 3222 if (hp_pin_sense || spec->ultra_low_power)
3215 msleep(85); 3223 msleep(85);
3216 3224
3217 snd_hda_codec_write(codec, hp_pin, 0, 3225 snd_hda_codec_write(codec, hp_pin, 0,
3218 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 3226 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3219 3227
3220 if (hp_pin_sense) 3228 if (hp_pin_sense || spec->ultra_low_power)
3221 msleep(100); 3229 msleep(100);
3222 3230
3223 alc_update_coef_idx(codec, 0x46, 3 << 12, 0); 3231 alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
@@ -3232,10 +3240,8 @@ static void alc256_shutup(struct hda_codec *codec)
3232 hda_nid_t hp_pin = alc_get_hp_pin(spec); 3240 hda_nid_t hp_pin = alc_get_hp_pin(spec);
3233 bool hp_pin_sense; 3241 bool hp_pin_sense;
3234 3242
3235 if (!hp_pin) { 3243 if (!hp_pin)
3236 alc269_shutup(codec); 3244 hp_pin = 0x21;
3237 return;
3238 }
3239 3245
3240 hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); 3246 hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
3241 3247
@@ -3245,7 +3251,7 @@ static void alc256_shutup(struct hda_codec *codec)
3245 snd_hda_codec_write(codec, hp_pin, 0, 3251 snd_hda_codec_write(codec, hp_pin, 0,
3246 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 3252 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3247 3253
3248 if (hp_pin_sense) 3254 if (hp_pin_sense || spec->ultra_low_power)
3249 msleep(85); 3255 msleep(85);
3250 3256
3251 /* 3k pull low control for Headset jack. */ 3257 /* 3k pull low control for Headset jack. */
@@ -3256,11 +3262,20 @@ static void alc256_shutup(struct hda_codec *codec)
3256 snd_hda_codec_write(codec, hp_pin, 0, 3262 snd_hda_codec_write(codec, hp_pin, 0,
3257 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); 3263 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
3258 3264
3259 if (hp_pin_sense) 3265 if (hp_pin_sense || spec->ultra_low_power)
3260 msleep(100); 3266 msleep(100);
3261 3267
3262 alc_auto_setup_eapd(codec, false); 3268 alc_auto_setup_eapd(codec, false);
3263 alc_shutup_pins(codec); 3269 alc_shutup_pins(codec);
3270 if (spec->ultra_low_power) {
3271 msleep(50);
3272 alc_update_coef_idx(codec, 0x03, 1<<1, 0);
3273 alc_update_coef_idx(codec, 0x08, 7<<4, 7<<4);
3274 alc_update_coef_idx(codec, 0x08, 3<<2, 0);
3275 alc_update_coef_idx(codec, 0x3b, 1<<15, 1<<15);
3276 alc_update_coef_idx(codec, 0x0e, 7<<6, 0);
3277 msleep(30);
3278 }
3264} 3279}
3265 3280
3266static void alc225_init(struct hda_codec *codec) 3281static void alc225_init(struct hda_codec *codec)
@@ -3270,8 +3285,7 @@ static void alc225_init(struct hda_codec *codec)
3270 bool hp1_pin_sense, hp2_pin_sense; 3285 bool hp1_pin_sense, hp2_pin_sense;
3271 3286
3272 if (!hp_pin) 3287 if (!hp_pin)
3273 return; 3288 hp_pin = 0x21;
3274
3275 msleep(30); 3289 msleep(30);
3276 3290
3277 hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); 3291 hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
@@ -3281,25 +3295,31 @@ static void alc225_init(struct hda_codec *codec)
3281 msleep(2); 3295 msleep(2);
3282 3296
3283 alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ 3297 alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
3298 if (spec->ultra_low_power) {
3299 alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
3300 alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
3301 alc_update_coef_idx(codec, 0x33, 1<<11, 0);
3302 msleep(30);
3303 }
3284 3304
3285 if (hp1_pin_sense) 3305 if (hp1_pin_sense || spec->ultra_low_power)
3286 snd_hda_codec_write(codec, hp_pin, 0, 3306 snd_hda_codec_write(codec, hp_pin, 0,
3287 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 3307 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3288 if (hp2_pin_sense) 3308 if (hp2_pin_sense)
3289 snd_hda_codec_write(codec, 0x16, 0, 3309 snd_hda_codec_write(codec, 0x16, 0,
3290 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 3310 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3291 3311
3292 if (hp1_pin_sense || hp2_pin_sense) 3312 if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
3293 msleep(85); 3313 msleep(85);
3294 3314
3295 if (hp1_pin_sense) 3315 if (hp1_pin_sense || spec->ultra_low_power)
3296 snd_hda_codec_write(codec, hp_pin, 0, 3316 snd_hda_codec_write(codec, hp_pin, 0,
3297 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 3317 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3298 if (hp2_pin_sense) 3318 if (hp2_pin_sense)
3299 snd_hda_codec_write(codec, 0x16, 0, 3319 snd_hda_codec_write(codec, 0x16, 0,
3300 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 3320 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
3301 3321
3302 if (hp1_pin_sense || hp2_pin_sense) 3322 if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
3303 msleep(100); 3323 msleep(100);
3304 3324
3305 alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); 3325 alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
@@ -3312,11 +3332,8 @@ static void alc225_shutup(struct hda_codec *codec)
3312 hda_nid_t hp_pin = alc_get_hp_pin(spec); 3332 hda_nid_t hp_pin = alc_get_hp_pin(spec);
3313 bool hp1_pin_sense, hp2_pin_sense; 3333 bool hp1_pin_sense, hp2_pin_sense;
3314 3334
3315 if (!hp_pin) { 3335 if (!hp_pin)
3316 alc269_shutup(codec); 3336 hp_pin = 0x21;
3317 return;
3318 }
3319
3320 /* 3k pull low control for Headset jack. */ 3337 /* 3k pull low control for Headset jack. */
3321 alc_update_coef_idx(codec, 0x4a, 0, 3 << 10); 3338 alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
3322 3339
@@ -3326,28 +3343,36 @@ static void alc225_shutup(struct hda_codec *codec)
3326 if (hp1_pin_sense || hp2_pin_sense) 3343 if (hp1_pin_sense || hp2_pin_sense)
3327 msleep(2); 3344 msleep(2);
3328 3345
3329 if (hp1_pin_sense) 3346 if (hp1_pin_sense || spec->ultra_low_power)
3330 snd_hda_codec_write(codec, hp_pin, 0, 3347 snd_hda_codec_write(codec, hp_pin, 0,
3331 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 3348 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3332 if (hp2_pin_sense) 3349 if (hp2_pin_sense)
3333 snd_hda_codec_write(codec, 0x16, 0, 3350 snd_hda_codec_write(codec, 0x16, 0,
3334 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 3351 AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
3335 3352
3336 if (hp1_pin_sense || hp2_pin_sense) 3353 if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
3337 msleep(85); 3354 msleep(85);
3338 3355
3339 if (hp1_pin_sense) 3356 if (hp1_pin_sense || spec->ultra_low_power)
3340 snd_hda_codec_write(codec, hp_pin, 0, 3357 snd_hda_codec_write(codec, hp_pin, 0,
3341 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); 3358 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
3342 if (hp2_pin_sense) 3359 if (hp2_pin_sense)
3343 snd_hda_codec_write(codec, 0x16, 0, 3360 snd_hda_codec_write(codec, 0x16, 0,
3344 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); 3361 AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
3345 3362
3346 if (hp1_pin_sense || hp2_pin_sense) 3363 if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power)
3347 msleep(100); 3364 msleep(100);
3348 3365
3349 alc_auto_setup_eapd(codec, false); 3366 alc_auto_setup_eapd(codec, false);
3350 alc_shutup_pins(codec); 3367 alc_shutup_pins(codec);
3368 if (spec->ultra_low_power) {
3369 msleep(50);
3370 alc_update_coef_idx(codec, 0x08, 0x0f << 2, 0x0c << 2);
3371 alc_update_coef_idx(codec, 0x0e, 7<<6, 0);
3372 alc_update_coef_idx(codec, 0x33, 1<<11, 1<<11);
3373 alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4);
3374 msleep(30);
3375 }
3351} 3376}
3352 3377
3353static void alc_default_init(struct hda_codec *codec) 3378static void alc_default_init(struct hda_codec *codec)
@@ -5527,7 +5552,12 @@ static void alc_fixup_headset_jack(struct hda_codec *codec,
5527static void alc295_fixup_chromebook(struct hda_codec *codec, 5552static void alc295_fixup_chromebook(struct hda_codec *codec,
5528 const struct hda_fixup *fix, int action) 5553 const struct hda_fixup *fix, int action)
5529{ 5554{
5555 struct alc_spec *spec = codec->spec;
5556
5530 switch (action) { 5557 switch (action) {
5558 case HDA_FIXUP_ACT_PRE_PROBE:
5559 spec->ultra_low_power = true;
5560 break;
5531 case HDA_FIXUP_ACT_INIT: 5561 case HDA_FIXUP_ACT_INIT:
5532 switch (codec->core.vendor_id) { 5562 switch (codec->core.vendor_id) {
5533 case 0x10ec0295: 5563 case 0x10ec0295:
@@ -6933,6 +6963,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
6933 SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), 6963 SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
6934 SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), 6964 SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
6935 SND_PCI_QUIRK(0x1558, 0x1325, "System76 Darter Pro (darp5)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), 6965 SND_PCI_QUIRK(0x1558, 0x1325, "System76 Darter Pro (darp5)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
6966 SND_PCI_QUIRK(0x1558, 0x8550, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
6967 SND_PCI_QUIRK(0x1558, 0x8560, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
6936 SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS), 6968 SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS),
6937 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), 6969 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
6938 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), 6970 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 521236efcc4d..f77a0d5c0385 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -233,7 +233,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
233 int fill_stages, dma_ch, stage; 233 int fill_stages, dma_ch, stage;
234 enum snd_ps3_ch ch; 234 enum snd_ps3_ch ch;
235 uint32_t ch0_kick_event = 0; /* initialize to mute gcc */ 235 uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
236 void *start_vaddr;
237 unsigned long irqsave; 236 unsigned long irqsave;
238 int silent = 0; 237 int silent = 0;
239 238
@@ -257,7 +256,6 @@ static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
257 fill_stages = 4; 256 fill_stages = 4;
258 spin_lock_irqsave(&card->dma_lock, irqsave); 257 spin_lock_irqsave(&card->dma_lock, irqsave);
259 for (ch = 0; ch < 2; ch++) { 258 for (ch = 0; ch < 2; ch++) {
260 start_vaddr = card->dma_next_transfer_vaddr[0];
261 for (stage = 0; stage < fill_stages; stage++) { 259 for (stage = 0; stage < fill_stages; stage++) {
262 dma_ch = stage * 2 + ch; 260 dma_ch = stage * 2 + ch;
263 if (silent) 261 if (silent)
@@ -526,9 +524,7 @@ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
526{ 524{
527 struct snd_pcm_runtime *runtime = substream->runtime; 525 struct snd_pcm_runtime *runtime = substream->runtime;
528 struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); 526 struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
529 int pcm_index;
530 527
531 pcm_index = substream->pcm->device;
532 /* to retrieve substream/runtime in interrupt handler */ 528 /* to retrieve substream/runtime in interrupt handler */
533 card->substream = substream; 529 card->substream = substream;
534 530
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index e7fef3fce44a..a24e486d9d83 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -303,7 +303,7 @@ static void aica_period_elapsed(struct timer_list *t)
303{ 303{
304 struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard, 304 struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard,
305 t, timer); 305 t, timer);
306 struct snd_pcm_substream *substream = dreamcastcard->timer_substream; 306 struct snd_pcm_substream *substream = dreamcastcard->substream;
307 /*timer function - so cannot sleep */ 307 /*timer function - so cannot sleep */
308 int play_period; 308 int play_period;
309 struct snd_pcm_runtime *runtime; 309 struct snd_pcm_runtime *runtime;
@@ -335,13 +335,6 @@ static void spu_begin_dma(struct snd_pcm_substream *substream)
335 dreamcastcard = substream->pcm->private_data; 335 dreamcastcard = substream->pcm->private_data;
336 /*get the queue to do the work */ 336 /*get the queue to do the work */
337 schedule_work(&(dreamcastcard->spu_dma_work)); 337 schedule_work(&(dreamcastcard->spu_dma_work));
338 /* Timer may already be running */
339 if (unlikely(dreamcastcard->timer_substream)) {
340 mod_timer(&dreamcastcard->timer, jiffies + 4);
341 return;
342 }
343 timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0);
344 dreamcastcard->timer_substream = substream;
345 mod_timer(&dreamcastcard->timer, jiffies + 4); 338 mod_timer(&dreamcastcard->timer, jiffies + 4);
346} 339}
347 340
@@ -379,8 +372,8 @@ static int snd_aicapcm_pcm_close(struct snd_pcm_substream
379{ 372{
380 struct snd_card_aica *dreamcastcard = substream->pcm->private_data; 373 struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
381 flush_work(&(dreamcastcard->spu_dma_work)); 374 flush_work(&(dreamcastcard->spu_dma_work));
382 if (dreamcastcard->timer_substream) 375 del_timer(&dreamcastcard->timer);
383 del_timer(&dreamcastcard->timer); 376 dreamcastcard->substream = NULL;
384 kfree(dreamcastcard->channel); 377 kfree(dreamcastcard->channel);
385 spu_disable(); 378 spu_disable();
386 return 0; 379 return 0;
@@ -613,6 +606,7 @@ static int snd_aica_probe(struct platform_device *devptr)
613 "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast"); 606 "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
614 /* Prepare to use the queue */ 607 /* Prepare to use the queue */
615 INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma); 608 INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
609 timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0);
616 /* Load the PCM 'chip' */ 610 /* Load the PCM 'chip' */
617 err = snd_aicapcmchip(dreamcastcard, 0); 611 err = snd_aicapcmchip(dreamcastcard, 0);
618 if (unlikely(err < 0)) 612 if (unlikely(err < 0))
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index aa35940f5c50..297be0ca3dbc 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -63,6 +63,7 @@ source "sound/soc/rockchip/Kconfig"
63source "sound/soc/samsung/Kconfig" 63source "sound/soc/samsung/Kconfig"
64source "sound/soc/sh/Kconfig" 64source "sound/soc/sh/Kconfig"
65source "sound/soc/sirf/Kconfig" 65source "sound/soc/sirf/Kconfig"
66source "sound/soc/sof/Kconfig"
66source "sound/soc/spear/Kconfig" 67source "sound/soc/spear/Kconfig"
67source "sound/soc/sprd/Kconfig" 68source "sound/soc/sprd/Kconfig"
68source "sound/soc/sti/Kconfig" 69source "sound/soc/sti/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 974fb9821e17..d90ce8a32887 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_SND_SOC) += rockchip/
47obj-$(CONFIG_SND_SOC) += samsung/ 47obj-$(CONFIG_SND_SOC) += samsung/
48obj-$(CONFIG_SND_SOC) += sh/ 48obj-$(CONFIG_SND_SOC) += sh/
49obj-$(CONFIG_SND_SOC) += sirf/ 49obj-$(CONFIG_SND_SOC) += sirf/
50obj-$(CONFIG_SND_SOC) += sof/
50obj-$(CONFIG_SND_SOC) += spear/ 51obj-$(CONFIG_SND_SOC) += spear/
51obj-$(CONFIG_SND_SOC) += sprd/ 52obj-$(CONFIG_SND_SOC) += sprd/
52obj-$(CONFIG_SND_SOC) += sti/ 53obj-$(CONFIG_SND_SOC) += sti/
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c
index 4c23381727a1..273c543e8ff3 100644
--- a/sound/soc/adi/axi-i2s.c
+++ b/sound/soc/adi/axi-i2s.c
@@ -43,6 +43,9 @@ struct axi_i2s {
43 struct clk *clk; 43 struct clk *clk;
44 struct clk *clk_ref; 44 struct clk *clk_ref;
45 45
46 bool has_capture;
47 bool has_playback;
48
46 struct snd_soc_dai_driver dai_driver; 49 struct snd_soc_dai_driver dai_driver;
47 50
48 struct snd_dmaengine_dai_dma_data capture_dma_data; 51 struct snd_dmaengine_dai_dma_data capture_dma_data;
@@ -136,8 +139,10 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
136{ 139{
137 struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai); 140 struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
138 141
139 snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, 142 snd_soc_dai_init_dma_data(
140 &i2s->capture_dma_data); 143 dai,
144 i2s->has_playback ? &i2s->playback_dma_data : NULL,
145 i2s->has_capture ? &i2s->capture_dma_data : NULL);
141 146
142 return 0; 147 return 0;
143} 148}
@@ -151,18 +156,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
151 156
152static struct snd_soc_dai_driver axi_i2s_dai = { 157static struct snd_soc_dai_driver axi_i2s_dai = {
153 .probe = axi_i2s_dai_probe, 158 .probe = axi_i2s_dai_probe,
154 .playback = {
155 .channels_min = 2,
156 .channels_max = 2,
157 .rates = SNDRV_PCM_RATE_KNOT,
158 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
159 },
160 .capture = {
161 .channels_min = 2,
162 .channels_max = 2,
163 .rates = SNDRV_PCM_RATE_KNOT,
164 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
165 },
166 .ops = &axi_i2s_dai_ops, 159 .ops = &axi_i2s_dai_ops,
167 .symmetric_rates = 1, 160 .symmetric_rates = 1,
168}; 161};
@@ -178,6 +171,19 @@ static const struct regmap_config axi_i2s_regmap_config = {
178 .max_register = AXI_I2S_REG_STATUS, 171 .max_register = AXI_I2S_REG_STATUS,
179}; 172};
180 173
174static void axi_i2s_parse_of(struct axi_i2s *i2s, const struct device_node *np)
175{
176 struct property *dma_names;
177 const char *dma_name;
178
179 of_property_for_each_string(np, "dma-names", dma_names, dma_name) {
180 if (strcmp(dma_name, "rx") == 0)
181 i2s->has_capture = true;
182 if (strcmp(dma_name, "tx") == 0)
183 i2s->has_playback = true;
184 }
185}
186
181static int axi_i2s_probe(struct platform_device *pdev) 187static int axi_i2s_probe(struct platform_device *pdev)
182{ 188{
183 struct resource *res; 189 struct resource *res;
@@ -191,6 +197,8 @@ static int axi_i2s_probe(struct platform_device *pdev)
191 197
192 platform_set_drvdata(pdev, i2s); 198 platform_set_drvdata(pdev, i2s);
193 199
200 axi_i2s_parse_of(i2s, pdev->dev.of_node);
201
194 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 202 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
195 base = devm_ioremap_resource(&pdev->dev, res); 203 base = devm_ioremap_resource(&pdev->dev, res);
196 if (IS_ERR(base)) 204 if (IS_ERR(base))
@@ -213,13 +221,29 @@ static int axi_i2s_probe(struct platform_device *pdev)
213 if (ret) 221 if (ret)
214 return ret; 222 return ret;
215 223
216 i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO; 224 if (i2s->has_playback) {
217 i2s->playback_dma_data.addr_width = 4; 225 axi_i2s_dai.playback.channels_min = 2;
218 i2s->playback_dma_data.maxburst = 1; 226 axi_i2s_dai.playback.channels_max = 2;
227 axi_i2s_dai.playback.rates = SNDRV_PCM_RATE_KNOT;
228 axi_i2s_dai.playback.formats =
229 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE;
230
231 i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO;
232 i2s->playback_dma_data.addr_width = 4;
233 i2s->playback_dma_data.maxburst = 1;
234 }
235
236 if (i2s->has_capture) {
237 axi_i2s_dai.capture.channels_min = 2;
238 axi_i2s_dai.capture.channels_max = 2;
239 axi_i2s_dai.capture.rates = SNDRV_PCM_RATE_KNOT;
240 axi_i2s_dai.capture.formats =
241 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE;
219 242
220 i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO; 243 i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO;
221 i2s->capture_dma_data.addr_width = 4; 244 i2s->capture_dma_data.addr_width = 4;
222 i2s->capture_dma_data.maxburst = 1; 245 i2s->capture_dma_data.maxburst = 1;
246 }
223 247
224 i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME; 248 i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME;
225 i2s->ratnum.den_step = 1; 249 i2s->ratnum.den_step = 1;
@@ -240,6 +264,10 @@ static int axi_i2s_probe(struct platform_device *pdev)
240 if (ret) 264 if (ret)
241 goto err_clk_disable; 265 goto err_clk_disable;
242 266
267 dev_info(&pdev->dev, "probed, capture %s, playback %s\n",
268 i2s->has_capture ? "enabled" : "disabled",
269 i2s->has_playback ? "enabled" : "disabled");
270
243 return 0; 271 return 0;
244 272
245err_clk_disable: 273err_clk_disable:
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index a5daad973ce5..16b0ea3a3d72 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -46,8 +46,9 @@
46#define DUAL_CHANNEL 2 46#define DUAL_CHANNEL 2
47 47
48static struct snd_soc_jack cz_jack; 48static struct snd_soc_jack cz_jack;
49static struct clk *da7219_dai_clk; 49static struct clk *da7219_dai_wclk;
50extern int bt_uart_enable; 50static struct clk *da7219_dai_bclk;
51extern bool bt_uart_enable;
51 52
52static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) 53static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
53{ 54{
@@ -72,7 +73,8 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
72 return ret; 73 return ret;
73 } 74 }
74 75
75 da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks"); 76 da7219_dai_wclk = clk_get(component->dev, "da7219-dai-wclk");
77 da7219_dai_bclk = clk_get(component->dev, "da7219-dai-bclk");
76 78
77 ret = snd_soc_card_jack_new(card, "Headset Jack", 79 ret = snd_soc_card_jack_new(card, "Headset Jack",
78 SND_JACK_HEADSET | SND_JACK_LINEOUT | 80 SND_JACK_HEADSET | SND_JACK_LINEOUT |
@@ -94,12 +96,15 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
94 return 0; 96 return 0;
95} 97}
96 98
97static int da7219_clk_enable(struct snd_pcm_substream *substream) 99static int da7219_clk_enable(struct snd_pcm_substream *substream,
100 int wclk_rate, int bclk_rate)
98{ 101{
99 int ret = 0; 102 int ret = 0;
100 struct snd_soc_pcm_runtime *rtd = substream->private_data; 103 struct snd_soc_pcm_runtime *rtd = substream->private_data;
101 104
102 ret = clk_prepare_enable(da7219_dai_clk); 105 clk_set_rate(da7219_dai_wclk, wclk_rate);
106 clk_set_rate(da7219_dai_bclk, bclk_rate);
107 ret = clk_prepare_enable(da7219_dai_bclk);
103 if (ret < 0) { 108 if (ret < 0) {
104 dev_err(rtd->dev, "can't enable master clock %d\n", ret); 109 dev_err(rtd->dev, "can't enable master clock %d\n", ret);
105 return ret; 110 return ret;
@@ -110,7 +115,7 @@ static int da7219_clk_enable(struct snd_pcm_substream *substream)
110 115
111static void da7219_clk_disable(void) 116static void da7219_clk_disable(void)
112{ 117{
113 clk_disable_unprepare(da7219_dai_clk); 118 clk_disable_unprepare(da7219_dai_bclk);
114} 119}
115 120
116static const unsigned int channels[] = { 121static const unsigned int channels[] = {
@@ -151,7 +156,7 @@ static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
151 &constraints_rates); 156 &constraints_rates);
152 157
153 machine->play_i2s_instance = I2S_SP_INSTANCE; 158 machine->play_i2s_instance = I2S_SP_INSTANCE;
154 return da7219_clk_enable(substream); 159 return 0;
155} 160}
156 161
157static int cz_da7219_cap_startup(struct snd_pcm_substream *substream) 162static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
@@ -173,12 +178,7 @@ static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
173 178
174 machine->cap_i2s_instance = I2S_SP_INSTANCE; 179 machine->cap_i2s_instance = I2S_SP_INSTANCE;
175 machine->capture_channel = CAP_CHANNEL1; 180 machine->capture_channel = CAP_CHANNEL1;
176 return da7219_clk_enable(substream); 181 return 0;
177}
178
179static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
180{
181 da7219_clk_disable();
182} 182}
183 183
184static int cz_max_startup(struct snd_pcm_substream *substream) 184static int cz_max_startup(struct snd_pcm_substream *substream)
@@ -199,12 +199,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream)
199 &constraints_rates); 199 &constraints_rates);
200 200
201 machine->play_i2s_instance = I2S_BT_INSTANCE; 201 machine->play_i2s_instance = I2S_BT_INSTANCE;
202 return da7219_clk_enable(substream); 202 return 0;
203}
204
205static void cz_max_shutdown(struct snd_pcm_substream *substream)
206{
207 da7219_clk_disable();
208} 203}
209 204
210static int cz_dmic0_startup(struct snd_pcm_substream *substream) 205static int cz_dmic0_startup(struct snd_pcm_substream *substream)
@@ -225,7 +220,7 @@ static int cz_dmic0_startup(struct snd_pcm_substream *substream)
225 &constraints_rates); 220 &constraints_rates);
226 221
227 machine->cap_i2s_instance = I2S_BT_INSTANCE; 222 machine->cap_i2s_instance = I2S_BT_INSTANCE;
228 return da7219_clk_enable(substream); 223 return 0;
229} 224}
230 225
231static int cz_dmic1_startup(struct snd_pcm_substream *substream) 226static int cz_dmic1_startup(struct snd_pcm_substream *substream)
@@ -247,10 +242,28 @@ static int cz_dmic1_startup(struct snd_pcm_substream *substream)
247 242
248 machine->cap_i2s_instance = I2S_SP_INSTANCE; 243 machine->cap_i2s_instance = I2S_SP_INSTANCE;
249 machine->capture_channel = CAP_CHANNEL0; 244 machine->capture_channel = CAP_CHANNEL0;
250 return da7219_clk_enable(substream); 245 return 0;
251} 246}
252 247
253static void cz_dmic_shutdown(struct snd_pcm_substream *substream) 248static int cz_da7219_params(struct snd_pcm_substream *substream,
249 struct snd_pcm_hw_params *params)
250{
251 int wclk, bclk;
252
253 wclk = params_rate(params);
254 bclk = wclk * params_channels(params) *
255 snd_pcm_format_width(params_format(params));
256 /* ADAU7002 spec: "The ADAU7002 requires a BCLK rate
257 * that is minimum of 64x the LRCLK sample rate."
258 * DA7219 is the only clk source so for all codecs
259 * we have to limit bclk to 64X lrclk.
260 */
261 if (bclk < (wclk * 64))
262 bclk = wclk * 64;
263 return da7219_clk_enable(substream, wclk, bclk);
264}
265
266static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
254{ 267{
255 da7219_clk_disable(); 268 da7219_clk_disable();
256} 269}
@@ -258,26 +271,31 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
258static const struct snd_soc_ops cz_da7219_play_ops = { 271static const struct snd_soc_ops cz_da7219_play_ops = {
259 .startup = cz_da7219_play_startup, 272 .startup = cz_da7219_play_startup,
260 .shutdown = cz_da7219_shutdown, 273 .shutdown = cz_da7219_shutdown,
274 .hw_params = cz_da7219_params,
261}; 275};
262 276
263static const struct snd_soc_ops cz_da7219_cap_ops = { 277static const struct snd_soc_ops cz_da7219_cap_ops = {
264 .startup = cz_da7219_cap_startup, 278 .startup = cz_da7219_cap_startup,
265 .shutdown = cz_da7219_shutdown, 279 .shutdown = cz_da7219_shutdown,
280 .hw_params = cz_da7219_params,
266}; 281};
267 282
268static const struct snd_soc_ops cz_max_play_ops = { 283static const struct snd_soc_ops cz_max_play_ops = {
269 .startup = cz_max_startup, 284 .startup = cz_max_startup,
270 .shutdown = cz_max_shutdown, 285 .shutdown = cz_da7219_shutdown,
286 .hw_params = cz_da7219_params,
271}; 287};
272 288
273static const struct snd_soc_ops cz_dmic0_cap_ops = { 289static const struct snd_soc_ops cz_dmic0_cap_ops = {
274 .startup = cz_dmic0_startup, 290 .startup = cz_dmic0_startup,
275 .shutdown = cz_dmic_shutdown, 291 .shutdown = cz_da7219_shutdown,
292 .hw_params = cz_da7219_params,
276}; 293};
277 294
278static const struct snd_soc_ops cz_dmic1_cap_ops = { 295static const struct snd_soc_ops cz_dmic1_cap_ops = {
279 .startup = cz_dmic1_startup, 296 .startup = cz_dmic1_startup,
280 .shutdown = cz_dmic_shutdown, 297 .shutdown = cz_da7219_shutdown,
298 .hw_params = cz_da7219_params,
281}; 299};
282 300
283static struct snd_soc_dai_link cz_dai_7219_98357[] = { 301static struct snd_soc_dai_link cz_dai_7219_98357[] = {
diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c
index 1a2e15ff1456..9775bda2a4ca 100644
--- a/sound/soc/amd/raven/acp3x-pcm-dma.c
+++ b/sound/soc/amd/raven/acp3x-pcm-dma.c
@@ -558,7 +558,7 @@ static int acp3x_dai_i2s_trigger(struct snd_pcm_substream *substream,
558 return ret; 558 return ret;
559} 559}
560 560
561struct snd_soc_dai_ops acp3x_dai_i2s_ops = { 561static struct snd_soc_dai_ops acp3x_dai_i2s_ops = {
562 .hw_params = acp3x_dai_i2s_hwparams, 562 .hw_params = acp3x_dai_i2s_hwparams,
563 .trigger = acp3x_dai_i2s_trigger, 563 .trigger = acp3x_dai_i2s_trigger,
564 .set_fmt = acp3x_dai_i2s_set_fmt, 564 .set_fmt = acp3x_dai_i2s_set_fmt,
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 64f86f0b87e5..c473b9e463ab 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -109,4 +109,18 @@ config SND_SOC_MIKROE_PROTO
109 using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins. 109 using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins.
110 Both playback and capture are supported. 110 Both playback and capture are supported.
111 111
112config SND_MCHP_SOC_I2S_MCC
113 tristate "Microchip ASoC driver for boards using I2S MCC"
114 depends on OF && (ARCH_AT91 || COMPILE_TEST)
115 select SND_SOC_GENERIC_DMAENGINE_PCM
116 select REGMAP_MMIO
117 help
118 Say Y or M if you want to add support for I2S Multi-Channel ASoC
119 driver on the following Microchip platforms:
120 - sam9x60
121
122 The I2SMCC complies with the Inter-IC Sound (I2S) bus specification
123 and supports a Time Division Multiplexed (TDM) interface with
124 external multi-channel audio codecs.
125
112endif 126endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 9f41bfa0fea3..1f6890ed3738 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -4,11 +4,13 @@ snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
4snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o 4snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
5snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o 5snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
6snd-soc-atmel-i2s-objs := atmel-i2s.o 6snd-soc-atmel-i2s-objs := atmel-i2s.o
7snd-soc-mchp-i2s-mcc-objs := mchp-i2s-mcc.o
7 8
8obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o 9obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
9obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o 10obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
10obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o 11obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
11obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o 12obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
13obj-$(CONFIG_SND_MCHP_SOC_I2S_MCC) += snd-soc-mchp-i2s-mcc.o
12 14
13# AT91 Machine Support 15# AT91 Machine Support
14snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o 16snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
new file mode 100644
index 000000000000..86495883ca3f
--- /dev/null
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -0,0 +1,974 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// Driver for Microchip I2S Multi-channel controller
4//
5// Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries
6//
7// Author: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/device.h>
12#include <linux/slab.h>
13
14#include <linux/delay.h>
15#include <linux/io.h>
16#include <linux/clk.h>
17#include <linux/mfd/syscon.h>
18#include <linux/lcm.h>
19
20#include <sound/core.h>
21#include <sound/pcm.h>
22#include <sound/pcm_params.h>
23#include <sound/initval.h>
24#include <sound/soc.h>
25#include <sound/dmaengine_pcm.h>
26
27/*
28 * ---- I2S Controller Register map ----
29 */
30#define MCHP_I2SMCC_CR 0x0000 /* Control Register */
31#define MCHP_I2SMCC_MRA 0x0004 /* Mode Register A */
32#define MCHP_I2SMCC_MRB 0x0008 /* Mode Register B */
33#define MCHP_I2SMCC_SR 0x000C /* Status Register */
34#define MCHP_I2SMCC_IERA 0x0010 /* Interrupt Enable Register A */
35#define MCHP_I2SMCC_IDRA 0x0014 /* Interrupt Disable Register A */
36#define MCHP_I2SMCC_IMRA 0x0018 /* Interrupt Mask Register A */
37#define MCHP_I2SMCC_ISRA 0X001C /* Interrupt Status Register A */
38
39#define MCHP_I2SMCC_IERB 0x0020 /* Interrupt Enable Register B */
40#define MCHP_I2SMCC_IDRB 0x0024 /* Interrupt Disable Register B */
41#define MCHP_I2SMCC_IMRB 0x0028 /* Interrupt Mask Register B */
42#define MCHP_I2SMCC_ISRB 0X002C /* Interrupt Status Register B */
43
44#define MCHP_I2SMCC_RHR 0x0030 /* Receiver Holding Register */
45#define MCHP_I2SMCC_THR 0x0034 /* Transmitter Holding Register */
46
47#define MCHP_I2SMCC_RHL0R 0x0040 /* Receiver Holding Left 0 Register */
48#define MCHP_I2SMCC_RHR0R 0x0044 /* Receiver Holding Right 0 Register */
49
50#define MCHP_I2SMCC_RHL1R 0x0048 /* Receiver Holding Left 1 Register */
51#define MCHP_I2SMCC_RHR1R 0x004C /* Receiver Holding Right 1 Register */
52
53#define MCHP_I2SMCC_RHL2R 0x0050 /* Receiver Holding Left 2 Register */
54#define MCHP_I2SMCC_RHR2R 0x0054 /* Receiver Holding Right 2 Register */
55
56#define MCHP_I2SMCC_RHL3R 0x0058 /* Receiver Holding Left 3 Register */
57#define MCHP_I2SMCC_RHR3R 0x005C /* Receiver Holding Right 3 Register */
58
59#define MCHP_I2SMCC_THL0R 0x0060 /* Transmitter Holding Left 0 Register */
60#define MCHP_I2SMCC_THR0R 0x0064 /* Transmitter Holding Right 0 Register */
61
62#define MCHP_I2SMCC_THL1R 0x0068 /* Transmitter Holding Left 1 Register */
63#define MCHP_I2SMCC_THR1R 0x006C /* Transmitter Holding Right 1 Register */
64
65#define MCHP_I2SMCC_THL2R 0x0070 /* Transmitter Holding Left 2 Register */
66#define MCHP_I2SMCC_THR2R 0x0074 /* Transmitter Holding Right 2 Register */
67
68#define MCHP_I2SMCC_THL3R 0x0078 /* Transmitter Holding Left 3 Register */
69#define MCHP_I2SMCC_THR3R 0x007C /* Transmitter Holding Right 3 Register */
70
71#define MCHP_I2SMCC_VERSION 0x00FC /* Version Register */
72
73/*
74 * ---- Control Register (Write-only) ----
75 */
76#define MCHP_I2SMCC_CR_RXEN BIT(0) /* Receiver Enable */
77#define MCHP_I2SMCC_CR_RXDIS BIT(1) /* Receiver Disable */
78#define MCHP_I2SMCC_CR_CKEN BIT(2) /* Clock Enable */
79#define MCHP_I2SMCC_CR_CKDIS BIT(3) /* Clock Disable */
80#define MCHP_I2SMCC_CR_TXEN BIT(4) /* Transmitter Enable */
81#define MCHP_I2SMCC_CR_TXDIS BIT(5) /* Transmitter Disable */
82#define MCHP_I2SMCC_CR_SWRST BIT(7) /* Software Reset */
83
84/*
85 * ---- Mode Register A (Read/Write) ----
86 */
87#define MCHP_I2SMCC_MRA_MODE_MASK GENMASK(0, 0)
88#define MCHP_I2SMCC_MRA_MODE_SLAVE (0 << 0)
89#define MCHP_I2SMCC_MRA_MODE_MASTER (1 << 0)
90
91#define MCHP_I2SMCC_MRA_DATALENGTH_MASK GENMASK(3, 1)
92#define MCHP_I2SMCC_MRA_DATALENGTH_32_BITS (0 << 1)
93#define MCHP_I2SMCC_MRA_DATALENGTH_24_BITS (1 << 1)
94#define MCHP_I2SMCC_MRA_DATALENGTH_20_BITS (2 << 1)
95#define MCHP_I2SMCC_MRA_DATALENGTH_18_BITS (3 << 1)
96#define MCHP_I2SMCC_MRA_DATALENGTH_16_BITS (4 << 1)
97#define MCHP_I2SMCC_MRA_DATALENGTH_16_BITS_COMPACT (5 << 1)
98#define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS (6 << 1)
99#define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1)
100
101#define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4)
102#define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4)
103#define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4)
104#define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4)
105#define MCHP_I2SMCC_MRA_WIRECFG_TDM_3 (3 << 4)
106
107#define MCHP_I2SMCC_MRA_FORMAT_MASK GENMASK(7, 6)
108#define MCHP_I2SMCC_MRA_FORMAT_I2S (0 << 6)
109#define MCHP_I2SMCC_MRA_FORMAT_LJ (1 << 6) /* Left Justified */
110#define MCHP_I2SMCC_MRA_FORMAT_TDM (2 << 6)
111#define MCHP_I2SMCC_MRA_FORMAT_TDMLJ (3 << 6)
112
113/* Transmitter uses one DMA channel ... */
114/* Left audio samples duplicated to right audio channel */
115#define MCHP_I2SMCC_MRA_RXMONO BIT(8)
116
117/* I2SDO output of I2SC is internally connected to I2SDI input */
118#define MCHP_I2SMCC_MRA_RXLOOP BIT(9)
119
120/* Receiver uses one DMA channel ... */
121/* Left audio samples duplicated to right audio channel */
122#define MCHP_I2SMCC_MRA_TXMONO BIT(10)
123
124/* x sample transmitted when underrun */
125#define MCHP_I2SMCC_MRA_TXSAME_ZERO (0 << 11) /* Zero sample */
126#define MCHP_I2SMCC_MRA_TXSAME_PREVIOUS (1 << 11) /* Previous sample */
127
128/* select between peripheral clock and generated clock */
129#define MCHP_I2SMCC_MRA_SRCCLK_PCLK (0 << 12)
130#define MCHP_I2SMCC_MRA_SRCCLK_GCLK (1 << 12)
131
132/* Number of TDM Channels - 1 */
133#define MCHP_I2SMCC_MRA_NBCHAN_MASK GENMASK(15, 13)
134#define MCHP_I2SMCC_MRA_NBCHAN(ch) \
135 ((((ch) - 1) << 13) & MCHP_I2SMCC_MRA_NBCHAN_MASK)
136
137/* Selected Clock to I2SMCC Master Clock ratio */
138#define MCHP_I2SMCC_MRA_IMCKDIV_MASK GENMASK(21, 16)
139#define MCHP_I2SMCC_MRA_IMCKDIV(div) \
140 (((div) << 16) & MCHP_I2SMCC_MRA_IMCKDIV_MASK)
141
142/* TDM Frame Synchronization */
143#define MCHP_I2SMCC_MRA_TDMFS_MASK GENMASK(23, 22)
144#define MCHP_I2SMCC_MRA_TDMFS_SLOT (0 << 22)
145#define MCHP_I2SMCC_MRA_TDMFS_HALF (1 << 22)
146#define MCHP_I2SMCC_MRA_TDMFS_BIT (2 << 22)
147
148/* Selected Clock to I2SMC Serial Clock ratio */
149#define MCHP_I2SMCC_MRA_ISCKDIV_MASK GENMASK(29, 24)
150#define MCHP_I2SMCC_MRA_ISCKDIV(div) \
151 (((div) << 24) & MCHP_I2SMCC_MRA_ISCKDIV_MASK)
152
153/* Master Clock mode */
154#define MCHP_I2SMCC_MRA_IMCKMODE_MASK GENMASK(30, 30)
155/* 0: No master clock generated*/
156#define MCHP_I2SMCC_MRA_IMCKMODE_NONE (0 << 30)
157/* 1: master clock generated (internally generated clock drives I2SMCK pin) */
158#define MCHP_I2SMCC_MRA_IMCKMODE_GEN (1 << 30)
159
160/* Slot Width */
161/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */
162/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */
163#define MCHP_I2SMCC_MRA_IWS BIT(31)
164
165/*
166 * ---- Mode Register B (Read/Write) ----
167 */
168/* all enabled I2S left channels are filled first, then I2S right channels */
169#define MCHP_I2SMCC_MRB_CRAMODE_LEFT_FIRST (0 << 0)
170/*
171 * an enabled I2S left channel is filled, then the corresponding right
172 * channel, until all channels are filled
173 */
174#define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0)
175
176#define MCHP_I2SMCC_MRB_FIFOEN BIT(1)
177
178#define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8)
179#define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \
180 (((fls(no_words) - 1) << 8) & MCHP_I2SMCC_MRB_DMACHUNK_MASK)
181
182#define MCHP_I2SMCC_MRB_CLKSEL_MASK GENMASK(16, 16)
183#define MCHP_I2SMCC_MRB_CLKSEL_EXT (0 << 16)
184#define MCHP_I2SMCC_MRB_CLKSEL_INT (1 << 16)
185
186/*
187 * ---- Status Registers (Read-only) ----
188 */
189#define MCHP_I2SMCC_SR_RXEN BIT(0) /* Receiver Enabled */
190#define MCHP_I2SMCC_SR_TXEN BIT(4) /* Transmitter Enabled */
191
192/*
193 * ---- Interrupt Enable/Disable/Mask/Status Registers A ----
194 */
195#define MCHP_I2SMCC_INT_TXRDY_MASK(ch) GENMASK((ch) - 1, 0)
196#define MCHP_I2SMCC_INT_TXRDYCH(ch) BIT(ch)
197#define MCHP_I2SMCC_INT_TXUNF_MASK(ch) GENMASK((ch) + 7, 8)
198#define MCHP_I2SMCC_INT_TXUNFCH(ch) BIT((ch) + 8)
199#define MCHP_I2SMCC_INT_RXRDY_MASK(ch) GENMASK((ch) + 15, 16)
200#define MCHP_I2SMCC_INT_RXRDYCH(ch) BIT((ch) + 16)
201#define MCHP_I2SMCC_INT_RXOVF_MASK(ch) GENMASK((ch) + 23, 24)
202#define MCHP_I2SMCC_INT_RXOVFCH(ch) BIT((ch) + 24)
203
204/*
205 * ---- Interrupt Enable/Disable/Mask/Status Registers B ----
206 */
207#define MCHP_I2SMCC_INT_WERR BIT(0)
208#define MCHP_I2SMCC_INT_TXFFRDY BIT(8)
209#define MCHP_I2SMCC_INT_TXFFEMP BIT(9)
210#define MCHP_I2SMCC_INT_RXFFRDY BIT(12)
211#define MCHP_I2SMCC_INT_RXFFFUL BIT(13)
212
213/*
214 * ---- Version Register (Read-only) ----
215 */
216#define MCHP_I2SMCC_VERSION_MASK GENMASK(11, 0)
217
218#define MCHP_I2SMCC_MAX_CHANNELS 8
219#define MCHP_I2MCC_TDM_SLOT_WIDTH 32
220
221static const struct regmap_config mchp_i2s_mcc_regmap_config = {
222 .reg_bits = 32,
223 .reg_stride = 4,
224 .val_bits = 32,
225 .max_register = MCHP_I2SMCC_VERSION,
226};
227
228struct mchp_i2s_mcc_dev {
229 struct wait_queue_head wq_txrdy;
230 struct wait_queue_head wq_rxrdy;
231 struct device *dev;
232 struct regmap *regmap;
233 struct clk *pclk;
234 struct clk *gclk;
235 struct snd_dmaengine_dai_dma_data playback;
236 struct snd_dmaengine_dai_dma_data capture;
237 unsigned int fmt;
238 unsigned int sysclk;
239 unsigned int frame_length;
240 int tdm_slots;
241 int channels;
242 int gclk_use:1;
243 int gclk_running:1;
244 int tx_rdy:1;
245 int rx_rdy:1;
246};
247
248static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
249{
250 struct mchp_i2s_mcc_dev *dev = dev_id;
251 u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0;
252 irqreturn_t ret = IRQ_NONE;
253
254 regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
255 regmap_read(dev->regmap, MCHP_I2SMCC_ISRA, &sra);
256 pendinga = imra & sra;
257
258 regmap_read(dev->regmap, MCHP_I2SMCC_IMRB, &imrb);
259 regmap_read(dev->regmap, MCHP_I2SMCC_ISRB, &srb);
260 pendingb = imrb & srb;
261
262 if (!pendinga && !pendingb)
263 return IRQ_NONE;
264
265 /*
266 * Tx/Rx ready interrupts are enabled when stopping only, to assure
267 * availability and to disable clocks if necessary
268 */
269 idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
270 MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
271 if (idra)
272 ret = IRQ_HANDLED;
273
274 if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
275 (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
276 (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) {
277 dev->tx_rdy = 1;
278 wake_up_interruptible(&dev->wq_txrdy);
279 }
280 if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
281 (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
282 (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) {
283 dev->rx_rdy = 1;
284 wake_up_interruptible(&dev->wq_rxrdy);
285 }
286 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
287
288 return ret;
289}
290
291static int mchp_i2s_mcc_set_sysclk(struct snd_soc_dai *dai,
292 int clk_id, unsigned int freq, int dir)
293{
294 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
295
296 dev_dbg(dev->dev, "%s() clk_id=%d freq=%u dir=%d\n",
297 __func__, clk_id, freq, dir);
298
299 /* We do not need SYSCLK */
300 if (dir == SND_SOC_CLOCK_IN)
301 return 0;
302
303 dev->sysclk = freq;
304
305 return 0;
306}
307
308static int mchp_i2s_mcc_set_bclk_ratio(struct snd_soc_dai *dai,
309 unsigned int ratio)
310{
311 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
312
313 dev_dbg(dev->dev, "%s() ratio=%u\n", __func__, ratio);
314
315 dev->frame_length = ratio;
316
317 return 0;
318}
319
320static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
321{
322 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
323
324 dev_dbg(dev->dev, "%s() fmt=%#x\n", __func__, fmt);
325
326 /* We don't support any kind of clock inversion */
327 if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
328 return -EINVAL;
329
330 /* We can't generate only FSYNC */
331 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFS)
332 return -EINVAL;
333
334 /* We can only reconfigure the IP when it's stopped */
335 if (fmt & SND_SOC_DAIFMT_CONT)
336 return -EINVAL;
337
338 dev->fmt = fmt;
339
340 return 0;
341}
342
343static int mchp_i2s_mcc_set_dai_tdm_slot(struct snd_soc_dai *dai,
344 unsigned int tx_mask,
345 unsigned int rx_mask,
346 int slots, int slot_width)
347{
348 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
349
350 dev_dbg(dev->dev,
351 "%s() tx_mask=0x%08x rx_mask=0x%08x slots=%d width=%d\n",
352 __func__, tx_mask, rx_mask, slots, slot_width);
353
354 if (slots < 0 || slots > MCHP_I2SMCC_MAX_CHANNELS ||
355 slot_width != MCHP_I2MCC_TDM_SLOT_WIDTH)
356 return -EINVAL;
357
358 if (slots) {
359 /* We do not support daisy chain */
360 if (rx_mask != GENMASK(slots - 1, 0) ||
361 rx_mask != tx_mask)
362 return -EINVAL;
363 }
364
365 dev->tdm_slots = slots;
366 dev->frame_length = slots * MCHP_I2MCC_TDM_SLOT_WIDTH;
367
368 return 0;
369}
370
371static int mchp_i2s_mcc_clk_get_rate_diff(struct clk *clk,
372 unsigned long rate,
373 struct clk **best_clk,
374 unsigned long *best_rate,
375 unsigned long *best_diff_rate)
376{
377 long round_rate;
378 unsigned int diff_rate;
379
380 round_rate = clk_round_rate(clk, rate);
381 if (round_rate < 0)
382 return (int)round_rate;
383
384 diff_rate = abs(rate - round_rate);
385 if (diff_rate < *best_diff_rate) {
386 *best_clk = clk;
387 *best_diff_rate = diff_rate;
388 *best_rate = rate;
389 }
390
391 return 0;
392}
393
394static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev,
395 unsigned int bclk, unsigned int *mra)
396{
397 unsigned long clk_rate;
398 unsigned long lcm_rate;
399 unsigned long best_rate = 0;
400 unsigned long best_diff_rate = ~0;
401 unsigned int sysclk;
402 struct clk *best_clk = NULL;
403 int ret;
404
405 /* For code simplification */
406 if (!dev->sysclk)
407 sysclk = bclk;
408 else
409 sysclk = dev->sysclk;
410
411 /*
412 * MCLK is Selected CLK / (2 * IMCKDIV),
413 * BCLK is Selected CLK / (2 * ISCKDIV);
414 * if IMCKDIV or ISCKDIV are 0, MCLK or BCLK = Selected CLK
415 */
416 lcm_rate = lcm(sysclk, bclk);
417 if ((lcm_rate / sysclk % 2 == 1 && lcm_rate / sysclk > 2) ||
418 (lcm_rate / bclk % 2 == 1 && lcm_rate / bclk > 2))
419 lcm_rate *= 2;
420
421 for (clk_rate = lcm_rate;
422 (clk_rate == sysclk || clk_rate / (sysclk * 2) <= GENMASK(5, 0)) &&
423 (clk_rate == bclk || clk_rate / (bclk * 2) <= GENMASK(5, 0));
424 clk_rate += lcm_rate) {
425 ret = mchp_i2s_mcc_clk_get_rate_diff(dev->gclk, clk_rate,
426 &best_clk, &best_rate,
427 &best_diff_rate);
428 if (ret) {
429 dev_err(dev->dev, "gclk error for rate %lu: %d",
430 clk_rate, ret);
431 } else {
432 if (!best_diff_rate) {
433 dev_dbg(dev->dev, "found perfect rate on gclk: %lu\n",
434 clk_rate);
435 break;
436 }
437 }
438
439 ret = mchp_i2s_mcc_clk_get_rate_diff(dev->pclk, clk_rate,
440 &best_clk, &best_rate,
441 &best_diff_rate);
442 if (ret) {
443 dev_err(dev->dev, "pclk error for rate %lu: %d",
444 clk_rate, ret);
445 } else {
446 if (!best_diff_rate) {
447 dev_dbg(dev->dev, "found perfect rate on pclk: %lu\n",
448 clk_rate);
449 break;
450 }
451 }
452 }
453
454 /* check if clocks returned only errors */
455 if (!best_clk) {
456 dev_err(dev->dev, "unable to change rate to clocks\n");
457 return -EINVAL;
458 }
459
460 dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n",
461 best_clk == dev->pclk ? "pclk" : "gclk",
462 best_rate, best_diff_rate);
463
464 /* set the rate */
465 ret = clk_set_rate(best_clk, best_rate);
466 if (ret) {
467 dev_err(dev->dev, "unable to set rate %lu to %s: %d\n",
468 best_rate, best_clk == dev->pclk ? "PCLK" : "GCLK",
469 ret);
470 return ret;
471 }
472
473 /* Configure divisors */
474 if (dev->sysclk)
475 *mra |= MCHP_I2SMCC_MRA_IMCKDIV(best_rate / (2 * sysclk));
476 *mra |= MCHP_I2SMCC_MRA_ISCKDIV(best_rate / (2 * bclk));
477
478 if (best_clk == dev->gclk) {
479 *mra |= MCHP_I2SMCC_MRA_SRCCLK_GCLK;
480 ret = clk_prepare(dev->gclk);
481 if (ret < 0)
482 dev_err(dev->dev, "unable to prepare GCLK: %d\n", ret);
483 else
484 dev->gclk_use = 1;
485 } else {
486 *mra |= MCHP_I2SMCC_MRA_SRCCLK_PCLK;
487 dev->gclk_use = 0;
488 }
489
490 return 0;
491}
492
493static int mchp_i2s_mcc_is_running(struct mchp_i2s_mcc_dev *dev)
494{
495 u32 sr;
496
497 regmap_read(dev->regmap, MCHP_I2SMCC_SR, &sr);
498 return !!(sr & (MCHP_I2SMCC_SR_TXEN | MCHP_I2SMCC_SR_RXEN));
499}
500
501static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
502 struct snd_pcm_hw_params *params,
503 struct snd_soc_dai *dai)
504{
505 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
506 u32 mra = 0;
507 u32 mrb = 0;
508 unsigned int channels = params_channels(params);
509 unsigned int frame_length = dev->frame_length;
510 unsigned int bclk_rate;
511 int set_divs = 0;
512 int ret;
513 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
514
515 dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
516 __func__, params_rate(params), params_format(params),
517 params_width(params), params_channels(params));
518
519 switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
520 case SND_SOC_DAIFMT_I2S:
521 if (dev->tdm_slots) {
522 dev_err(dev->dev, "I2S with TDM is not supported\n");
523 return -EINVAL;
524 }
525 mra |= MCHP_I2SMCC_MRA_FORMAT_I2S;
526 break;
527 case SND_SOC_DAIFMT_LEFT_J:
528 if (dev->tdm_slots) {
529 dev_err(dev->dev, "Left-Justified with TDM is not supported\n");
530 return -EINVAL;
531 }
532 mra |= MCHP_I2SMCC_MRA_FORMAT_LJ;
533 break;
534 case SND_SOC_DAIFMT_DSP_A:
535 mra |= MCHP_I2SMCC_MRA_FORMAT_TDM;
536 break;
537 default:
538 dev_err(dev->dev, "unsupported bus format\n");
539 return -EINVAL;
540 }
541
542 switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
543 case SND_SOC_DAIFMT_CBS_CFS:
544 /* cpu is BCLK and LRC master */
545 mra |= MCHP_I2SMCC_MRA_MODE_MASTER;
546 if (dev->sysclk)
547 mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN;
548 set_divs = 1;
549 break;
550 case SND_SOC_DAIFMT_CBS_CFM:
551 /* cpu is BCLK master */
552 mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT;
553 set_divs = 1;
554 /* fall through */
555 case SND_SOC_DAIFMT_CBM_CFM:
556 /* cpu is slave */
557 mra |= MCHP_I2SMCC_MRA_MODE_SLAVE;
558 if (dev->sysclk)
559 dev_warn(dev->dev, "Unable to generate MCLK in Slave mode\n");
560 break;
561 default:
562 dev_err(dev->dev, "unsupported master/slave mode\n");
563 return -EINVAL;
564 }
565
566 if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
567 switch (channels) {
568 case 1:
569 if (is_playback)
570 mra |= MCHP_I2SMCC_MRA_TXMONO;
571 else
572 mra |= MCHP_I2SMCC_MRA_RXMONO;
573 break;
574 case 2:
575 break;
576 default:
577 dev_err(dev->dev, "unsupported number of audio channels\n");
578 return -EINVAL;
579 }
580
581 if (!frame_length)
582 frame_length = 2 * params_physical_width(params);
583 } else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) {
584 if (dev->tdm_slots) {
585 if (channels % 2 && channels * 2 <= dev->tdm_slots) {
586 /*
587 * Duplicate data for even-numbered channels
588 * to odd-numbered channels
589 */
590 if (is_playback)
591 mra |= MCHP_I2SMCC_MRA_TXMONO;
592 else
593 mra |= MCHP_I2SMCC_MRA_RXMONO;
594 }
595 channels = dev->tdm_slots;
596 }
597
598 mra |= MCHP_I2SMCC_MRA_NBCHAN(channels);
599 if (!frame_length)
600 frame_length = channels * MCHP_I2MCC_TDM_SLOT_WIDTH;
601 }
602
603 /*
604 * We must have the same burst size configured
605 * in the DMA transfer and in out IP
606 */
607 mrb |= MCHP_I2SMCC_MRB_DMACHUNK(channels);
608 if (is_playback)
609 dev->playback.maxburst = 1 << (fls(channels) - 1);
610 else
611 dev->capture.maxburst = 1 << (fls(channels) - 1);
612
613 switch (params_format(params)) {
614 case SNDRV_PCM_FORMAT_S8:
615 mra |= MCHP_I2SMCC_MRA_DATALENGTH_8_BITS;
616 break;
617 case SNDRV_PCM_FORMAT_S16_LE:
618 mra |= MCHP_I2SMCC_MRA_DATALENGTH_16_BITS;
619 break;
620 case SNDRV_PCM_FORMAT_S18_3LE:
621 mra |= MCHP_I2SMCC_MRA_DATALENGTH_18_BITS |
622 MCHP_I2SMCC_MRA_IWS;
623 break;
624 case SNDRV_PCM_FORMAT_S20_3LE:
625 mra |= MCHP_I2SMCC_MRA_DATALENGTH_20_BITS |
626 MCHP_I2SMCC_MRA_IWS;
627 break;
628 case SNDRV_PCM_FORMAT_S24_3LE:
629 mra |= MCHP_I2SMCC_MRA_DATALENGTH_24_BITS |
630 MCHP_I2SMCC_MRA_IWS;
631 break;
632 case SNDRV_PCM_FORMAT_S24_LE:
633 mra |= MCHP_I2SMCC_MRA_DATALENGTH_24_BITS;
634 break;
635 case SNDRV_PCM_FORMAT_S32_LE:
636 mra |= MCHP_I2SMCC_MRA_DATALENGTH_32_BITS;
637 break;
638 default:
639 dev_err(dev->dev, "unsupported size/endianness for audio samples\n");
640 return -EINVAL;
641 }
642
643 /*
644 * If we are already running, the wanted setup must be
645 * the same with the one that's currently ongoing
646 */
647 if (mchp_i2s_mcc_is_running(dev)) {
648 u32 mra_cur;
649 u32 mrb_cur;
650
651 regmap_read(dev->regmap, MCHP_I2SMCC_MRA, &mra_cur);
652 regmap_read(dev->regmap, MCHP_I2SMCC_MRB, &mrb_cur);
653 if (mra != mra_cur || mrb != mrb_cur)
654 return -EINVAL;
655
656 return 0;
657 }
658
659 /* Save the number of channels to know what interrupts to enable */
660 dev->channels = channels;
661
662 if (set_divs) {
663 bclk_rate = frame_length * params_rate(params);
664 ret = mchp_i2s_mcc_config_divs(dev, bclk_rate, &mra);
665 if (ret) {
666 dev_err(dev->dev, "unable to configure the divisors: %d\n",
667 ret);
668 return ret;
669 }
670 }
671
672 ret = regmap_write(dev->regmap, MCHP_I2SMCC_MRA, mra);
673 if (ret < 0)
674 return ret;
675 return regmap_write(dev->regmap, MCHP_I2SMCC_MRB, mrb);
676}
677
678static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
679 struct snd_soc_dai *dai)
680{
681 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
682 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
683 long err;
684
685 if (is_playback) {
686 err = wait_event_interruptible_timeout(dev->wq_txrdy,
687 dev->tx_rdy,
688 msecs_to_jiffies(500));
689 } else {
690 err = wait_event_interruptible_timeout(dev->wq_rxrdy,
691 dev->rx_rdy,
692 msecs_to_jiffies(500));
693 }
694
695 if (err == 0) {
696 u32 idra;
697
698 dev_warn_once(dev->dev, "Timeout waiting for %s\n",
699 is_playback ? "Tx ready" : "Rx ready");
700 if (is_playback)
701 idra = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
702 else
703 idra = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
704 regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
705 }
706
707 if (!mchp_i2s_mcc_is_running(dev)) {
708 regmap_write(dev->regmap, MCHP_I2SMCC_CR, MCHP_I2SMCC_CR_CKDIS);
709
710 if (dev->gclk_running) {
711 clk_disable_unprepare(dev->gclk);
712 dev->gclk_running = 0;
713 }
714 }
715
716 return 0;
717}
718
719static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
720 struct snd_soc_dai *dai)
721{
722 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
723 bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
724 u32 cr = 0;
725 u32 iera = 0;
726 u32 sr;
727 int err;
728
729 switch (cmd) {
730 case SNDRV_PCM_TRIGGER_START:
731 case SNDRV_PCM_TRIGGER_RESUME:
732 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
733 if (is_playback)
734 cr = MCHP_I2SMCC_CR_TXEN | MCHP_I2SMCC_CR_CKEN;
735 else
736 cr = MCHP_I2SMCC_CR_RXEN | MCHP_I2SMCC_CR_CKEN;
737 break;
738 case SNDRV_PCM_TRIGGER_STOP:
739 case SNDRV_PCM_TRIGGER_SUSPEND:
740 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
741 regmap_read(dev->regmap, MCHP_I2SMCC_SR, &sr);
742 if (is_playback && (sr & MCHP_I2SMCC_SR_TXEN)) {
743 cr = MCHP_I2SMCC_CR_TXDIS;
744 dev->tx_rdy = 0;
745 /*
746 * Enable Tx Ready interrupts on all channels
747 * to assure all data is sent
748 */
749 iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
750 } else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) {
751 cr = MCHP_I2SMCC_CR_RXDIS;
752 dev->rx_rdy = 0;
753 /*
754 * Enable Rx Ready interrupts on all channels
755 * to assure all data is received
756 */
757 iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
758 }
759 break;
760 default:
761 return -EINVAL;
762 }
763
764 if ((cr & MCHP_I2SMCC_CR_CKEN) && dev->gclk_use &&
765 !dev->gclk_running) {
766 err = clk_enable(dev->gclk);
767 if (err) {
768 dev_err_once(dev->dev, "failed to enable GCLK: %d\n",
769 err);
770 } else {
771 dev->gclk_running = 1;
772 }
773 }
774
775 regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
776 regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr);
777
778 return 0;
779}
780
781static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream,
782 struct snd_soc_dai *dai)
783{
784 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
785
786 /* Software reset the IP if it's not running */
787 if (!mchp_i2s_mcc_is_running(dev)) {
788 return regmap_write(dev->regmap, MCHP_I2SMCC_CR,
789 MCHP_I2SMCC_CR_SWRST);
790 }
791
792 return 0;
793}
794
795static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
796 .set_sysclk = mchp_i2s_mcc_set_sysclk,
797 .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
798 .startup = mchp_i2s_mcc_startup,
799 .trigger = mchp_i2s_mcc_trigger,
800 .hw_params = mchp_i2s_mcc_hw_params,
801 .hw_free = mchp_i2s_mcc_hw_free,
802 .set_fmt = mchp_i2s_mcc_set_dai_fmt,
803 .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
804};
805
806static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
807{
808 struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
809
810 init_waitqueue_head(&dev->wq_txrdy);
811 init_waitqueue_head(&dev->wq_rxrdy);
812
813 snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture);
814
815 return 0;
816}
817
818#define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000
819
820#define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
821 SNDRV_PCM_FMTBIT_S16_LE | \
822 SNDRV_PCM_FMTBIT_S18_3LE | \
823 SNDRV_PCM_FMTBIT_S20_3LE | \
824 SNDRV_PCM_FMTBIT_S24_3LE | \
825 SNDRV_PCM_FMTBIT_S24_LE | \
826 SNDRV_PCM_FMTBIT_S32_LE)
827
828static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
829 .probe = mchp_i2s_mcc_dai_probe,
830 .playback = {
831 .stream_name = "I2SMCC-Playback",
832 .channels_min = 1,
833 .channels_max = 8,
834 .rates = MCHP_I2SMCC_RATES,
835 .formats = MCHP_I2SMCC_FORMATS,
836 },
837 .capture = {
838 .stream_name = "I2SMCC-Capture",
839 .channels_min = 1,
840 .channels_max = 8,
841 .rates = MCHP_I2SMCC_RATES,
842 .formats = MCHP_I2SMCC_FORMATS,
843 },
844 .ops = &mchp_i2s_mcc_dai_ops,
845 .symmetric_rates = 1,
846 .symmetric_samplebits = 1,
847 .symmetric_channels = 1,
848};
849
850static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
851 .name = "mchp-i2s-mcc",
852};
853
854#ifdef CONFIG_OF
855static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
856 {
857 .compatible = "microchip,sam9x60-i2smcc",
858 },
859 { /* sentinel */ }
860};
861MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids);
862#endif
863
864static int mchp_i2s_mcc_probe(struct platform_device *pdev)
865{
866 struct mchp_i2s_mcc_dev *dev;
867 struct resource *mem;
868 struct regmap *regmap;
869 void __iomem *base;
870 u32 version;
871 int irq;
872 int err;
873
874 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
875 if (!dev)
876 return -ENOMEM;
877
878 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
879 base = devm_ioremap_resource(&pdev->dev, mem);
880 if (IS_ERR(base))
881 return PTR_ERR(base);
882
883 regmap = devm_regmap_init_mmio(&pdev->dev, base,
884 &mchp_i2s_mcc_regmap_config);
885 if (IS_ERR(regmap))
886 return PTR_ERR(regmap);
887
888 irq = platform_get_irq(pdev, 0);
889 if (irq < 0)
890 return irq;
891
892 err = devm_request_irq(&pdev->dev, irq, mchp_i2s_mcc_interrupt, 0,
893 dev_name(&pdev->dev), dev);
894 if (err)
895 return err;
896
897 dev->pclk = devm_clk_get(&pdev->dev, "pclk");
898 if (IS_ERR(dev->pclk)) {
899 err = PTR_ERR(dev->pclk);
900 dev_err(&pdev->dev,
901 "failed to get the peripheral clock: %d\n", err);
902 return err;
903 }
904
905 /* Get the optional generated clock */
906 dev->gclk = devm_clk_get(&pdev->dev, "gclk");
907 if (IS_ERR(dev->gclk)) {
908 if (PTR_ERR(dev->gclk) == -EPROBE_DEFER)
909 return -EPROBE_DEFER;
910 dev_warn(&pdev->dev,
911 "generated clock not found: %d\n", err);
912 dev->gclk = NULL;
913 }
914
915 dev->dev = &pdev->dev;
916 dev->regmap = regmap;
917 platform_set_drvdata(pdev, dev);
918
919 err = clk_prepare_enable(dev->pclk);
920 if (err) {
921 dev_err(&pdev->dev,
922 "failed to enable the peripheral clock: %d\n", err);
923 return err;
924 }
925
926 err = devm_snd_soc_register_component(&pdev->dev,
927 &mchp_i2s_mcc_component,
928 &mchp_i2s_mcc_dai, 1);
929 if (err) {
930 dev_err(&pdev->dev, "failed to register DAI: %d\n", err);
931 clk_disable_unprepare(dev->pclk);
932 return err;
933 }
934
935 dev->playback.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_THR;
936 dev->capture.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_RHR;
937
938 err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
939 if (err) {
940 dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
941 clk_disable_unprepare(dev->pclk);
942 return err;
943 }
944
945 /* Get IP version. */
946 regmap_read(dev->regmap, MCHP_I2SMCC_VERSION, &version);
947 dev_info(&pdev->dev, "hw version: %#lx\n",
948 version & MCHP_I2SMCC_VERSION_MASK);
949
950 return 0;
951}
952
953static int mchp_i2s_mcc_remove(struct platform_device *pdev)
954{
955 struct mchp_i2s_mcc_dev *dev = platform_get_drvdata(pdev);
956
957 clk_disable_unprepare(dev->pclk);
958
959 return 0;
960}
961
962static struct platform_driver mchp_i2s_mcc_driver = {
963 .driver = {
964 .name = "mchp_i2s_mcc",
965 .of_match_table = of_match_ptr(mchp_i2s_mcc_dt_ids),
966 },
967 .probe = mchp_i2s_mcc_probe,
968 .remove = mchp_i2s_mcc_remove,
969};
970module_platform_driver(mchp_i2s_mcc_driver);
971
972MODULE_DESCRIPTION("Microchip I2S Multi-Channel Controller driver");
973MODULE_AUTHOR("Codrin Ciubotariu <codrin.ciubotariu@microchip.com>");
974MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index 214adcad5419..ae445184614a 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -117,8 +117,8 @@ static int tse850_put_mux2(struct snd_kcontrol *kctrl,
117 return snd_soc_dapm_put_enum_double(kctrl, ucontrol); 117 return snd_soc_dapm_put_enum_double(kctrl, ucontrol);
118} 118}
119 119
120int tse850_get_mix(struct snd_kcontrol *kctrl, 120static int tse850_get_mix(struct snd_kcontrol *kctrl,
121 struct snd_ctl_elem_value *ucontrol) 121 struct snd_ctl_elem_value *ucontrol)
122{ 122{
123 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); 123 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
124 struct snd_soc_card *card = dapm->card; 124 struct snd_soc_card *card = dapm->card;
@@ -129,8 +129,8 @@ int tse850_get_mix(struct snd_kcontrol *kctrl,
129 return 0; 129 return 0;
130} 130}
131 131
132int tse850_put_mix(struct snd_kcontrol *kctrl, 132static int tse850_put_mix(struct snd_kcontrol *kctrl,
133 struct snd_ctl_elem_value *ucontrol) 133 struct snd_ctl_elem_value *ucontrol)
134{ 134{
135 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); 135 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
136 struct snd_soc_card *card = dapm->card; 136 struct snd_soc_card *card = dapm->card;
@@ -151,8 +151,8 @@ int tse850_put_mix(struct snd_kcontrol *kctrl,
151 return 1; 151 return 1;
152} 152}
153 153
154int tse850_get_ana(struct snd_kcontrol *kctrl, 154static int tse850_get_ana(struct snd_kcontrol *kctrl,
155 struct snd_ctl_elem_value *ucontrol) 155 struct snd_ctl_elem_value *ucontrol)
156{ 156{
157 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); 157 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
158 struct snd_soc_card *card = dapm->card; 158 struct snd_soc_card *card = dapm->card;
@@ -184,8 +184,8 @@ int tse850_get_ana(struct snd_kcontrol *kctrl,
184 return 0; 184 return 0;
185} 185}
186 186
187int tse850_put_ana(struct snd_kcontrol *kctrl, 187static int tse850_put_ana(struct snd_kcontrol *kctrl,
188 struct snd_ctl_elem_value *ucontrol) 188 struct snd_ctl_elem_value *ucontrol)
189{ 189{
190 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); 190 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl);
191 struct snd_soc_card *card = dapm->card; 191 struct snd_soc_card *card = dapm->card;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 667fc1d59e18..8f577258080b 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -94,6 +94,7 @@ config SND_SOC_ALL_CODECS
94 select SND_SOC_JZ4725B_CODEC 94 select SND_SOC_JZ4725B_CODEC
95 select SND_SOC_LM4857 if I2C 95 select SND_SOC_LM4857 if I2C
96 select SND_SOC_LM49453 if I2C 96 select SND_SOC_LM49453 if I2C
97 select SND_SOC_LOCHNAGAR_SC if MFD_LOCHNAGAR
97 select SND_SOC_MAX98088 if I2C 98 select SND_SOC_MAX98088 if I2C
98 select SND_SOC_MAX98090 if I2C 99 select SND_SOC_MAX98090 if I2C
99 select SND_SOC_MAX98095 if I2C 100 select SND_SOC_MAX98095 if I2C
@@ -179,8 +180,8 @@ config SND_SOC_ALL_CODECS
179 select SND_SOC_TLV320AIC23_SPI if SPI_MASTER 180 select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
180 select SND_SOC_TLV320AIC26 if SPI_MASTER 181 select SND_SOC_TLV320AIC26 if SPI_MASTER
181 select SND_SOC_TLV320AIC31XX if I2C 182 select SND_SOC_TLV320AIC31XX if I2C
182 select SND_SOC_TLV320AIC32X4_I2C if I2C 183 select SND_SOC_TLV320AIC32X4_I2C if I2C && COMMON_CLK
183 select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER 184 select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER && COMMON_CLK
184 select SND_SOC_TLV320AIC3X if I2C 185 select SND_SOC_TLV320AIC3X if I2C
185 select SND_SOC_TPA6130A2 if I2C 186 select SND_SOC_TPA6130A2 if I2C
186 select SND_SOC_TLV320DAC33 if I2C 187 select SND_SOC_TLV320DAC33 if I2C
@@ -688,6 +689,13 @@ config SND_SOC_ISABELLE
688config SND_SOC_LM49453 689config SND_SOC_LM49453
689 tristate 690 tristate
690 691
692config SND_SOC_LOCHNAGAR_SC
693 tristate "Lochnagar Sound Card"
694 depends on MFD_LOCHNAGAR
695 help
696 This driver support the sound card functionality of the Cirrus
697 Logic Lochnagar audio development board.
698
691config SND_SOC_MAX98088 699config SND_SOC_MAX98088
692 tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec" 700 tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec"
693 depends on I2C 701 depends on I2C
@@ -1097,15 +1105,18 @@ config SND_SOC_TLV320AIC31XX
1097 1105
1098config SND_SOC_TLV320AIC32X4 1106config SND_SOC_TLV320AIC32X4
1099 tristate 1107 tristate
1108 depends on COMMON_CLK
1100 1109
1101config SND_SOC_TLV320AIC32X4_I2C 1110config SND_SOC_TLV320AIC32X4_I2C
1102 tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C" 1111 tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
1103 depends on I2C 1112 depends on I2C
1113 depends on COMMON_CLK
1104 select SND_SOC_TLV320AIC32X4 1114 select SND_SOC_TLV320AIC32X4
1105 1115
1106config SND_SOC_TLV320AIC32X4_SPI 1116config SND_SOC_TLV320AIC32X4_SPI
1107 tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI" 1117 tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
1108 depends on SPI_MASTER 1118 depends on SPI_MASTER
1119 depends on COMMON_CLK
1109 select SND_SOC_TLV320AIC32X4 1120 select SND_SOC_TLV320AIC32X4
1110 1121
1111config SND_SOC_TLV320AIC3X 1122config SND_SOC_TLV320AIC3X
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index aab2ad95a137..aa7720a7a0aa 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -91,6 +91,7 @@ snd-soc-jz4725b-codec-objs := jz4725b.o
91snd-soc-l3-objs := l3.o 91snd-soc-l3-objs := l3.o
92snd-soc-lm4857-objs := lm4857.o 92snd-soc-lm4857-objs := lm4857.o
93snd-soc-lm49453-objs := lm49453.o 93snd-soc-lm49453-objs := lm49453.o
94snd-soc-lochnagar-sc-objs := lochnagar-sc.o
94snd-soc-max9759-objs := max9759.o 95snd-soc-max9759-objs := max9759.o
95snd-soc-max9768-objs := max9768.o 96snd-soc-max9768-objs := max9768.o
96snd-soc-max98088-objs := max98088.o 97snd-soc-max98088-objs := max98088.o
@@ -192,7 +193,7 @@ snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
192snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o 193snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
193snd-soc-tlv320aic26-objs := tlv320aic26.o 194snd-soc-tlv320aic26-objs := tlv320aic26.o
194snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o 195snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
195snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o 196snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
196snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o 197snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
197snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o 198snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
198snd-soc-tlv320aic3x-objs := tlv320aic3x.o 199snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -364,6 +365,7 @@ obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o
364obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 365obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
365obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o 366obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
366obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o 367obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
368obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o
367obj-$(CONFIG_SND_SOC_MAX9759) += snd-soc-max9759.o 369obj-$(CONFIG_SND_SOC_MAX9759) += snd-soc-max9759.o
368obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o 370obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
369obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o 371obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index 4b5731a41876..116221e581ce 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -29,18 +29,27 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c,
29 struct regmap_config config; 29 struct regmap_config config;
30 30
31 config = cs42l51_regmap; 31 config = cs42l51_regmap;
32 config.val_bits = 8;
33 config.reg_bits = 8;
34 32
35 return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config)); 33 return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
36} 34}
37 35
36static int cs42l51_i2c_remove(struct i2c_client *i2c)
37{
38 return cs42l51_remove(&i2c->dev);
39}
40
41static const struct dev_pm_ops cs42l51_pm_ops = {
42 SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume)
43};
44
38static struct i2c_driver cs42l51_i2c_driver = { 45static struct i2c_driver cs42l51_i2c_driver = {
39 .driver = { 46 .driver = {
40 .name = "cs42l51", 47 .name = "cs42l51",
41 .of_match_table = cs42l51_of_match, 48 .of_match_table = cs42l51_of_match,
49 .pm = &cs42l51_pm_ops,
42 }, 50 },
43 .probe = cs42l51_i2c_probe, 51 .probe = cs42l51_i2c_probe,
52 .remove = cs42l51_i2c_remove,
44 .id_table = cs42l51_i2c_id, 53 .id_table = cs42l51_i2c_id,
45}; 54};
46 55
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index fd2bd74024c1..991e4ebd7a04 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -30,7 +30,9 @@
30#include <sound/initval.h> 30#include <sound/initval.h>
31#include <sound/pcm_params.h> 31#include <sound/pcm_params.h>
32#include <sound/pcm.h> 32#include <sound/pcm.h>
33#include <linux/gpio/consumer.h>
33#include <linux/regmap.h> 34#include <linux/regmap.h>
35#include <linux/regulator/consumer.h>
34 36
35#include "cs42l51.h" 37#include "cs42l51.h"
36 38
@@ -40,11 +42,21 @@ enum master_slave_mode {
40 MODE_MASTER, 42 MODE_MASTER,
41}; 43};
42 44
45static const char * const cs42l51_supply_names[] = {
46 "VL",
47 "VD",
48 "VA",
49 "VAHP",
50};
51
43struct cs42l51_private { 52struct cs42l51_private {
44 unsigned int mclk; 53 unsigned int mclk;
45 struct clk *mclk_handle; 54 struct clk *mclk_handle;
46 unsigned int audio_mode; /* The mode (I2S or left-justified) */ 55 unsigned int audio_mode; /* The mode (I2S or left-justified) */
47 enum master_slave_mode func; 56 enum master_slave_mode func;
57 struct regulator_bulk_data supplies[ARRAY_SIZE(cs42l51_supply_names)];
58 struct gpio_desc *reset_gpio;
59 struct regmap *regmap;
48}; 60};
49 61
50#define CS42L51_FORMATS ( \ 62#define CS42L51_FORMATS ( \
@@ -111,6 +123,7 @@ static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
111static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0); 123static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
112 124
113static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0); 125static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
126static const DECLARE_TLV_DB_SCALE(adc_boost_tlv, 2000, 2000, 0);
114static const char *chan_mix[] = { 127static const char *chan_mix[] = {
115 "L R", 128 "L R",
116 "L+R", 129 "L+R",
@@ -139,6 +152,8 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
139 SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0), 152 SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
140 SOC_DOUBLE_TLV("Mic Boost Volume", 153 SOC_DOUBLE_TLV("Mic Boost Volume",
141 CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv), 154 CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
155 SOC_DOUBLE_TLV("ADC Boost Volume",
156 CS42L51_MIC_CTL, 5, 6, 1, 0, adc_boost_tlv),
142 SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv), 157 SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
143 SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv), 158 SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
144 SOC_ENUM_EXT("PCM channel mixer", 159 SOC_ENUM_EXT("PCM channel mixer",
@@ -195,7 +210,8 @@ static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
195 SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); 210 SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
196 211
197static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { 212static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
198 SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1), 213 SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1, NULL,
214 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
199 SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0, 215 SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
200 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), 216 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
201 SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0, 217 SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
@@ -329,6 +345,19 @@ static struct cs42l51_ratios slave_auto_ratios[] = {
329 { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 }, 345 { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
330}; 346};
331 347
348/*
349 * Master mode mclk/fs ratios.
350 * Recommended configurations are SSM for 4-50khz and DSM for 50-100kHz ranges
351 * The table below provides support of following ratios:
352 * 128: SSM (%128) with div2 disabled
353 * 256: SSM (%128) with div2 enabled
354 * In both cases, if sampling rate is above 50kHz, SSM is overridden
355 * with DSM (%128) configuration
356 */
357static struct cs42l51_ratios master_ratios[] = {
358 { 128, CS42L51_SSM_MODE, 0 }, { 256, CS42L51_SSM_MODE, 1 },
359};
360
332static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, 361static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
333 int clk_id, unsigned int freq, int dir) 362 int clk_id, unsigned int freq, int dir)
334{ 363{
@@ -351,11 +380,13 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
351 unsigned int ratio; 380 unsigned int ratio;
352 struct cs42l51_ratios *ratios = NULL; 381 struct cs42l51_ratios *ratios = NULL;
353 int nr_ratios = 0; 382 int nr_ratios = 0;
354 int intf_ctl, power_ctl, fmt; 383 int intf_ctl, power_ctl, fmt, mode;
355 384
356 switch (cs42l51->func) { 385 switch (cs42l51->func) {
357 case MODE_MASTER: 386 case MODE_MASTER:
358 return -EINVAL; 387 ratios = master_ratios;
388 nr_ratios = ARRAY_SIZE(master_ratios);
389 break;
359 case MODE_SLAVE: 390 case MODE_SLAVE:
360 ratios = slave_ratios; 391 ratios = slave_ratios;
361 nr_ratios = ARRAY_SIZE(slave_ratios); 392 nr_ratios = ARRAY_SIZE(slave_ratios);
@@ -391,7 +422,16 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
391 switch (cs42l51->func) { 422 switch (cs42l51->func) {
392 case MODE_MASTER: 423 case MODE_MASTER:
393 intf_ctl |= CS42L51_INTF_CTL_MASTER; 424 intf_ctl |= CS42L51_INTF_CTL_MASTER;
394 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); 425 mode = ratios[i].speed_mode;
426 /* Force DSM mode if sampling rate is above 50kHz */
427 if (rate > 50000)
428 mode = CS42L51_DSM_MODE;
429 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(mode);
430 /*
431 * Auto detect mode is not applicable for master mode and has to
432 * be disabled. Otherwise SPEED[1:0] bits will be ignored.
433 */
434 power_ctl &= ~CS42L51_MIC_POWER_CTL_AUTO;
395 break; 435 break;
396 case MODE_SLAVE: 436 case MODE_SLAVE:
397 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); 437 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
@@ -464,6 +504,13 @@ static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
464 return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg); 504 return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg);
465} 505}
466 506
507static int cs42l51_of_xlate_dai_id(struct snd_soc_component *component,
508 struct device_node *endpoint)
509{
510 /* return dai id 0, whatever the endpoint index */
511 return 0;
512}
513
467static const struct snd_soc_dai_ops cs42l51_dai_ops = { 514static const struct snd_soc_dai_ops cs42l51_dai_ops = {
468 .hw_params = cs42l51_hw_params, 515 .hw_params = cs42l51_hw_params,
469 .set_sysclk = cs42l51_set_dai_sysclk, 516 .set_sysclk = cs42l51_set_dai_sysclk,
@@ -526,13 +573,113 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
526 .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets), 573 .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
527 .dapm_routes = cs42l51_routes, 574 .dapm_routes = cs42l51_routes,
528 .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), 575 .num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
576 .of_xlate_dai_id = cs42l51_of_xlate_dai_id,
529 .idle_bias_on = 1, 577 .idle_bias_on = 1,
530 .use_pmdown_time = 1, 578 .use_pmdown_time = 1,
531 .endianness = 1, 579 .endianness = 1,
532 .non_legacy_dai_naming = 1, 580 .non_legacy_dai_naming = 1,
533}; 581};
534 582
583static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg)
584{
585 switch (reg) {
586 case CS42L51_POWER_CTL1:
587 case CS42L51_MIC_POWER_CTL:
588 case CS42L51_INTF_CTL:
589 case CS42L51_MIC_CTL:
590 case CS42L51_ADC_CTL:
591 case CS42L51_ADC_INPUT:
592 case CS42L51_DAC_OUT_CTL:
593 case CS42L51_DAC_CTL:
594 case CS42L51_ALC_PGA_CTL:
595 case CS42L51_ALC_PGB_CTL:
596 case CS42L51_ADCA_ATT:
597 case CS42L51_ADCB_ATT:
598 case CS42L51_ADCA_VOL:
599 case CS42L51_ADCB_VOL:
600 case CS42L51_PCMA_VOL:
601 case CS42L51_PCMB_VOL:
602 case CS42L51_BEEP_FREQ:
603 case CS42L51_BEEP_VOL:
604 case CS42L51_BEEP_CONF:
605 case CS42L51_TONE_CTL:
606 case CS42L51_AOUTA_VOL:
607 case CS42L51_AOUTB_VOL:
608 case CS42L51_PCM_MIXER:
609 case CS42L51_LIMIT_THRES_DIS:
610 case CS42L51_LIMIT_REL:
611 case CS42L51_LIMIT_ATT:
612 case CS42L51_ALC_EN:
613 case CS42L51_ALC_REL:
614 case CS42L51_ALC_THRES:
615 case CS42L51_NOISE_CONF:
616 case CS42L51_CHARGE_FREQ:
617 return true;
618 default:
619 return false;
620 }
621}
622
623static bool cs42l51_volatile_reg(struct device *dev, unsigned int reg)
624{
625 switch (reg) {
626 case CS42L51_STATUS:
627 return true;
628 default:
629 return false;
630 }
631}
632
633static bool cs42l51_readable_reg(struct device *dev, unsigned int reg)
634{
635 switch (reg) {
636 case CS42L51_CHIP_REV_ID:
637 case CS42L51_POWER_CTL1:
638 case CS42L51_MIC_POWER_CTL:
639 case CS42L51_INTF_CTL:
640 case CS42L51_MIC_CTL:
641 case CS42L51_ADC_CTL:
642 case CS42L51_ADC_INPUT:
643 case CS42L51_DAC_OUT_CTL:
644 case CS42L51_DAC_CTL:
645 case CS42L51_ALC_PGA_CTL:
646 case CS42L51_ALC_PGB_CTL:
647 case CS42L51_ADCA_ATT:
648 case CS42L51_ADCB_ATT:
649 case CS42L51_ADCA_VOL:
650 case CS42L51_ADCB_VOL:
651 case CS42L51_PCMA_VOL:
652 case CS42L51_PCMB_VOL:
653 case CS42L51_BEEP_FREQ:
654 case CS42L51_BEEP_VOL:
655 case CS42L51_BEEP_CONF:
656 case CS42L51_TONE_CTL:
657 case CS42L51_AOUTA_VOL:
658 case CS42L51_AOUTB_VOL:
659 case CS42L51_PCM_MIXER:
660 case CS42L51_LIMIT_THRES_DIS:
661 case CS42L51_LIMIT_REL:
662 case CS42L51_LIMIT_ATT:
663 case CS42L51_ALC_EN:
664 case CS42L51_ALC_REL:
665 case CS42L51_ALC_THRES:
666 case CS42L51_NOISE_CONF:
667 case CS42L51_STATUS:
668 case CS42L51_CHARGE_FREQ:
669 return true;
670 default:
671 return false;
672 }
673}
674
535const struct regmap_config cs42l51_regmap = { 675const struct regmap_config cs42l51_regmap = {
676 .reg_bits = 8,
677 .reg_stride = 1,
678 .val_bits = 8,
679 .use_single_write = true,
680 .readable_reg = cs42l51_readable_reg,
681 .volatile_reg = cs42l51_volatile_reg,
682 .writeable_reg = cs42l51_writeable_reg,
536 .max_register = CS42L51_CHARGE_FREQ, 683 .max_register = CS42L51_CHARGE_FREQ,
537 .cache_type = REGCACHE_RBTREE, 684 .cache_type = REGCACHE_RBTREE,
538}; 685};
@@ -542,7 +689,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
542{ 689{
543 struct cs42l51_private *cs42l51; 690 struct cs42l51_private *cs42l51;
544 unsigned int val; 691 unsigned int val;
545 int ret; 692 int ret, i;
546 693
547 if (IS_ERR(regmap)) 694 if (IS_ERR(regmap))
548 return PTR_ERR(regmap); 695 return PTR_ERR(regmap);
@@ -553,6 +700,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
553 return -ENOMEM; 700 return -ENOMEM;
554 701
555 dev_set_drvdata(dev, cs42l51); 702 dev_set_drvdata(dev, cs42l51);
703 cs42l51->regmap = regmap;
556 704
557 cs42l51->mclk_handle = devm_clk_get(dev, "MCLK"); 705 cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
558 if (IS_ERR(cs42l51->mclk_handle)) { 706 if (IS_ERR(cs42l51->mclk_handle)) {
@@ -561,6 +709,34 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
561 cs42l51->mclk_handle = NULL; 709 cs42l51->mclk_handle = NULL;
562 } 710 }
563 711
712 for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++)
713 cs42l51->supplies[i].supply = cs42l51_supply_names[i];
714
715 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs42l51->supplies),
716 cs42l51->supplies);
717 if (ret != 0) {
718 dev_err(dev, "Failed to request supplies: %d\n", ret);
719 return ret;
720 }
721
722 ret = regulator_bulk_enable(ARRAY_SIZE(cs42l51->supplies),
723 cs42l51->supplies);
724 if (ret != 0) {
725 dev_err(dev, "Failed to enable supplies: %d\n", ret);
726 return ret;
727 }
728
729 cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset",
730 GPIOD_OUT_LOW);
731 if (IS_ERR(cs42l51->reset_gpio))
732 return PTR_ERR(cs42l51->reset_gpio);
733
734 if (cs42l51->reset_gpio) {
735 dev_dbg(dev, "Release reset gpio\n");
736 gpiod_set_value_cansleep(cs42l51->reset_gpio, 0);
737 mdelay(2);
738 }
739
564 /* Verify that we have a CS42L51 */ 740 /* Verify that we have a CS42L51 */
565 ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); 741 ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
566 if (ret < 0) { 742 if (ret < 0) {
@@ -579,11 +755,50 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
579 755
580 ret = devm_snd_soc_register_component(dev, 756 ret = devm_snd_soc_register_component(dev,
581 &soc_component_device_cs42l51, &cs42l51_dai, 1); 757 &soc_component_device_cs42l51, &cs42l51_dai, 1);
758 if (ret < 0)
759 goto error;
760
761 return 0;
762
582error: 763error:
764 regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
765 cs42l51->supplies);
583 return ret; 766 return ret;
584} 767}
585EXPORT_SYMBOL_GPL(cs42l51_probe); 768EXPORT_SYMBOL_GPL(cs42l51_probe);
586 769
770int cs42l51_remove(struct device *dev)
771{
772 struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
773
774 gpiod_set_value_cansleep(cs42l51->reset_gpio, 1);
775
776 return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
777 cs42l51->supplies);
778}
779EXPORT_SYMBOL_GPL(cs42l51_remove);
780
781int __maybe_unused cs42l51_suspend(struct device *dev)
782{
783 struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
784
785 regcache_cache_only(cs42l51->regmap, true);
786 regcache_mark_dirty(cs42l51->regmap);
787
788 return 0;
789}
790EXPORT_SYMBOL_GPL(cs42l51_suspend);
791
792int __maybe_unused cs42l51_resume(struct device *dev)
793{
794 struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
795
796 regcache_cache_only(cs42l51->regmap, false);
797
798 return regcache_sync(cs42l51->regmap);
799}
800EXPORT_SYMBOL_GPL(cs42l51_resume);
801
587const struct of_device_id cs42l51_of_match[] = { 802const struct of_device_id cs42l51_of_match[] = {
588 { .compatible = "cirrus,cs42l51", }, 803 { .compatible = "cirrus,cs42l51", },
589 { } 804 { }
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
index 0ca805492ac4..79dee01137c8 100644
--- a/sound/soc/codecs/cs42l51.h
+++ b/sound/soc/codecs/cs42l51.h
@@ -22,6 +22,9 @@ struct device;
22 22
23extern const struct regmap_config cs42l51_regmap; 23extern const struct regmap_config cs42l51_regmap;
24int cs42l51_probe(struct device *dev, struct regmap *regmap); 24int cs42l51_probe(struct device *dev, struct regmap *regmap);
25int cs42l51_remove(struct device *dev);
26int __maybe_unused cs42l51_suspend(struct device *dev);
27int __maybe_unused cs42l51_resume(struct device *dev);
25extern const struct of_device_id cs42l51_of_match[]; 28extern const struct of_device_id cs42l51_of_match[];
26 29
27#define CS42L51_CHIP_ID 0x1B 30#define CS42L51_CHIP_ID 0x1B
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index 3f7b255587e6..80d672710eae 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -2322,6 +2322,8 @@ static int cs43130_probe(struct snd_soc_component *component)
2322 return ret; 2322 return ret;
2323 2323
2324 cs43130->wq = create_singlethread_workqueue("cs43130_hp"); 2324 cs43130->wq = create_singlethread_workqueue("cs43130_hp");
2325 if (!cs43130->wq)
2326 return -ENOMEM;
2325 INIT_WORK(&cs43130->work, cs43130_imp_meas); 2327 INIT_WORK(&cs43130->work, cs43130_imp_meas);
2326 } 2328 }
2327 2329
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index b16832a6a9af..eebbf02e1c39 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -75,7 +75,9 @@ static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
75 75
76 v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; 76 v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
77 77
78 return wm_adsp2_early_event(w, kcontrol, event, v); 78 wm_adsp2_set_dspclk(w, v);
79
80 return wm_adsp_early_event(w, kcontrol, event);
79} 81}
80 82
81static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); 83static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 92d006a5283e..425c11d63e49 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1305,7 +1305,10 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
1305 /* By default only 64 BCLK per WCLK is supported */ 1305 /* By default only 64 BCLK per WCLK is supported */
1306 dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64; 1306 dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64;
1307 1307
1308 snd_soc_component_write(component, DA7213_DAI_CLK_MODE, dai_clk_mode); 1308 snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE,
1309 DA7213_DAI_BCLKS_PER_WCLK_MASK |
1310 DA7213_DAI_CLK_POL_MASK | DA7213_DAI_WCLK_POL_MASK,
1311 dai_clk_mode);
1309 snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK, 1312 snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
1310 dai_ctrl); 1313 dai_ctrl);
1311 snd_soc_component_write(component, DA7213_DAI_OFFSET, dai_offset); 1314 snd_soc_component_write(component, DA7213_DAI_OFFSET, dai_offset);
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h
index 5a78dba1dcb5..9d31efc3cfe5 100644
--- a/sound/soc/codecs/da7213.h
+++ b/sound/soc/codecs/da7213.h
@@ -181,7 +181,9 @@
181#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0) 181#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0)
182#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) 182#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
183#define DA7213_DAI_CLK_POL_INV (0x1 << 2) 183#define DA7213_DAI_CLK_POL_INV (0x1 << 2)
184#define DA7213_DAI_CLK_POL_MASK (0x1 << 2)
184#define DA7213_DAI_WCLK_POL_INV (0x1 << 3) 185#define DA7213_DAI_WCLK_POL_INV (0x1 << 3)
186#define DA7213_DAI_WCLK_POL_MASK (0x1 << 3)
185#define DA7213_DAI_CLK_EN_MASK (0x1 << 7) 187#define DA7213_DAI_CLK_EN_MASK (0x1 << 7)
186 188
187/* DA7213_DAI_CTRL = 0x29 */ 189/* DA7213_DAI_CTRL = 0x29 */
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 121a8190f93e..7d9d1f84eed8 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -797,6 +797,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
797{ 797{
798 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 798 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
799 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 799 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
800 struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
800 u8 pll_ctrl, pll_status; 801 u8 pll_ctrl, pll_status;
801 int i = 0, ret; 802 int i = 0, ret;
802 bool srm_lock = false; 803 bool srm_lock = false;
@@ -805,11 +806,11 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
805 case SND_SOC_DAPM_PRE_PMU: 806 case SND_SOC_DAPM_PRE_PMU:
806 if (da7219->master) { 807 if (da7219->master) {
807 /* Enable DAI clks for master mode */ 808 /* Enable DAI clks for master mode */
808 if (da7219->dai_clks) { 809 if (bclk) {
809 ret = clk_prepare_enable(da7219->dai_clks); 810 ret = clk_prepare_enable(bclk);
810 if (ret) { 811 if (ret) {
811 dev_err(component->dev, 812 dev_err(component->dev,
812 "Failed to enable dai_clks\n"); 813 "Failed to enable DAI clks\n");
813 return ret; 814 return ret;
814 } 815 }
815 } else { 816 } else {
@@ -852,8 +853,8 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
852 853
853 /* Disable DAI clks if in master mode */ 854 /* Disable DAI clks if in master mode */
854 if (da7219->master) { 855 if (da7219->master) {
855 if (da7219->dai_clks) 856 if (bclk)
856 clk_disable_unprepare(da7219->dai_clks); 857 clk_disable_unprepare(bclk);
857 else 858 else
858 snd_soc_component_update_bits(component, 859 snd_soc_component_update_bits(component,
859 DA7219_DAI_CLK_MODE, 860 DA7219_DAI_CLK_MODE,
@@ -1385,17 +1386,50 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
1385 return 0; 1386 return 0;
1386} 1387}
1387 1388
1389static int da7219_set_bclks_per_wclk(struct snd_soc_component *component,
1390 unsigned long factor)
1391{
1392 u8 bclks_per_wclk;
1393
1394 switch (factor) {
1395 case 32:
1396 bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
1397 break;
1398 case 64:
1399 bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
1400 break;
1401 case 128:
1402 bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
1403 break;
1404 case 256:
1405 bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
1406 break;
1407 default:
1408 return -EINVAL;
1409 }
1410
1411 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
1412 DA7219_DAI_BCLKS_PER_WCLK_MASK,
1413 bclks_per_wclk);
1414
1415 return 0;
1416}
1417
1388static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, 1418static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
1389 unsigned int tx_mask, unsigned int rx_mask, 1419 unsigned int tx_mask, unsigned int rx_mask,
1390 int slots, int slot_width) 1420 int slots, int slot_width)
1391{ 1421{
1392 struct snd_soc_component *component = dai->component; 1422 struct snd_soc_component *component = dai->component;
1393 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 1423 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
1424 struct clk *wclk = da7219->dai_clks[DA7219_DAI_WCLK_IDX];
1425 struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
1394 unsigned int ch_mask; 1426 unsigned int ch_mask;
1395 u8 dai_bclks_per_wclk, slot_offset; 1427 unsigned long sr, bclk_rate;
1428 u8 slot_offset;
1396 u16 offset; 1429 u16 offset;
1397 __le16 dai_offset; 1430 __le16 dai_offset;
1398 u32 frame_size; 1431 u32 frame_size;
1432 int ret;
1399 1433
1400 /* No channels enabled so disable TDM */ 1434 /* No channels enabled so disable TDM */
1401 if (!tx_mask) { 1435 if (!tx_mask) {
@@ -1432,28 +1466,26 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
1432 */ 1466 */
1433 if (da7219->master) { 1467 if (da7219->master) {
1434 frame_size = slots * slot_width; 1468 frame_size = slots * slot_width;
1435 switch (frame_size) {
1436 case 32:
1437 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
1438 break;
1439 case 64:
1440 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
1441 break;
1442 case 128:
1443 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
1444 break;
1445 case 256:
1446 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
1447 break;
1448 default:
1449 dev_err(component->dev, "Invalid frame size %d\n",
1450 frame_size);
1451 return -EINVAL;
1452 }
1453 1469
1454 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, 1470 if (bclk) {
1455 DA7219_DAI_BCLKS_PER_WCLK_MASK, 1471 sr = clk_get_rate(wclk);
1456 dai_bclks_per_wclk); 1472 bclk_rate = sr * frame_size;
1473 ret = clk_set_rate(bclk, bclk_rate);
1474 if (ret) {
1475 dev_err(component->dev,
1476 "Failed to set TDM BCLK rate %lu: %d\n",
1477 bclk_rate, ret);
1478 return ret;
1479 }
1480 } else {
1481 ret = da7219_set_bclks_per_wclk(component, frame_size);
1482 if (ret) {
1483 dev_err(component->dev,
1484 "Failed to set TDM BCLKs per WCLK %d: %d\n",
1485 frame_size, ret);
1486 return ret;
1487 }
1488 }
1457 } 1489 }
1458 1490
1459 dai_offset = cpu_to_le16(offset); 1491 dai_offset = cpu_to_le16(offset);
@@ -1471,44 +1503,12 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
1471 return 0; 1503 return 0;
1472} 1504}
1473 1505
1474static int da7219_hw_params(struct snd_pcm_substream *substream, 1506static int da7219_set_sr(struct snd_soc_component *component,
1475 struct snd_pcm_hw_params *params, 1507 unsigned long rate)
1476 struct snd_soc_dai *dai)
1477{ 1508{
1478 struct snd_soc_component *component = dai->component; 1509 u8 fs;
1479 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
1480 u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs;
1481 unsigned int channels;
1482 int word_len = params_width(params);
1483 int frame_size;
1484 1510
1485 switch (word_len) { 1511 switch (rate) {
1486 case 16:
1487 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
1488 break;
1489 case 20:
1490 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE;
1491 break;
1492 case 24:
1493 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE;
1494 break;
1495 case 32:
1496 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE;
1497 break;
1498 default:
1499 return -EINVAL;
1500 }
1501
1502 channels = params_channels(params);
1503 if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
1504 dev_err(component->dev,
1505 "Invalid number of channels, only 1 to %d supported\n",
1506 DA7219_DAI_CH_NUM_MAX);
1507 return -EINVAL;
1508 }
1509 dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT;
1510
1511 switch (params_rate(params)) {
1512 case 8000: 1512 case 8000:
1513 fs = DA7219_SR_8000; 1513 fs = DA7219_SR_8000;
1514 break; 1514 break;
@@ -1546,28 +1546,118 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
1546 return -EINVAL; 1546 return -EINVAL;
1547 } 1547 }
1548 1548
1549 snd_soc_component_write(component, DA7219_SR, fs);
1550
1551 return 0;
1552}
1553
1554static int da7219_hw_params(struct snd_pcm_substream *substream,
1555 struct snd_pcm_hw_params *params,
1556 struct snd_soc_dai *dai)
1557{
1558 struct snd_soc_component *component = dai->component;
1559 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
1560 struct clk *wclk = da7219->dai_clks[DA7219_DAI_WCLK_IDX];
1561 struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
1562 u8 dai_ctrl = 0;
1563 unsigned int channels;
1564 unsigned long sr, bclk_rate;
1565 int word_len = params_width(params);
1566 int frame_size, ret;
1567
1568 switch (word_len) {
1569 case 16:
1570 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
1571 break;
1572 case 20:
1573 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE;
1574 break;
1575 case 24:
1576 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE;
1577 break;
1578 case 32:
1579 dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE;
1580 break;
1581 default:
1582 return -EINVAL;
1583 }
1584
1585 channels = params_channels(params);
1586 if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
1587 dev_err(component->dev,
1588 "Invalid number of channels, only 1 to %d supported\n",
1589 DA7219_DAI_CH_NUM_MAX);
1590 return -EINVAL;
1591 }
1592 dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT;
1593
1594 sr = params_rate(params);
1595 if (da7219->master && wclk) {
1596 ret = clk_set_rate(wclk, sr);
1597 if (ret) {
1598 dev_err(component->dev,
1599 "Failed to set WCLK SR %lu: %d\n", sr, ret);
1600 return ret;
1601 }
1602 } else {
1603 ret = da7219_set_sr(component, sr);
1604 if (ret) {
1605 dev_err(component->dev,
1606 "Failed to set SR %lu: %d\n", sr, ret);
1607 return ret;
1608 }
1609 }
1610
1549 /* 1611 /*
1550 * If we're master, then we have a limited set of BCLK rates we 1612 * If we're master, then we have a limited set of BCLK rates we
1551 * support. For slave mode this isn't the case and the codec can detect 1613 * support. For slave mode this isn't the case and the codec can detect
1552 * the BCLK rate automatically. 1614 * the BCLK rate automatically.
1553 */ 1615 */
1554 if (da7219->master && !da7219->tdm_en) { 1616 if (da7219->master && !da7219->tdm_en) {
1555 frame_size = word_len * 2; 1617 if ((word_len * DA7219_DAI_CH_NUM_MAX) <= 32)
1556 if (frame_size <= 32) 1618 frame_size = 32;
1557 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
1558 else 1619 else
1559 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; 1620 frame_size = 64;
1621
1622 if (bclk) {
1623 bclk_rate = frame_size * sr;
1624 /*
1625 * Rounding the rate here avoids failure trying to set a
1626 * new rate on an already enabled bclk. In that
1627 * instance this will just set the same rate as is
1628 * currently in use, and so should continue without
1629 * problem, as long as the BCLK rate is suitable for the
1630 * desired frame size.
1631 */
1632 bclk_rate = clk_round_rate(bclk, bclk_rate);
1633 if ((bclk_rate / sr) < frame_size) {
1634 dev_err(component->dev,
1635 "BCLK rate mismatch against frame size");
1636 return -EINVAL;
1637 }
1560 1638
1561 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, 1639 ret = clk_set_rate(bclk, bclk_rate);
1562 DA7219_DAI_BCLKS_PER_WCLK_MASK, 1640 if (ret) {
1563 dai_bclks_per_wclk); 1641 dev_err(component->dev,
1642 "Failed to set BCLK rate %lu: %d\n",
1643 bclk_rate, ret);
1644 return ret;
1645 }
1646 } else {
1647 ret = da7219_set_bclks_per_wclk(component, frame_size);
1648 if (ret) {
1649 dev_err(component->dev,
1650 "Failed to set BCLKs per WCLK %d: %d\n",
1651 frame_size, ret);
1652 return ret;
1653 }
1654 }
1564 } 1655 }
1565 1656
1566 snd_soc_component_update_bits(component, DA7219_DAI_CTRL, 1657 snd_soc_component_update_bits(component, DA7219_DAI_CTRL,
1567 DA7219_DAI_WORD_LENGTH_MASK | 1658 DA7219_DAI_WORD_LENGTH_MASK |
1568 DA7219_DAI_CH_NUM_MASK, 1659 DA7219_DAI_CH_NUM_MASK,
1569 dai_ctrl); 1660 dai_ctrl);
1570 snd_soc_component_write(component, DA7219_SR, fs);
1571 1661
1572 return 0; 1662 return 0;
1573} 1663}
@@ -1583,20 +1673,26 @@ static const struct snd_soc_dai_ops da7219_dai_ops = {
1583#define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 1673#define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
1584 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 1674 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
1585 1675
1676#define DA7219_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
1677 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
1678 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
1679 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
1680 SNDRV_PCM_RATE_96000)
1681
1586static struct snd_soc_dai_driver da7219_dai = { 1682static struct snd_soc_dai_driver da7219_dai = {
1587 .name = "da7219-hifi", 1683 .name = "da7219-hifi",
1588 .playback = { 1684 .playback = {
1589 .stream_name = "Playback", 1685 .stream_name = "Playback",
1590 .channels_min = 1, 1686 .channels_min = 1,
1591 .channels_max = DA7219_DAI_CH_NUM_MAX, 1687 .channels_max = DA7219_DAI_CH_NUM_MAX,
1592 .rates = SNDRV_PCM_RATE_8000_96000, 1688 .rates = DA7219_RATES,
1593 .formats = DA7219_FORMATS, 1689 .formats = DA7219_FORMATS,
1594 }, 1690 },
1595 .capture = { 1691 .capture = {
1596 .stream_name = "Capture", 1692 .stream_name = "Capture",
1597 .channels_min = 1, 1693 .channels_min = 1,
1598 .channels_max = DA7219_DAI_CH_NUM_MAX, 1694 .channels_max = DA7219_DAI_CH_NUM_MAX,
1599 .rates = SNDRV_PCM_RATE_8000_96000, 1695 .rates = DA7219_RATES,
1600 .formats = DA7219_FORMATS, 1696 .formats = DA7219_FORMATS,
1601 }, 1697 },
1602 .ops = &da7219_dai_ops, 1698 .ops = &da7219_dai_ops,
@@ -1672,11 +1768,14 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_component *compone
1672 1768
1673 pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source"); 1769 pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source");
1674 1770
1675 pdata->dai_clks_name = "da7219-dai-clks"; 1771 pdata->dai_clk_names[DA7219_DAI_WCLK_IDX] = "da7219-dai-wclk";
1676 if (device_property_read_string(dev, "clock-output-names", 1772 pdata->dai_clk_names[DA7219_DAI_BCLK_IDX] = "da7219-dai-bclk";
1677 &pdata->dai_clks_name)) 1773 if (device_property_read_string_array(dev, "clock-output-names",
1678 dev_warn(dev, "Using default clk name: %s\n", 1774 pdata->dai_clk_names,
1679 pdata->dai_clks_name); 1775 DA7219_DAI_NUM_CLKS) < 0)
1776 dev_warn(dev, "Using default DAI clk names: %s, %s\n",
1777 pdata->dai_clk_names[DA7219_DAI_WCLK_IDX],
1778 pdata->dai_clk_names[DA7219_DAI_BCLK_IDX]);
1680 1779
1681 if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0) 1780 if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0)
1682 pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32); 1781 pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32);
@@ -1793,12 +1892,16 @@ static int da7219_handle_supplies(struct snd_soc_component *component)
1793} 1892}
1794 1893
1795#ifdef CONFIG_COMMON_CLK 1894#ifdef CONFIG_COMMON_CLK
1796static int da7219_dai_clks_prepare(struct clk_hw *hw) 1895static int da7219_wclk_prepare(struct clk_hw *hw)
1797{ 1896{
1798 struct da7219_priv *da7219 = 1897 struct da7219_priv *da7219 =
1799 container_of(hw, struct da7219_priv, dai_clks_hw); 1898 container_of(hw, struct da7219_priv,
1899 dai_clks_hw[DA7219_DAI_WCLK_IDX]);
1800 struct snd_soc_component *component = da7219->component; 1900 struct snd_soc_component *component = da7219->component;
1801 1901
1902 if (!da7219->master)
1903 return -EINVAL;
1904
1802 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, 1905 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
1803 DA7219_DAI_CLK_EN_MASK, 1906 DA7219_DAI_CLK_EN_MASK,
1804 DA7219_DAI_CLK_EN_MASK); 1907 DA7219_DAI_CLK_EN_MASK);
@@ -1806,33 +1909,42 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw)
1806 return 0; 1909 return 0;
1807} 1910}
1808 1911
1809static void da7219_dai_clks_unprepare(struct clk_hw *hw) 1912static void da7219_wclk_unprepare(struct clk_hw *hw)
1810{ 1913{
1811 struct da7219_priv *da7219 = 1914 struct da7219_priv *da7219 =
1812 container_of(hw, struct da7219_priv, dai_clks_hw); 1915 container_of(hw, struct da7219_priv,
1916 dai_clks_hw[DA7219_DAI_WCLK_IDX]);
1813 struct snd_soc_component *component = da7219->component; 1917 struct snd_soc_component *component = da7219->component;
1814 1918
1919 if (!da7219->master)
1920 return;
1921
1815 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, 1922 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
1816 DA7219_DAI_CLK_EN_MASK, 0); 1923 DA7219_DAI_CLK_EN_MASK, 0);
1817} 1924}
1818 1925
1819static int da7219_dai_clks_is_prepared(struct clk_hw *hw) 1926static int da7219_wclk_is_prepared(struct clk_hw *hw)
1820{ 1927{
1821 struct da7219_priv *da7219 = 1928 struct da7219_priv *da7219 =
1822 container_of(hw, struct da7219_priv, dai_clks_hw); 1929 container_of(hw, struct da7219_priv,
1930 dai_clks_hw[DA7219_DAI_WCLK_IDX]);
1823 struct snd_soc_component *component = da7219->component; 1931 struct snd_soc_component *component = da7219->component;
1824 u8 clk_reg; 1932 u8 clk_reg;
1825 1933
1934 if (!da7219->master)
1935 return -EINVAL;
1936
1826 clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE); 1937 clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE);
1827 1938
1828 return !!(clk_reg & DA7219_DAI_CLK_EN_MASK); 1939 return !!(clk_reg & DA7219_DAI_CLK_EN_MASK);
1829} 1940}
1830 1941
1831static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, 1942static unsigned long da7219_wclk_recalc_rate(struct clk_hw *hw,
1832 unsigned long parent_rate) 1943 unsigned long parent_rate)
1833{ 1944{
1834 struct da7219_priv *da7219 = 1945 struct da7219_priv *da7219 =
1835 container_of(hw, struct da7219_priv, dai_clks_hw); 1946 container_of(hw, struct da7219_priv,
1947 dai_clks_hw[DA7219_DAI_WCLK_IDX]);
1836 struct snd_soc_component *component = da7219->component; 1948 struct snd_soc_component *component = da7219->component;
1837 u8 fs = snd_soc_component_read32(component, DA7219_SR); 1949 u8 fs = snd_soc_component_read32(component, DA7219_SR);
1838 1950
@@ -1864,11 +1976,148 @@ static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw,
1864 } 1976 }
1865} 1977}
1866 1978
1867static const struct clk_ops da7219_dai_clks_ops = { 1979static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
1868 .prepare = da7219_dai_clks_prepare, 1980 unsigned long *parent_rate)
1869 .unprepare = da7219_dai_clks_unprepare, 1981{
1870 .is_prepared = da7219_dai_clks_is_prepared, 1982 struct da7219_priv *da7219 =
1871 .recalc_rate = da7219_dai_clks_recalc_rate, 1983 container_of(hw, struct da7219_priv,
1984 dai_clks_hw[DA7219_DAI_WCLK_IDX]);
1985
1986 if (!da7219->master)
1987 return -EINVAL;
1988
1989 if (rate < 11025)
1990 return 8000;
1991 else if (rate < 12000)
1992 return 11025;
1993 else if (rate < 16000)
1994 return 12000;
1995 else if (rate < 22050)
1996 return 16000;
1997 else if (rate < 24000)
1998 return 22050;
1999 else if (rate < 32000)
2000 return 24000;
2001 else if (rate < 44100)
2002 return 32000;
2003 else if (rate < 48000)
2004 return 44100;
2005 else if (rate < 88200)
2006 return 48000;
2007 else if (rate < 96000)
2008 return 88200;
2009 else
2010 return 96000;
2011}
2012
2013static int da7219_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
2014 unsigned long parent_rate)
2015{
2016 struct da7219_priv *da7219 =
2017 container_of(hw, struct da7219_priv,
2018 dai_clks_hw[DA7219_DAI_WCLK_IDX]);
2019 struct snd_soc_component *component = da7219->component;
2020
2021 if (!da7219->master)
2022 return -EINVAL;
2023
2024 return da7219_set_sr(component, rate);
2025}
2026
2027static unsigned long da7219_bclk_recalc_rate(struct clk_hw *hw,
2028 unsigned long parent_rate)
2029{
2030 struct da7219_priv *da7219 =
2031 container_of(hw, struct da7219_priv,
2032 dai_clks_hw[DA7219_DAI_BCLK_IDX]);
2033 struct snd_soc_component *component = da7219->component;
2034 u8 bclks_per_wclk = snd_soc_component_read32(component,
2035 DA7219_DAI_CLK_MODE);
2036
2037 switch (bclks_per_wclk & DA7219_DAI_BCLKS_PER_WCLK_MASK) {
2038 case DA7219_DAI_BCLKS_PER_WCLK_32:
2039 return parent_rate * 32;
2040 case DA7219_DAI_BCLKS_PER_WCLK_64:
2041 return parent_rate * 64;
2042 case DA7219_DAI_BCLKS_PER_WCLK_128:
2043 return parent_rate * 128;
2044 case DA7219_DAI_BCLKS_PER_WCLK_256:
2045 return parent_rate * 256;
2046 default:
2047 return 0;
2048 }
2049}
2050
2051static unsigned long da7219_bclk_get_factor(unsigned long rate,
2052 unsigned long parent_rate)
2053{
2054 unsigned long factor;
2055
2056 factor = rate / parent_rate;
2057 if (factor < 64)
2058 return 32;
2059 else if (factor < 128)
2060 return 64;
2061 else if (factor < 256)
2062 return 128;
2063 else
2064 return 256;
2065}
2066
2067static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
2068 unsigned long *parent_rate)
2069{
2070 struct da7219_priv *da7219 =
2071 container_of(hw, struct da7219_priv,
2072 dai_clks_hw[DA7219_DAI_BCLK_IDX]);
2073 unsigned long factor;
2074
2075 if (!*parent_rate || !da7219->master)
2076 return -EINVAL;
2077
2078 /*
2079 * We don't allow changing the parent rate as some BCLK rates can be
2080 * derived from multiple parent WCLK rates (BCLK rates are set as a
2081 * multiplier of WCLK in HW). We just do some rounding down based on the
2082 * parent WCLK rate set and find the appropriate multiplier of BCLK to
2083 * get the rounded down BCLK value.
2084 */
2085 factor = da7219_bclk_get_factor(rate, *parent_rate);
2086
2087 return *parent_rate * factor;
2088}
2089
2090static int da7219_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
2091 unsigned long parent_rate)
2092{
2093 struct da7219_priv *da7219 =
2094 container_of(hw, struct da7219_priv,
2095 dai_clks_hw[DA7219_DAI_BCLK_IDX]);
2096 struct snd_soc_component *component = da7219->component;
2097 unsigned long factor;
2098
2099 if (!da7219->master)
2100 return -EINVAL;
2101
2102 factor = da7219_bclk_get_factor(rate, parent_rate);
2103
2104 return da7219_set_bclks_per_wclk(component, factor);
2105}
2106
2107static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = {
2108 [DA7219_DAI_WCLK_IDX] = {
2109 .prepare = da7219_wclk_prepare,
2110 .unprepare = da7219_wclk_unprepare,
2111 .is_prepared = da7219_wclk_is_prepared,
2112 .recalc_rate = da7219_wclk_recalc_rate,
2113 .round_rate = da7219_wclk_round_rate,
2114 .set_rate = da7219_wclk_set_rate,
2115 },
2116 [DA7219_DAI_BCLK_IDX] = {
2117 .recalc_rate = da7219_bclk_recalc_rate,
2118 .round_rate = da7219_bclk_round_rate,
2119 .set_rate = da7219_bclk_set_rate,
2120 },
1872}; 2121};
1873 2122
1874static int da7219_register_dai_clks(struct snd_soc_component *component) 2123static int da7219_register_dai_clks(struct snd_soc_component *component)
@@ -1876,47 +2125,81 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
1876 struct device *dev = component->dev; 2125 struct device *dev = component->dev;
1877 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 2126 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
1878 struct da7219_pdata *pdata = da7219->pdata; 2127 struct da7219_pdata *pdata = da7219->pdata;
1879 struct clk_init_data init = {};
1880 struct clk *dai_clks;
1881 struct clk_lookup *dai_clks_lookup;
1882 const char *parent_name; 2128 const char *parent_name;
2129 int i, ret;
1883 2130
1884 if (da7219->mclk) { 2131 for (i = 0; i < DA7219_DAI_NUM_CLKS; ++i) {
1885 parent_name = __clk_get_name(da7219->mclk); 2132 struct clk_init_data init = {};
1886 init.parent_names = &parent_name; 2133 struct clk *dai_clk;
1887 init.num_parents = 1; 2134 struct clk_lookup *dai_clk_lookup;
1888 } else { 2135 struct clk_hw *dai_clk_hw = &da7219->dai_clks_hw[i];
1889 init.parent_names = NULL;
1890 init.num_parents = 0;
1891 }
1892 2136
1893 init.name = pdata->dai_clks_name; 2137 switch (i) {
1894 init.ops = &da7219_dai_clks_ops; 2138 case DA7219_DAI_WCLK_IDX:
1895 init.flags = CLK_GET_RATE_NOCACHE; 2139 /*
1896 da7219->dai_clks_hw.init = &init; 2140 * If we can, make MCLK the parent of WCLK to ensure
2141 * it's enabled as required.
2142 */
2143 if (da7219->mclk) {
2144 parent_name = __clk_get_name(da7219->mclk);
2145 init.parent_names = &parent_name;
2146 init.num_parents = 1;
2147 } else {
2148 init.parent_names = NULL;
2149 init.num_parents = 0;
2150 }
2151 break;
2152 case DA7219_DAI_BCLK_IDX:
2153 /* Make WCLK the parent of BCLK */
2154 parent_name = __clk_get_name(da7219->dai_clks[DA7219_DAI_WCLK_IDX]);
2155 init.parent_names = &parent_name;
2156 init.num_parents = 1;
2157 break;
2158 default:
2159 dev_err(dev, "Invalid clock index\n");
2160 ret = -EINVAL;
2161 goto err;
2162 }
1897 2163
1898 dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw); 2164 init.name = pdata->dai_clk_names[i];
1899 if (IS_ERR(dai_clks)) { 2165 init.ops = &da7219_dai_clk_ops[i];
1900 dev_warn(dev, "Failed to register DAI clocks: %ld\n", 2166 init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE;
1901 PTR_ERR(dai_clks)); 2167 dai_clk_hw->init = &init;
1902 return PTR_ERR(dai_clks); 2168
1903 } 2169 dai_clk = devm_clk_register(dev, dai_clk_hw);
1904 da7219->dai_clks = dai_clks; 2170 if (IS_ERR(dai_clk)) {
2171 dev_warn(dev, "Failed to register %s: %ld\n",
2172 init.name, PTR_ERR(dai_clk));
2173 ret = PTR_ERR(dai_clk);
2174 goto err;
2175 }
2176 da7219->dai_clks[i] = dai_clk;
1905 2177
1906 /* If we're using DT, then register as provider accordingly */ 2178 /* If we're using DT, then register as provider accordingly */
1907 if (dev->of_node) { 2179 if (dev->of_node) {
1908 devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, 2180 devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
1909 &da7219->dai_clks_hw); 2181 dai_clk_hw);
1910 } else { 2182 } else {
1911 dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name, 2183 dai_clk_lookup = clkdev_create(dai_clk, init.name,
1912 "%s", dev_name(dev)); 2184 "%s", dev_name(dev));
1913 if (!dai_clks_lookup) 2185 if (!dai_clk_lookup) {
1914 return -ENOMEM; 2186 ret = -ENOMEM;
1915 else 2187 goto err;
1916 da7219->dai_clks_lookup = dai_clks_lookup; 2188 } else {
2189 da7219->dai_clks_lookup[i] = dai_clk_lookup;
2190 }
2191 }
1917 } 2192 }
1918 2193
1919 return 0; 2194 return 0;
2195
2196err:
2197 do {
2198 if (da7219->dai_clks_lookup[i])
2199 clkdev_drop(da7219->dai_clks_lookup[i]);
2200 } while (i-- > 0);
2201
2202 return ret;
1920} 2203}
1921#else 2204#else
1922static inline int da7219_register_dai_clks(struct snd_soc_component *component) 2205static inline int da7219_register_dai_clks(struct snd_soc_component *component)
@@ -2080,12 +2363,17 @@ err_disable_reg:
2080static void da7219_remove(struct snd_soc_component *component) 2363static void da7219_remove(struct snd_soc_component *component)
2081{ 2364{
2082 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 2365 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
2366#ifdef CONFIG_COMMON_CLK
2367 int i;
2368#endif
2083 2369
2084 da7219_aad_exit(component); 2370 da7219_aad_exit(component);
2085 2371
2086#ifdef CONFIG_COMMON_CLK 2372#ifdef CONFIG_COMMON_CLK
2087 if (da7219->dai_clks_lookup) 2373 for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) {
2088 clkdev_drop(da7219->dai_clks_lookup); 2374 if (da7219->dai_clks_lookup[i])
2375 clkdev_drop(da7219->dai_clks_lookup[i]);
2376 }
2089#endif 2377#endif
2090 2378
2091 /* Supplies */ 2379 /* Supplies */
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index 018819c631fb..f3b180bc986f 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -820,10 +820,10 @@ struct da7219_priv {
820 struct mutex pll_lock; 820 struct mutex pll_lock;
821 821
822#ifdef CONFIG_COMMON_CLK 822#ifdef CONFIG_COMMON_CLK
823 struct clk_hw dai_clks_hw; 823 struct clk_hw dai_clks_hw[DA7219_DAI_NUM_CLKS];
824#endif 824#endif
825 struct clk_lookup *dai_clks_lookup; 825 struct clk_lookup *dai_clks_lookup[DA7219_DAI_NUM_CLKS];
826 struct clk *dai_clks; 826 struct clk *dai_clks[DA7219_DAI_NUM_CLKS];
827 827
828 struct clk *mclk; 828 struct clk *mclk;
829 unsigned int mclk_rate; 829 unsigned int mclk_rate;
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 6d4a323f786b..ec2770b3f77d 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -43,6 +43,7 @@ struct es8316_priv {
43 unsigned int sysclk; 43 unsigned int sysclk;
44 unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; 44 unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
45 struct snd_pcm_hw_constraint_list sysclk_constraints; 45 struct snd_pcm_hw_constraint_list sysclk_constraints;
46 bool jd_inverted;
46}; 47};
47 48
48/* 49/*
@@ -577,6 +578,9 @@ static irqreturn_t es8316_irq(int irq, void *data)
577 if (!es8316->jack) 578 if (!es8316->jack)
578 goto out; 579 goto out;
579 580
581 if (es8316->jd_inverted)
582 flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
583
580 dev_dbg(comp->dev, "gpio flags %#04x\n", flags); 584 dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
581 if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { 585 if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
582 /* Jack removed, or spurious IRQ? */ 586 /* Jack removed, or spurious IRQ? */
@@ -592,6 +596,8 @@ static irqreturn_t es8316_irq(int irq, void *data)
592 /* Jack inserted, determine type */ 596 /* Jack inserted, determine type */
593 es8316_enable_micbias_for_mic_gnd_short_detect(comp); 597 es8316_enable_micbias_for_mic_gnd_short_detect(comp);
594 regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); 598 regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
599 if (es8316->jd_inverted)
600 flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
595 dev_dbg(comp->dev, "gpio flags %#04x\n", flags); 601 dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
596 if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { 602 if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
597 /* Jack unplugged underneath us */ 603 /* Jack unplugged underneath us */
@@ -633,6 +639,14 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component,
633{ 639{
634 struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); 640 struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
635 641
642 /*
643 * Init es8316->jd_inverted here and not in the probe, as we cannot
644 * guarantee that the bytchr-es8316 driver, which might set this
645 * property, will probe before us.
646 */
647 es8316->jd_inverted = device_property_read_bool(component->dev,
648 "everest,jack-detect-inverted");
649
636 mutex_lock(&es8316->lock); 650 mutex_lock(&es8316->lock);
637 651
638 es8316->jack = jack; 652 es8316->jack = jack;
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index f889d94c8e3c..7d4940256914 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -328,6 +328,12 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
328 dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); 328 dev_err(&hdev->dev, "failed to create hda codec %d\n", ret);
329 goto error_no_pm; 329 goto error_no_pm;
330 } 330 }
331 /*
332 * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver
333 * hda_codec.c will check this flag to determine if unregister
334 * device is needed.
335 */
336 hdev->type = HDA_DEV_ASOC;
331 337
332 /* 338 /*
333 * snd_hda_codec_device_new decrements the usage count so call get pm 339 * snd_hda_codec_device_new decrements the usage count so call get pm
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 5eeb0fe836a9..660e0587f399 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -455,24 +455,11 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
455 struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) 455 struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
456{ 456{
457 struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai); 457 struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
458 struct hdac_device *hdev = hdmi->hdev;
459 struct hdac_hdmi_dai_port_map *dai_map; 458 struct hdac_hdmi_dai_port_map *dai_map;
460 struct hdac_hdmi_port *port;
461 struct hdac_hdmi_pcm *pcm; 459 struct hdac_hdmi_pcm *pcm;
462 int format; 460 int format;
463 461
464 dai_map = &hdmi->dai_map[dai->id]; 462 dai_map = &hdmi->dai_map[dai->id];
465 port = dai_map->port;
466
467 if (!port)
468 return -ENODEV;
469
470 if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
471 dev_err(&hdev->dev,
472 "device is not configured for this pin:port%d:%d\n",
473 port->pin->nid, port->id);
474 return -ENODEV;
475 }
476 463
477 format = snd_hdac_calc_stream_format(params_rate(hparams), 464 format = snd_hdac_calc_stream_format(params_rate(hparams),
478 params_channels(hparams), params_format(hparams), 465 params_channels(hparams), params_format(hparams),
@@ -1855,6 +1842,17 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
1855 hdmi->card = dapm->card->snd_card; 1842 hdmi->card = dapm->card->snd_card;
1856 1843
1857 /* 1844 /*
1845 * Setup a device_link between card device and HDMI codec device.
1846 * The card device is the consumer and the HDMI codec device is
1847 * the supplier. With this setting, we can make sure that the audio
1848 * domain in display power will be always turned on before operating
1849 * on the HDMI audio codec registers.
1850 * Let's use the flag DL_FLAG_AUTOREMOVE_CONSUMER. This can make
1851 * sure the device link is freed when the machine driver is removed.
1852 */
1853 device_link_add(component->card->dev, &hdev->dev, DL_FLAG_RPM_ACTIVE |
1854 DL_FLAG_AUTOREMOVE_CONSUMER);
1855 /*
1858 * hdac_device core already sets the state to active and calls 1856 * hdac_device core already sets the state to active and calls
1859 * get_noresume. So enable runtime and set the device to suspend. 1857 * get_noresume. So enable runtime and set the device to suspend.
1860 */ 1858 */
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 35df73e42cbc..39caf19abb0b 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -439,8 +439,12 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
439 if (!ret) { 439 if (!ret) {
440 ret = snd_pcm_hw_constraint_eld(substream->runtime, 440 ret = snd_pcm_hw_constraint_eld(substream->runtime,
441 hcp->eld); 441 hcp->eld);
442 if (ret) 442 if (ret) {
443 mutex_lock(&hcp->current_stream_lock);
444 hcp->current_stream = NULL;
445 mutex_unlock(&hcp->current_stream_lock);
443 return ret; 446 return ret;
447 }
444 } 448 }
445 /* Select chmap supported */ 449 /* Select chmap supported */
446 hdmi_codec_eld_chmap(hcp); 450 hdmi_codec_eld_chmap(hcp);
@@ -492,10 +496,6 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
492 return ret; 496 return ret;
493 } 497 }
494 498
495 ret = hdmi_codec_new_stream(substream, dai);
496 if (ret)
497 return ret;
498
499 hdmi_audio_infoframe_init(&hp.cea); 499 hdmi_audio_infoframe_init(&hp.cea);
500 hp.cea.channels = params_channels(params); 500 hp.cea.channels = params_channels(params);
501 hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; 501 hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
@@ -757,7 +757,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
757 dev_dbg(dev, "%s()\n", __func__); 757 dev_dbg(dev, "%s()\n", __func__);
758 758
759 if (!hcd) { 759 if (!hcd) {
760 dev_err(dev, "%s: No plalform data\n", __func__); 760 dev_err(dev, "%s: No platform data\n", __func__);
761 return -EINVAL; 761 return -EINVAL;
762 } 762 }
763 763
diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c
new file mode 100644
index 000000000000..3209b39e46af
--- /dev/null
+++ b/sound/soc/codecs/lochnagar-sc.c
@@ -0,0 +1,266 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// Lochnagar sound card driver
4//
5// Copyright (c) 2017-2019 Cirrus Logic, Inc. and
6// Cirrus Logic International Semiconductor Ltd.
7//
8// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
9// Piotr Stankiewicz <piotrs@opensource.cirrus.com>
10
11#include <linux/clk.h>
12#include <linux/module.h>
13#include <sound/soc.h>
14
15#include <linux/mfd/lochnagar.h>
16#include <linux/mfd/lochnagar1_regs.h>
17#include <linux/mfd/lochnagar2_regs.h>
18
19struct lochnagar_sc_priv {
20 struct clk *mclk;
21};
22
23static const struct snd_soc_dapm_widget lochnagar_sc_widgets[] = {
24 SND_SOC_DAPM_LINE("Line Jack", NULL),
25 SND_SOC_DAPM_LINE("USB Audio", NULL),
26};
27
28static const struct snd_soc_dapm_route lochnagar_sc_routes[] = {
29 { "Line Jack", NULL, "AIF1 Playback" },
30 { "AIF1 Capture", NULL, "Line Jack" },
31
32 { "USB Audio", NULL, "USB1 Playback" },
33 { "USB Audio", NULL, "USB2 Playback" },
34 { "USB1 Capture", NULL, "USB Audio" },
35 { "USB2 Capture", NULL, "USB Audio" },
36};
37
38static const unsigned int lochnagar_sc_chan_vals[] = {
39 4, 8,
40};
41
42static const struct snd_pcm_hw_constraint_list lochnagar_sc_chan_constraint = {
43 .count = ARRAY_SIZE(lochnagar_sc_chan_vals),
44 .list = lochnagar_sc_chan_vals,
45};
46
47static const unsigned int lochnagar_sc_rate_vals[] = {
48 8000, 16000, 24000, 32000, 48000, 96000, 192000,
49 22050, 44100, 88200, 176400,
50};
51
52static const struct snd_pcm_hw_constraint_list lochnagar_sc_rate_constraint = {
53 .count = ARRAY_SIZE(lochnagar_sc_rate_vals),
54 .list = lochnagar_sc_rate_vals,
55};
56
57static int lochnagar_sc_hw_rule_rate(struct snd_pcm_hw_params *params,
58 struct snd_pcm_hw_rule *rule)
59{
60 struct snd_interval range = {
61 .min = 8000,
62 .max = 24576000 / hw_param_interval(params, rule->deps[0])->max,
63 };
64
65 return snd_interval_refine(hw_param_interval(params, rule->var),
66 &range);
67}
68
69static int lochnagar_sc_startup(struct snd_pcm_substream *substream,
70 struct snd_soc_dai *dai)
71{
72 struct snd_soc_component *comp = dai->component;
73 struct lochnagar_sc_priv *priv = snd_soc_component_get_drvdata(comp);
74 int ret;
75
76 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
77 SNDRV_PCM_HW_PARAM_RATE,
78 &lochnagar_sc_rate_constraint);
79 if (ret)
80 return ret;
81
82 return snd_pcm_hw_rule_add(substream->runtime, 0,
83 SNDRV_PCM_HW_PARAM_RATE,
84 lochnagar_sc_hw_rule_rate, priv,
85 SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
86}
87
88static int lochnagar_sc_line_startup(struct snd_pcm_substream *substream,
89 struct snd_soc_dai *dai)
90{
91 struct snd_soc_component *comp = dai->component;
92 struct lochnagar_sc_priv *priv = snd_soc_component_get_drvdata(comp);
93 int ret;
94
95 ret = clk_prepare_enable(priv->mclk);
96 if (ret < 0) {
97 dev_err(dai->dev, "Failed to enable MCLK: %d\n", ret);
98 return ret;
99 }
100
101 ret = lochnagar_sc_startup(substream, dai);
102 if (ret)
103 return ret;
104
105 return snd_pcm_hw_constraint_list(substream->runtime, 0,
106 SNDRV_PCM_HW_PARAM_CHANNELS,
107 &lochnagar_sc_chan_constraint);
108}
109
110static void lochnagar_sc_line_shutdown(struct snd_pcm_substream *substream,
111 struct snd_soc_dai *dai)
112{
113 struct snd_soc_component *comp = dai->component;
114 struct lochnagar_sc_priv *priv = snd_soc_component_get_drvdata(comp);
115
116 clk_disable_unprepare(priv->mclk);
117}
118
119static int lochnagar_sc_check_fmt(struct snd_soc_dai *dai, unsigned int fmt,
120 unsigned int tar)
121{
122 tar |= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
123
124 if ((fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) != tar)
125 return -EINVAL;
126
127 return 0;
128}
129
130static int lochnagar_sc_set_line_fmt(struct snd_soc_dai *dai, unsigned int fmt)
131{
132 return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBS_CFS);
133}
134
135static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt)
136{
137 return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBM_CFM);
138}
139
140static const struct snd_soc_dai_ops lochnagar_sc_line_ops = {
141 .startup = lochnagar_sc_line_startup,
142 .shutdown = lochnagar_sc_line_shutdown,
143 .set_fmt = lochnagar_sc_set_line_fmt,
144};
145
146static const struct snd_soc_dai_ops lochnagar_sc_usb_ops = {
147 .startup = lochnagar_sc_startup,
148 .set_fmt = lochnagar_sc_set_usb_fmt,
149};
150
151static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
152 {
153 .name = "lochnagar-line",
154 .playback = {
155 .stream_name = "AIF1 Playback",
156 .channels_min = 4,
157 .channels_max = 8,
158 .rates = SNDRV_PCM_RATE_KNOT,
159 .formats = SNDRV_PCM_FMTBIT_S32_LE,
160 },
161 .capture = {
162 .stream_name = "AIF1 Capture",
163 .channels_min = 4,
164 .channels_max = 8,
165 .rates = SNDRV_PCM_RATE_KNOT,
166 .formats = SNDRV_PCM_FMTBIT_S32_LE,
167 },
168 .ops = &lochnagar_sc_line_ops,
169 .symmetric_rates = true,
170 .symmetric_samplebits = true,
171 },
172 {
173 .name = "lochnagar-usb1",
174 .playback = {
175 .stream_name = "USB1 Playback",
176 .channels_min = 1,
177 .channels_max = 8,
178 .rates = SNDRV_PCM_RATE_KNOT,
179 .formats = SNDRV_PCM_FMTBIT_S32_LE,
180 },
181 .capture = {
182 .stream_name = "USB1 Capture",
183 .channels_min = 1,
184 .channels_max = 8,
185 .rates = SNDRV_PCM_RATE_KNOT,
186 .formats = SNDRV_PCM_FMTBIT_S32_LE,
187 },
188 .ops = &lochnagar_sc_usb_ops,
189 .symmetric_rates = true,
190 .symmetric_samplebits = true,
191 },
192 {
193 .name = "lochnagar-usb2",
194 .playback = {
195 .stream_name = "USB2 Playback",
196 .channels_min = 1,
197 .channels_max = 8,
198 .rates = SNDRV_PCM_RATE_KNOT,
199 .formats = SNDRV_PCM_FMTBIT_S32_LE,
200 },
201 .capture = {
202 .stream_name = "USB2 Capture",
203 .channels_min = 1,
204 .channels_max = 8,
205 .rates = SNDRV_PCM_RATE_KNOT,
206 .formats = SNDRV_PCM_FMTBIT_S32_LE,
207 },
208 .ops = &lochnagar_sc_usb_ops,
209 .symmetric_rates = true,
210 .symmetric_samplebits = true,
211 },
212};
213
214static const struct snd_soc_component_driver lochnagar_sc_driver = {
215 .non_legacy_dai_naming = 1,
216
217 .dapm_widgets = lochnagar_sc_widgets,
218 .num_dapm_widgets = ARRAY_SIZE(lochnagar_sc_widgets),
219 .dapm_routes = lochnagar_sc_routes,
220 .num_dapm_routes = ARRAY_SIZE(lochnagar_sc_routes),
221};
222
223static int lochnagar_sc_probe(struct platform_device *pdev)
224{
225 struct lochnagar_sc_priv *priv;
226 int ret;
227
228 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
229 if (!priv)
230 return -ENOMEM;
231
232 priv->mclk = devm_clk_get(&pdev->dev, "mclk");
233 if (IS_ERR(priv->mclk)) {
234 ret = PTR_ERR(priv->mclk);
235 dev_err(&pdev->dev, "Failed to get MCLK: %d\n", ret);
236 return ret;
237 }
238
239 platform_set_drvdata(pdev, priv);
240
241 return devm_snd_soc_register_component(&pdev->dev,
242 &lochnagar_sc_driver,
243 lochnagar_sc_dai,
244 ARRAY_SIZE(lochnagar_sc_dai));
245}
246
247static const struct of_device_id lochnagar_of_match[] = {
248 { .compatible = "cirrus,lochnagar2-soundcard" },
249 {}
250};
251MODULE_DEVICE_TABLE(of, lochnagar_of_match);
252
253static struct platform_driver lochnagar_sc_codec_driver = {
254 .driver = {
255 .name = "lochnagar-soundcard",
256 .of_match_table = of_match_ptr(lochnagar_of_match),
257 },
258
259 .probe = lochnagar_sc_probe,
260};
261module_platform_driver(lochnagar_sc_codec_driver);
262
263MODULE_DESCRIPTION("ASoC Lochnagar Sound Card Driver");
264MODULE_AUTHOR("Piotr Stankiewicz <piotrs@opensource.cirrus.com>");
265MODULE_LICENSE("GPL v2");
266MODULE_ALIAS("platform:lochnagar-soundcard");
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 30c242c38d99..7619ea31ab50 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -1194,14 +1194,14 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
1194 &max98090_right_rcv_mixer_controls[0], 1194 &max98090_right_rcv_mixer_controls[0],
1195 ARRAY_SIZE(max98090_right_rcv_mixer_controls)), 1195 ARRAY_SIZE(max98090_right_rcv_mixer_controls)),
1196 1196
1197 SND_SOC_DAPM_MUX("LINMOD Mux", M98090_REG_LOUTR_MIXER, 1197 SND_SOC_DAPM_MUX("LINMOD Mux", SND_SOC_NOPM, 0, 0,
1198 M98090_LINMOD_SHIFT, 0, &max98090_linmod_mux), 1198 &max98090_linmod_mux),
1199 1199
1200 SND_SOC_DAPM_MUX("MIXHPLSEL Mux", M98090_REG_HP_CONTROL, 1200 SND_SOC_DAPM_MUX("MIXHPLSEL Mux", SND_SOC_NOPM, 0, 0,
1201 M98090_MIXHPLSEL_SHIFT, 0, &max98090_mixhplsel_mux), 1201 &max98090_mixhplsel_mux),
1202 1202
1203 SND_SOC_DAPM_MUX("MIXHPRSEL Mux", M98090_REG_HP_CONTROL, 1203 SND_SOC_DAPM_MUX("MIXHPRSEL Mux", SND_SOC_NOPM, 0, 0,
1204 M98090_MIXHPRSEL_SHIFT, 0, &max98090_mixhprsel_mux), 1204 &max98090_mixhprsel_mux),
1205 1205
1206 SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE, 1206 SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE,
1207 M98090_HPLEN_SHIFT, 0, NULL, 0), 1207 M98090_HPLEN_SHIFT, 0, NULL, 0),
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index d469576b5a7b..d037a3e4d323 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -97,7 +97,10 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
97 SNDRV_PCM_FMTBIT_S32, 97 SNDRV_PCM_FMTBIT_S32,
98 .rates = SNDRV_PCM_RATE_8000 | 98 .rates = SNDRV_PCM_RATE_8000 |
99 SNDRV_PCM_RATE_16000 | 99 SNDRV_PCM_RATE_16000 |
100 SNDRV_PCM_RATE_32000 |
101 SNDRV_PCM_RATE_44100 |
100 SNDRV_PCM_RATE_48000 | 102 SNDRV_PCM_RATE_48000 |
103 SNDRV_PCM_RATE_88200 |
101 SNDRV_PCM_RATE_96000, 104 SNDRV_PCM_RATE_96000,
102 .rate_min = 8000, 105 .rate_min = 8000,
103 .rate_max = 96000, 106 .rate_max = 96000,
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index d4c4fee6d3d9..50b3fc5457ea 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -320,32 +320,6 @@ enum {
320#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB) 320#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB)
321#define DL_GAIN_REG_MASK 0x0f9f 321#define DL_GAIN_REG_MASK 0x0f9f
322 322
323static void lo_store_gain(struct mt6358_priv *priv)
324{
325 unsigned int reg;
326 unsigned int gain_l, gain_r;
327
328 regmap_read(priv->regmap, MT6358_ZCD_CON1, &reg);
329 gain_l = (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
330 gain_r = (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
331
332 priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] = gain_l;
333 priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] = gain_r;
334}
335
336static void hp_store_gain(struct mt6358_priv *priv)
337{
338 unsigned int reg;
339 unsigned int gain_l, gain_r;
340
341 regmap_read(priv->regmap, MT6358_ZCD_CON2, &reg);
342 gain_l = (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
343 gain_r = (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
344
345 priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = gain_l;
346 priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = gain_r;
347}
348
349static void hp_zcd_disable(struct mt6358_priv *priv) 323static void hp_zcd_disable(struct mt6358_priv *priv)
350{ 324{
351 regmap_write(priv->regmap, MT6358_ZCD_CON0, 0x0000); 325 regmap_write(priv->regmap, MT6358_ZCD_CON0, 0x0000);
@@ -405,10 +379,9 @@ static bool is_valid_hp_pga_idx(int reg_idx)
405 reg_idx == DL_GAIN_N_40DB; 379 reg_idx == DL_GAIN_N_40DB;
406} 380}
407 381
408static void headset_volume_ramp(struct mt6358_priv *priv, 382static void headset_volume_ramp(struct mt6358_priv *priv, int from, int to)
409 int from, int to)
410{ 383{
411 int offset = 0, count = 1, reg_idx; 384 int offset = 0, count = 0, reg_idx;
412 385
413 if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to)) 386 if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to))
414 dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n", 387 dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n",
@@ -422,7 +395,7 @@ static void headset_volume_ramp(struct mt6358_priv *priv,
422 else 395 else
423 offset = from - to; 396 offset = from - to;
424 397
425 while (offset > 0) { 398 while (offset >= 0) {
426 if (to > from) 399 if (to > from)
427 reg_idx = from + count; 400 reg_idx = from + count;
428 else 401 else
@@ -440,25 +413,76 @@ static void headset_volume_ramp(struct mt6358_priv *priv,
440 } 413 }
441} 414}
442 415
416static int mt6358_put_volsw(struct snd_kcontrol *kcontrol,
417 struct snd_ctl_elem_value *ucontrol)
418{
419 struct snd_soc_component *component =
420 snd_soc_kcontrol_component(kcontrol);
421 struct mt6358_priv *priv = snd_soc_component_get_drvdata(component);
422 struct soc_mixer_control *mc =
423 (struct soc_mixer_control *)kcontrol->private_value;
424 unsigned int reg;
425 int ret;
426
427 ret = snd_soc_put_volsw(kcontrol, ucontrol);
428 if (ret < 0)
429 return ret;
430
431 switch (mc->reg) {
432 case MT6358_ZCD_CON2:
433 regmap_read(priv->regmap, MT6358_ZCD_CON2, &reg);
434 priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
435 (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
436 priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
437 (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
438 break;
439 case MT6358_ZCD_CON1:
440 regmap_read(priv->regmap, MT6358_ZCD_CON1, &reg);
441 priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] =
442 (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
443 priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] =
444 (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
445 break;
446 case MT6358_ZCD_CON3:
447 regmap_read(priv->regmap, MT6358_ZCD_CON3, &reg);
448 priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL] =
449 (reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
450 priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTR] =
451 (reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
452 break;
453 case MT6358_AUDENC_ANA_CON0:
454 case MT6358_AUDENC_ANA_CON1:
455 regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON0, &reg);
456 priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] =
457 (reg >> RG_AUDPREAMPLGAIN_SFT) & RG_AUDPREAMPLGAIN_MASK;
458 regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON1, &reg);
459 priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] =
460 (reg >> RG_AUDPREAMPRGAIN_SFT) & RG_AUDPREAMPRGAIN_MASK;
461 break;
462 }
463
464 return ret;
465}
466
443static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); 467static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
444static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0); 468static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
445 469
446static const struct snd_kcontrol_new mt6358_snd_controls[] = { 470static const struct snd_kcontrol_new mt6358_snd_controls[] = {
447 /* dl pga gain */ 471 /* dl pga gain */
448 SOC_DOUBLE_TLV("Headphone Volume", 472 SOC_DOUBLE_EXT_TLV("Headphone Volume",
449 MT6358_ZCD_CON2, 0, 7, 0x12, 1, 473 MT6358_ZCD_CON2, 0, 7, 0x12, 1,
450 playback_tlv), 474 snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
451 SOC_DOUBLE_TLV("Lineout Volume", 475 SOC_DOUBLE_EXT_TLV("Lineout Volume",
452 MT6358_ZCD_CON1, 0, 7, 0x12, 1, 476 MT6358_ZCD_CON1, 0, 7, 0x12, 1,
453 playback_tlv), 477 snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
454 SOC_SINGLE_TLV("Handset Volume", 478 SOC_SINGLE_EXT_TLV("Handset Volume",
455 MT6358_ZCD_CON3, 0, 0x12, 1, 479 MT6358_ZCD_CON3, 0, 0x12, 1,
456 playback_tlv), 480 snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
457 /* ul pga gain */ 481 /* ul pga gain */
458 SOC_DOUBLE_R_TLV("PGA Volume", 482 SOC_DOUBLE_R_EXT_TLV("PGA Volume",
459 MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1, 483 MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1,
460 8, 4, 0, 484 8, 4, 0,
461 pga_tlv), 485 snd_soc_get_volsw, mt6358_put_volsw, pga_tlv),
462}; 486};
463 487
464/* MUX */ 488/* MUX */
@@ -832,8 +856,6 @@ static int mtk_hp_enable(struct mt6358_priv *priv)
832 /* Reduce ESD resistance of AU_REFN */ 856 /* Reduce ESD resistance of AU_REFN */
833 regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); 857 regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
834 858
835 /* save target gain to restore after hardware open complete */
836 hp_store_gain(priv);
837 /* Set HPR/HPL gain as minimum (~ -40dB) */ 859 /* Set HPR/HPL gain as minimum (~ -40dB) */
838 regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG); 860 regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG);
839 861
@@ -1043,8 +1065,6 @@ static int mtk_hp_spk_enable(struct mt6358_priv *priv)
1043 /* Reduce ESD resistance of AU_REFN */ 1065 /* Reduce ESD resistance of AU_REFN */
1044 regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); 1066 regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
1045 1067
1046 /* save target gain to restore after hardware open complete */
1047 hp_store_gain(priv);
1048 /* Set HPR/HPL gain to -10dB */ 1068 /* Set HPR/HPL gain to -10dB */
1049 regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG); 1069 regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
1050 1070
@@ -1104,7 +1124,6 @@ static int mtk_hp_spk_enable(struct mt6358_priv *priv)
1104 hp_main_output_ramp(priv, true); 1124 hp_main_output_ramp(priv, true);
1105 1125
1106 /* Set LO gain as minimum (~ -40dB) */ 1126 /* Set LO gain as minimum (~ -40dB) */
1107 lo_store_gain(priv);
1108 regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG); 1127 regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG);
1109 /* apply volume setting */ 1128 /* apply volume setting */
1110 headset_volume_ramp(priv, 1129 headset_volume_ramp(priv,
@@ -1740,6 +1759,21 @@ static void mt6358_dmic_disable(struct mt6358_priv *priv)
1740 regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000); 1759 regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000);
1741} 1760}
1742 1761
1762static void mt6358_restore_pga(struct mt6358_priv *priv)
1763{
1764 unsigned int gain_l, gain_r;
1765
1766 gain_l = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
1767 gain_r = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
1768
1769 regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0,
1770 RG_AUDPREAMPLGAIN_MASK_SFT,
1771 gain_l << RG_AUDPREAMPLGAIN_SFT);
1772 regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1,
1773 RG_AUDPREAMPRGAIN_MASK_SFT,
1774 gain_r << RG_AUDPREAMPRGAIN_SFT);
1775}
1776
1743static int mt_mic_type_event(struct snd_soc_dapm_widget *w, 1777static int mt_mic_type_event(struct snd_soc_dapm_widget *w,
1744 struct snd_kcontrol *kcontrol, 1778 struct snd_kcontrol *kcontrol,
1745 int event) 1779 int event)
@@ -1764,6 +1798,7 @@ static int mt_mic_type_event(struct snd_soc_dapm_widget *w,
1764 mt6358_amic_enable(priv); 1798 mt6358_amic_enable(priv);
1765 break; 1799 break;
1766 } 1800 }
1801 mt6358_restore_pga(priv);
1767 1802
1768 break; 1803 break;
1769 case SND_SOC_DAPM_POST_PMD: 1804 case SND_SOC_DAPM_POST_PMD:
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index 645aa0794123..dd82c65cfa7f 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -493,7 +493,7 @@ static int nau8810_set_sysclk(struct snd_soc_dai *dai,
493 return 0; 493 return 0;
494} 494}
495 495
496static int nau88l0_calc_pll(unsigned int pll_in, 496static int nau8810_calc_pll(unsigned int pll_in,
497 unsigned int fs, struct nau8810_pll *pll_param) 497 unsigned int fs, struct nau8810_pll *pll_param)
498{ 498{
499 u64 f2, f2_max, pll_ratio; 499 u64 f2, f2_max, pll_ratio;
@@ -505,7 +505,8 @@ static int nau88l0_calc_pll(unsigned int pll_in,
505 f2_max = 0; 505 f2_max = 0;
506 scal_sel = ARRAY_SIZE(nau8810_mclk_scaler); 506 scal_sel = ARRAY_SIZE(nau8810_mclk_scaler);
507 for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { 507 for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
508 f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10; 508 f2 = 256ULL * fs * 4 * nau8810_mclk_scaler[i];
509 f2 = div_u64(f2, 10);
509 if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && 510 if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX &&
510 f2_max < f2) { 511 f2_max < f2) {
511 f2_max = f2; 512 f2_max = f2;
@@ -542,7 +543,7 @@ static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
542 int ret, fs; 543 int ret, fs;
543 544
544 fs = freq_out / 256; 545 fs = freq_out / 256;
545 ret = nau88l0_calc_pll(freq_in, fs, pll_param); 546 ret = nau8810_calc_pll(freq_in, fs, pll_param);
546 if (ret < 0) { 547 if (ret < 0) {
547 dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in); 548 dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in);
548 return ret; 549 return ret;
@@ -667,6 +668,24 @@ static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream,
667 struct snd_soc_component *component = dai->component; 668 struct snd_soc_component *component = dai->component;
668 struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component); 669 struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
669 int val_len = 0, val_rate = 0, ret = 0; 670 int val_len = 0, val_rate = 0, ret = 0;
671 unsigned int ctrl_val, bclk_fs, bclk_div;
672
673 /* Select BCLK configuration if the codec as master. */
674 regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &ctrl_val);
675 if (ctrl_val & NAU8810_CLKIO_MASTER) {
676 /* get the bclk and fs ratio */
677 bclk_fs = snd_soc_params_to_bclk(params) / params_rate(params);
678 if (bclk_fs <= 32)
679 bclk_div = NAU8810_BCLKDIV_8;
680 else if (bclk_fs <= 64)
681 bclk_div = NAU8810_BCLKDIV_4;
682 else if (bclk_fs <= 128)
683 bclk_div = NAU8810_BCLKDIV_2;
684 else
685 return -EINVAL;
686 regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
687 NAU8810_BCLKSEL_MASK, bclk_div);
688 }
670 689
671 switch (params_width(params)) { 690 switch (params_width(params)) {
672 case 16: 691 case 16:
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index 08d3fe192e65..e0d5839fe1a7 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -457,13 +457,16 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
457 if (chan > 2) { 457 if (chan > 2) {
458 switch (fmt) { 458 switch (fmt) {
459 case PCM3168A_FMT_I2S: 459 case PCM3168A_FMT_I2S:
460 case PCM3168A_FMT_DSP_A:
460 fmt = PCM3168A_FMT_I2S_TDM; 461 fmt = PCM3168A_FMT_I2S_TDM;
461 break; 462 break;
462 case PCM3168A_FMT_LEFT_J: 463 case PCM3168A_FMT_LEFT_J:
464 case PCM3168A_FMT_DSP_B:
463 fmt = PCM3168A_FMT_LEFT_J_TDM; 465 fmt = PCM3168A_FMT_LEFT_J_TDM;
464 break; 466 break;
465 default: 467 default:
466 dev_err(component->dev, "TDM is supported under I2S/Left_J only\n"); 468 dev_err(component->dev,
469 "TDM is supported under DSP/I2S/Left_J only\n");
467 return -EINVAL; 470 return -EINVAL;
468 } 471 }
469 } 472 }
@@ -526,6 +529,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
526 break; 529 break;
527 case PCM3168A_FMT_LEFT_J: 530 case PCM3168A_FMT_LEFT_J:
528 case PCM3168A_FMT_I2S: 531 case PCM3168A_FMT_I2S:
532 case PCM3168A_FMT_DSP_A:
533 case PCM3168A_FMT_DSP_B:
529 sample_min = 24; 534 sample_min = 24;
530 channel_max = channel_maxs[tx]; 535 channel_max = channel_maxs[tx];
531 break; 536 break;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 9a0751978090..cd45d41df4ec 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -3419,6 +3419,9 @@ static int rt5645_probe(struct snd_soc_component *component)
3419 RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s), 3419 RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s),
3420 GFP_KERNEL); 3420 GFP_KERNEL);
3421 3421
3422 if (!rt5645->eq_param)
3423 return -ENOMEM;
3424
3422 return 0; 3425 return 0;
3423} 3426}
3424 3427
@@ -3631,6 +3634,11 @@ static const struct rt5645_platform_data jd_mode3_platform_data = {
3631 .jd_mode = 3, 3634 .jd_mode = 3,
3632}; 3635};
3633 3636
3637static const struct rt5645_platform_data lattepanda_board_platform_data = {
3638 .jd_mode = 2,
3639 .inv_jd1_1 = true
3640};
3641
3634static const struct dmi_system_id dmi_platform_data[] = { 3642static const struct dmi_system_id dmi_platform_data[] = {
3635 { 3643 {
3636 .ident = "Chrome Buddy", 3644 .ident = "Chrome Buddy",
@@ -3728,6 +3736,15 @@ static const struct dmi_system_id dmi_platform_data[] = {
3728 }, 3736 },
3729 .driver_data = (void *)&intel_braswell_platform_data, 3737 .driver_data = (void *)&intel_braswell_platform_data,
3730 }, 3738 },
3739 {
3740 .ident = "LattePanda board",
3741 .matches = {
3742 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
3743 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
3744 DMI_EXACT_MATCH(DMI_BOARD_VERSION, "Default string"),
3745 },
3746 .driver_data = (void *)&lattepanda_board_platform_data,
3747 },
3731 { } 3748 { }
3732}; 3749};
3733 3750
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 29b2d60076b0..cb8252ff31cb 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1645,7 +1645,10 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
1645 break; 1645 break;
1646 } 1646 }
1647 1647
1648 return val == 0; 1648 if (rt5651->jd_active_high)
1649 return val != 0;
1650 else
1651 return val == 0;
1649} 1652}
1650 1653
1651/* Jack detect and button-press timings */ 1654/* Jack detect and button-press timings */
@@ -1868,20 +1871,47 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component,
1868 case RT5651_JD1_1: 1871 case RT5651_JD1_1:
1869 snd_soc_component_update_bits(component, RT5651_JD_CTRL2, 1872 snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
1870 RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); 1873 RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1);
1871 snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, 1874 /* active-low is normal, set inv flag for active-high */
1872 RT5651_JD1_1_IRQ_EN, RT5651_JD1_1_IRQ_EN); 1875 if (rt5651->jd_active_high)
1876 snd_soc_component_update_bits(component,
1877 RT5651_IRQ_CTRL1,
1878 RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV,
1879 RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV);
1880 else
1881 snd_soc_component_update_bits(component,
1882 RT5651_IRQ_CTRL1,
1883 RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV,
1884 RT5651_JD1_1_IRQ_EN);
1873 break; 1885 break;
1874 case RT5651_JD1_2: 1886 case RT5651_JD1_2:
1875 snd_soc_component_update_bits(component, RT5651_JD_CTRL2, 1887 snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
1876 RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_2); 1888 RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_2);
1877 snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, 1889 /* active-low is normal, set inv flag for active-high */
1878 RT5651_JD1_2_IRQ_EN, RT5651_JD1_2_IRQ_EN); 1890 if (rt5651->jd_active_high)
1891 snd_soc_component_update_bits(component,
1892 RT5651_IRQ_CTRL1,
1893 RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV,
1894 RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV);
1895 else
1896 snd_soc_component_update_bits(component,
1897 RT5651_IRQ_CTRL1,
1898 RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV,
1899 RT5651_JD1_2_IRQ_EN);
1879 break; 1900 break;
1880 case RT5651_JD2: 1901 case RT5651_JD2:
1881 snd_soc_component_update_bits(component, RT5651_JD_CTRL2, 1902 snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
1882 RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD2); 1903 RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD2);
1883 snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, 1904 /* active-low is normal, set inv flag for active-high */
1884 RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); 1905 if (rt5651->jd_active_high)
1906 snd_soc_component_update_bits(component,
1907 RT5651_IRQ_CTRL1,
1908 RT5651_JD2_IRQ_EN | RT5651_JD2_INV,
1909 RT5651_JD2_IRQ_EN | RT5651_JD2_INV);
1910 else
1911 snd_soc_component_update_bits(component,
1912 RT5651_IRQ_CTRL1,
1913 RT5651_JD2_IRQ_EN | RT5651_JD2_INV,
1914 RT5651_JD2_IRQ_EN);
1885 break; 1915 break;
1886 default: 1916 default:
1887 dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); 1917 dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
@@ -1986,6 +2016,9 @@ static void rt5651_apply_properties(struct snd_soc_component *component)
1986 "realtek,jack-detect-source", &val) == 0) 2016 "realtek,jack-detect-source", &val) == 0)
1987 rt5651->jd_src = val; 2017 rt5651->jd_src = val;
1988 2018
2019 if (device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
2020 rt5651->jd_active_high = true;
2021
1989 /* 2022 /*
1990 * Testing on various boards has shown that good defaults for the OVCD 2023 * Testing on various boards has shown that good defaults for the OVCD
1991 * threshold and scale-factor are 2000µA and 0.75. For an effective 2024 * threshold and scale-factor are 2000µA and 0.75. For an effective
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
index 41fcb8b5eb40..05b0f6f8b95d 100644
--- a/sound/soc/codecs/rt5651.h
+++ b/sound/soc/codecs/rt5651.h
@@ -2083,6 +2083,7 @@ struct rt5651_priv {
2083 int release_count; 2083 int release_count;
2084 int poll_count; 2084 int poll_count;
2085 unsigned int jd_src; 2085 unsigned int jd_src;
2086 bool jd_active_high;
2086 unsigned int ovcd_th; 2087 unsigned int ovcd_th;
2087 unsigned int ovcd_sf; 2088 unsigned int ovcd_sf;
2088 2089
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 84501c2020c7..84b6bd8b50e1 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -25,6 +25,7 @@
25#include <linux/sysfs.h> 25#include <linux/sysfs.h>
26#include <linux/clk.h> 26#include <linux/clk.h>
27#include <linux/firmware.h> 27#include <linux/firmware.h>
28#include <linux/acpi.h>
28 29
29#include "rt5677-spi.h" 30#include "rt5677-spi.h"
30 31
@@ -57,13 +58,15 @@ static DEFINE_MUTEX(spi_mutex);
57 * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes 58 * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes
58 * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes 59 * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes
59 * 60 *
60 * For example, reading 260 bytes at 0x60030002 uses the following commands: 61 * Note:
61 * 0x60030002 RT5677_SPI_READ_16 2 bytes 62 * 16 Bit writes and reads are restricted to the address range
63 * 0x18020000 ~ 0x18021000
64 *
65 * For example, reading 256 bytes at 0x60030004 uses the following commands:
62 * 0x60030004 RT5677_SPI_READ_32 4 bytes 66 * 0x60030004 RT5677_SPI_READ_32 4 bytes
63 * 0x60030008 RT5677_SPI_READ_BURST 240 bytes 67 * 0x60030008 RT5677_SPI_READ_BURST 240 bytes
64 * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes 68 * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes
65 * 0x60030100 RT5677_SPI_READ_32 4 bytes 69 * 0x60030100 RT5677_SPI_READ_32 4 bytes
66 * 0x60030104 RT5677_SPI_READ_16 2 bytes
67 * 70 *
68 * Input: 71 * Input:
69 * @read: true for read commands; false for write commands 72 * @read: true for read commands; false for write commands
@@ -78,15 +81,13 @@ static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len)
78{ 81{
79 u8 cmd; 82 u8 cmd;
80 83
81 if (align == 2 || align == 6 || remain == 2) { 84 if (align == 4 || remain <= 4) {
82 cmd = RT5677_SPI_READ_16;
83 *len = 2;
84 } else if (align == 4 || remain <= 6) {
85 cmd = RT5677_SPI_READ_32; 85 cmd = RT5677_SPI_READ_32;
86 *len = 4; 86 *len = 4;
87 } else { 87 } else {
88 cmd = RT5677_SPI_READ_BURST; 88 cmd = RT5677_SPI_READ_BURST;
89 *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); 89 *len = (((remain - 1) >> 3) + 1) << 3;
90 *len = min_t(u32, *len, RT5677_SPI_BURST_LEN);
90 } 91 }
91 return read ? cmd : cmd + 1; 92 return read ? cmd : cmd + 1;
92} 93}
@@ -107,7 +108,7 @@ static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen)
107 } 108 }
108} 109}
109 110
110/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ 111/* Read DSP address space using SPI. addr and len have to be 4-byte aligned. */
111int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) 112int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
112{ 113{
113 u32 offset; 114 u32 offset;
@@ -123,7 +124,7 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
123 if (!g_spi) 124 if (!g_spi)
124 return -ENODEV; 125 return -ENODEV;
125 126
126 if ((addr & 1) || (len & 1)) { 127 if ((addr & 3) || (len & 3)) {
127 dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); 128 dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len);
128 return -EACCES; 129 return -EACCES;
129 } 130 }
@@ -158,13 +159,13 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
158} 159}
159EXPORT_SYMBOL_GPL(rt5677_spi_read); 160EXPORT_SYMBOL_GPL(rt5677_spi_read);
160 161
161/* Write DSP address space using SPI. addr has to be 2-byte aligned. 162/* Write DSP address space using SPI. addr has to be 4-byte aligned.
162 * If len is not 2-byte aligned, an extra byte of zero is written at the end 163 * If len is not 4-byte aligned, then extra zeros are written at the end
163 * as padding. 164 * as padding.
164 */ 165 */
165int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) 166int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
166{ 167{
167 u32 offset, len_with_pad = len; 168 u32 offset;
168 int status = 0; 169 int status = 0;
169 struct spi_transfer t; 170 struct spi_transfer t;
170 struct spi_message m; 171 struct spi_message m;
@@ -177,22 +178,19 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
177 if (!g_spi) 178 if (!g_spi)
178 return -ENODEV; 179 return -ENODEV;
179 180
180 if (addr & 1) { 181 if (addr & 3) {
181 dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); 182 dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len);
182 return -EACCES; 183 return -EACCES;
183 } 184 }
184 185
185 if (len & 1)
186 len_with_pad = len + 1;
187
188 memset(&t, 0, sizeof(t)); 186 memset(&t, 0, sizeof(t));
189 t.tx_buf = buf; 187 t.tx_buf = buf;
190 t.speed_hz = RT5677_SPI_FREQ; 188 t.speed_hz = RT5677_SPI_FREQ;
191 spi_message_init_with_transfers(&m, &t, 1); 189 spi_message_init_with_transfers(&m, &t, 1);
192 190
193 for (offset = 0; offset < len_with_pad;) { 191 for (offset = 0; offset < len;) {
194 spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, 192 spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7,
195 len_with_pad - offset, &t.len); 193 len - offset, &t.len);
196 194
197 /* Construct SPI message header */ 195 /* Construct SPI message header */
198 buf[0] = spi_cmd; 196 buf[0] = spi_cmd;
@@ -226,9 +224,16 @@ static int rt5677_spi_probe(struct spi_device *spi)
226 return 0; 224 return 0;
227} 225}
228 226
227static const struct acpi_device_id rt5677_spi_acpi_id[] = {
228 { "RT5677AA", 0 },
229 { }
230};
231MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id);
232
229static struct spi_driver rt5677_spi_driver = { 233static struct spi_driver rt5677_spi_driver = {
230 .driver = { 234 .driver = {
231 .name = "rt5677", 235 .name = "rt5677",
236 .acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id),
232 }, 237 },
233 .probe = rt5677_spi_probe, 238 .probe = rt5677_spi_probe,
234}; 239};
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 86a7fa31c294..505fb3d7b1c5 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -2588,6 +2588,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
2588 2588
2589 rt5682_reset(rt5682->regmap); 2589 rt5682_reset(rt5682->regmap);
2590 2590
2591 mutex_init(&rt5682->calibrate_mutex);
2591 rt5682_calibrate(rt5682); 2592 rt5682_calibrate(rt5682);
2592 2593
2593 ret = regmap_multi_reg_write(rt5682->regmap, patch_list, 2594 ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
@@ -2654,7 +2655,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
2654 INIT_DELAYED_WORK(&rt5682->jd_check_work, 2655 INIT_DELAYED_WORK(&rt5682->jd_check_work,
2655 rt5682_jd_check_handler); 2656 rt5682_jd_check_handler);
2656 2657
2657 mutex_init(&rt5682->calibrate_mutex);
2658 2658
2659 if (i2c->irq) { 2659 if (i2c->irq) {
2660 ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, 2660 ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c
index c07e8a80b4b7..351aa55c384e 100644
--- a/sound/soc/codecs/simple-amplifier.c
+++ b/sound/soc/codecs/simple-amplifier.c
@@ -89,7 +89,8 @@ static int simple_amp_probe(struct platform_device *pdev)
89 return -ENOMEM; 89 return -ENOMEM;
90 platform_set_drvdata(pdev, priv); 90 platform_set_drvdata(pdev, priv);
91 91
92 priv->gpiod_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 92 priv->gpiod_enable = devm_gpiod_get_optional(dev, "enable",
93 GPIOD_OUT_LOW);
93 if (IS_ERR(priv->gpiod_enable)) { 94 if (IS_ERR(priv->gpiod_enable)) {
94 err = PTR_ERR(priv->gpiod_enable); 95 err = PTR_ERR(priv->gpiod_enable);
95 if (err != -EPROBE_DEFER) 96 if (err != -EPROBE_DEFER)
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index e424499a8450..e0af21050078 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -461,9 +461,6 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
461 struct sirf_audio_codec *sirf_audio_codec; 461 struct sirf_audio_codec *sirf_audio_codec;
462 void __iomem *base; 462 void __iomem *base;
463 struct resource *mem_res; 463 struct resource *mem_res;
464 const struct of_device_id *match;
465
466 match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
467 464
468 sirf_audio_codec = devm_kzalloc(&pdev->dev, 465 sirf_audio_codec = devm_kzalloc(&pdev->dev,
469 sizeof(struct sirf_audio_codec), GFP_KERNEL); 466 sizeof(struct sirf_audio_codec), GFP_KERNEL);
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index c544a1e35f5e..9b37e98da0db 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -25,6 +25,7 @@
25#include <linux/of_gpio.h> 25#include <linux/of_gpio.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <sound/core.h> 27#include <sound/core.h>
28#include <sound/jack.h>
28#include <sound/pcm.h> 29#include <sound/pcm.h>
29#include <sound/pcm_params.h> 30#include <sound/pcm_params.h>
30#include <sound/soc.h> 31#include <sound/soc.h>
@@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg)
89 case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */ 90 case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
90 case AIC31XX_INTRDACFLAG2: 91 case AIC31XX_INTRDACFLAG2:
91 case AIC31XX_INTRADCFLAG2: 92 case AIC31XX_INTRADCFLAG2:
93 case AIC31XX_HSDETECT:
92 return true; 94 return true;
93 } 95 }
94 return false; 96 return false;
@@ -163,6 +165,7 @@ struct aic31xx_priv {
163 struct aic31xx_pdata pdata; 165 struct aic31xx_pdata pdata;
164 struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; 166 struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
165 struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; 167 struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
168 struct snd_soc_jack *jack;
166 unsigned int sysclk; 169 unsigned int sysclk;
167 u8 p_div; 170 u8 p_div;
168 int rate_div_line; 171 int rate_div_line;
@@ -1261,6 +1264,20 @@ static int aic31xx_set_bias_level(struct snd_soc_component *component,
1261 return 0; 1264 return 0;
1262} 1265}
1263 1266
1267static int aic31xx_set_jack(struct snd_soc_component *component,
1268 struct snd_soc_jack *jack, void *data)
1269{
1270 struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
1271
1272 aic31xx->jack = jack;
1273
1274 /* Enable/Disable jack detection */
1275 regmap_write(aic31xx->regmap, AIC31XX_HSDETECT,
1276 jack ? AIC31XX_HSD_ENABLE : 0);
1277
1278 return 0;
1279}
1280
1264static int aic31xx_codec_probe(struct snd_soc_component *component) 1281static int aic31xx_codec_probe(struct snd_soc_component *component)
1265{ 1282{
1266 struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); 1283 struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
@@ -1301,6 +1318,7 @@ static int aic31xx_codec_probe(struct snd_soc_component *component)
1301 1318
1302static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { 1319static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
1303 .probe = aic31xx_codec_probe, 1320 .probe = aic31xx_codec_probe,
1321 .set_jack = aic31xx_set_jack,
1304 .set_bias_level = aic31xx_set_bias_level, 1322 .set_bias_level = aic31xx_set_bias_level,
1305 .controls = common31xx_snd_controls, 1323 .controls = common31xx_snd_controls,
1306 .num_controls = ARRAY_SIZE(common31xx_snd_controls), 1324 .num_controls = ARRAY_SIZE(common31xx_snd_controls),
@@ -1405,8 +1423,47 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
1405 dev_err(dev, "Short circuit on Left output is detected\n"); 1423 dev_err(dev, "Short circuit on Left output is detected\n");
1406 if (value & AIC31XX_HPRSCDETECT) 1424 if (value & AIC31XX_HPRSCDETECT)
1407 dev_err(dev, "Short circuit on Right output is detected\n"); 1425 dev_err(dev, "Short circuit on Right output is detected\n");
1426 if (value & (AIC31XX_HSPLUG | AIC31XX_BUTTONPRESS)) {
1427 unsigned int val;
1428 int status = 0;
1429
1430 ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG2,
1431 &val);
1432 if (ret) {
1433 dev_err(dev, "Failed to read interrupt mask: %d\n",
1434 ret);
1435 goto exit;
1436 }
1437
1438 if (val & AIC31XX_BUTTONPRESS)
1439 status |= SND_JACK_BTN_0;
1440
1441 ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &val);
1442 if (ret) {
1443 dev_err(dev, "Failed to read headset type: %d\n", ret);
1444 goto exit;
1445 }
1446
1447 switch ((val & AIC31XX_HSD_TYPE_MASK) >>
1448 AIC31XX_HSD_TYPE_SHIFT) {
1449 case AIC31XX_HSD_HP:
1450 status |= SND_JACK_HEADPHONE;
1451 break;
1452 case AIC31XX_HSD_HS:
1453 status |= SND_JACK_HEADSET;
1454 break;
1455 default:
1456 break;
1457 }
1458
1459 if (aic31xx->jack)
1460 snd_soc_jack_report(aic31xx->jack, status,
1461 AIC31XX_JACK_MASK);
1462 }
1408 if (value & ~(AIC31XX_HPLSCDETECT | 1463 if (value & ~(AIC31XX_HPLSCDETECT |
1409 AIC31XX_HPRSCDETECT)) 1464 AIC31XX_HPRSCDETECT |
1465 AIC31XX_HSPLUG |
1466 AIC31XX_BUTTONPRESS))
1410 dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value); 1467 dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
1411 1468
1412read_overflow: 1469read_overflow:
@@ -1518,6 +1575,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
1518 AIC31XX_GPIO1_FUNC_SHIFT); 1575 AIC31XX_GPIO1_FUNC_SHIFT);
1519 1576
1520 regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, 1577 regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
1578 AIC31XX_HSPLUGDET |
1579 AIC31XX_BUTTONPRESSDET |
1521 AIC31XX_SC | 1580 AIC31XX_SC |
1522 AIC31XX_ENGINE); 1581 AIC31XX_ENGINE);
1523 1582
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
index 2636f2c6bc79..cb024955c978 100644
--- a/sound/soc/codecs/tlv320aic31xx.h
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -20,6 +20,10 @@
20#define AIC31XX_MINIDSP_BIT BIT(2) 20#define AIC31XX_MINIDSP_BIT BIT(2)
21#define DAC31XX_BIT BIT(3) 21#define DAC31XX_BIT BIT(3)
22 22
23#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \
24 SND_JACK_HEADSET | \
25 SND_JACK_BTN_0)
26
23enum aic31xx_type { 27enum aic31xx_type {
24 AIC3100 = 0, 28 AIC3100 = 0,
25 AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, 29 AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
@@ -220,6 +224,14 @@ struct aic31xx_pdata {
220/* AIC31XX_DACMUTE */ 224/* AIC31XX_DACMUTE */
221#define AIC31XX_DACMUTE_MASK GENMASK(3, 2) 225#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
222 226
227/* AIC31XX_HSDETECT */
228#define AIC31XX_HSD_ENABLE BIT(7)
229#define AIC31XX_HSD_TYPE_MASK GENMASK(6, 5)
230#define AIC31XX_HSD_TYPE_SHIFT 5
231#define AIC31XX_HSD_NONE 0x00
232#define AIC31XX_HSD_HP 0x01
233#define AIC31XX_HSD_HS 0x03
234
223/* AIC31XX_MICBIAS */ 235/* AIC31XX_MICBIAS */
224#define AIC31XX_MICBIAS_MASK GENMASK(1, 0) 236#define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
225#define AIC31XX_MICBIAS_SHIFT 0 237#define AIC31XX_MICBIAS_SHIFT 0
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
new file mode 100644
index 000000000000..156c153c12ab
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -0,0 +1,483 @@
1/* SPDX-License-Identifier: GPL-2.0
2 *
3 * Clock Tree for the Texas Instruments TLV320AIC32x4
4 *
5 * Copyright 2019 Annaliese McDermond
6 *
7 * Author: Annaliese McDermond <nh6z@nh6z.net>
8 */
9
10#include <linux/clk-provider.h>
11#include <linux/clkdev.h>
12#include <linux/regmap.h>
13#include <linux/device.h>
14
15#include "tlv320aic32x4.h"
16
17#define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
18struct clk_aic32x4 {
19 struct clk_hw hw;
20 struct device *dev;
21 struct regmap *regmap;
22 unsigned int reg;
23};
24
25/*
26 * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
27 * @p: Divider
28 * @r: first multiplier
29 * @j: integer part of second multiplier
30 * @d: decimal part of second multiplier
31 */
32struct clk_aic32x4_pll_muldiv {
33 u8 p;
34 u16 r;
35 u8 j;
36 u16 d;
37};
38
39struct aic32x4_clkdesc {
40 const char *name;
41 const char * const *parent_names;
42 unsigned int num_parents;
43 const struct clk_ops *ops;
44 unsigned int reg;
45};
46
47static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
48{
49 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
50
51 return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
52 AIC32X4_PLLEN, AIC32X4_PLLEN);
53}
54
55static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
56{
57 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
58
59 regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
60 AIC32X4_PLLEN, 0);
61}
62
63static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
64{
65 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
66
67 unsigned int val;
68 int ret;
69
70 ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
71 if (ret < 0)
72 return ret;
73
74 return !!(val & AIC32X4_PLLEN);
75}
76
77static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
78 struct clk_aic32x4_pll_muldiv *settings)
79{
80 /* Change to use regmap_bulk_read? */
81 unsigned int val;
82 int ret;
83
84 ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
85 if (ret < 0)
86 return ret;
87 settings->r = val & AIC32X4_PLL_R_MASK;
88 settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
89
90 ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
91 if (ret < 0)
92 return ret;
93 settings->j = val;
94
95 ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
96 if (ret < 0)
97 return ret;
98 settings->d = val << 8;
99
100 ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB, &val);
101 if (ret < 0)
102 return ret;
103 settings->d |= val;
104
105 return 0;
106}
107
108static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
109 struct clk_aic32x4_pll_muldiv *settings)
110{
111 int ret;
112 /* Change to use regmap_bulk_write for some if not all? */
113
114 ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
115 AIC32X4_PLL_R_MASK, settings->r);
116 if (ret < 0)
117 return ret;
118
119 ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
120 AIC32X4_PLL_P_MASK,
121 settings->p << AIC32X4_PLL_P_SHIFT);
122 if (ret < 0)
123 return ret;
124
125 ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
126 if (ret < 0)
127 return ret;
128
129 ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
130 if (ret < 0)
131 return ret;
132 ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
133 if (ret < 0)
134 return ret;
135
136 return 0;
137}
138
139static unsigned long clk_aic32x4_pll_calc_rate(
140 struct clk_aic32x4_pll_muldiv *settings,
141 unsigned long parent_rate)
142{
143 u64 rate;
144 /*
145 * We scale j by 10000 to account for the decimal part of P and divide
146 * it back out later.
147 */
148 rate = (u64) parent_rate * settings->r *
149 ((settings->j * 10000) + settings->d);
150
151 return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
152}
153
154static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
155 unsigned long rate, unsigned long parent_rate)
156{
157 u64 multiplier;
158
159 settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
160 if (settings->p > 8)
161 return -1;
162
163 /*
164 * We scale this figure by 10000 so that we can get the decimal part
165 * of the multiplier. This is because we can't do floating point
166 * math in the kernel.
167 */
168 multiplier = (u64) rate * settings->p * 10000;
169 do_div(multiplier, parent_rate);
170
171 /*
172 * J can't be over 64, so R can scale this.
173 * R can't be greater than 4.
174 */
175 settings->r = ((u32) multiplier / 640000) + 1;
176 if (settings->r > 4)
177 return -1;
178 do_div(multiplier, settings->r);
179
180 /*
181 * J can't be < 1.
182 */
183 if (multiplier < 10000)
184 return -1;
185
186 /* Figure out the integer part, J, and the fractional part, D. */
187 settings->j = (u32) multiplier / 10000;
188 settings->d = (u32) multiplier % 10000;
189
190 return 0;
191}
192
193static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
194 unsigned long parent_rate)
195{
196 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
197 struct clk_aic32x4_pll_muldiv settings;
198 int ret;
199
200 ret = clk_aic32x4_pll_get_muldiv(pll, &settings);
201 if (ret < 0)
202 return 0;
203
204 return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
205}
206
207static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
208 unsigned long rate,
209 unsigned long *parent_rate)
210{
211 struct clk_aic32x4_pll_muldiv settings;
212 int ret;
213
214 ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
215 if (ret < 0)
216 return 0;
217
218 return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
219}
220
221static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
222 unsigned long rate,
223 unsigned long parent_rate)
224{
225 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
226 struct clk_aic32x4_pll_muldiv settings;
227 int ret;
228
229 ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
230 if (ret < 0)
231 return -EINVAL;
232
233 return clk_aic32x4_pll_set_muldiv(pll, &settings);
234}
235
236static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
237{
238 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
239
240 return regmap_update_bits(pll->regmap,
241 AIC32X4_CLKMUX,
242 AIC32X4_PLL_CLKIN_MASK,
243 index << AIC32X4_PLL_CLKIN_SHIFT);
244}
245
246static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
247{
248 struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
249 unsigned int val;
250
251 regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
252
253 return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
254}
255
256
257static const struct clk_ops aic32x4_pll_ops = {
258 .prepare = clk_aic32x4_pll_prepare,
259 .unprepare = clk_aic32x4_pll_unprepare,
260 .is_prepared = clk_aic32x4_pll_is_prepared,
261 .recalc_rate = clk_aic32x4_pll_recalc_rate,
262 .round_rate = clk_aic32x4_pll_round_rate,
263 .set_rate = clk_aic32x4_pll_set_rate,
264 .set_parent = clk_aic32x4_pll_set_parent,
265 .get_parent = clk_aic32x4_pll_get_parent,
266};
267
268static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
269{
270 struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
271
272 return regmap_update_bits(mux->regmap,
273 AIC32X4_CLKMUX,
274 AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
275}
276
277static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
278{
279 struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
280 unsigned int val;
281
282 regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
283
284 return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
285}
286
287static const struct clk_ops aic32x4_codec_clkin_ops = {
288 .set_parent = clk_aic32x4_codec_clkin_set_parent,
289 .get_parent = clk_aic32x4_codec_clkin_get_parent,
290};
291
292static int clk_aic32x4_div_prepare(struct clk_hw *hw)
293{
294 struct clk_aic32x4 *div = to_clk_aic32x4(hw);
295
296 return regmap_update_bits(div->regmap, div->reg,
297 AIC32X4_DIVEN, AIC32X4_DIVEN);
298}
299
300static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
301{
302 struct clk_aic32x4 *div = to_clk_aic32x4(hw);
303
304 regmap_update_bits(div->regmap, div->reg,
305 AIC32X4_DIVEN, 0);
306}
307
308static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
309 unsigned long parent_rate)
310{
311 struct clk_aic32x4 *div = to_clk_aic32x4(hw);
312 u8 divisor;
313
314 divisor = DIV_ROUND_UP(parent_rate, rate);
315 if (divisor > 128)
316 return -EINVAL;
317
318 return regmap_update_bits(div->regmap, div->reg,
319 AIC32X4_DIV_MASK, divisor);
320}
321
322static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
323 unsigned long *parent_rate)
324{
325 unsigned long divisor;
326
327 divisor = DIV_ROUND_UP(*parent_rate, rate);
328 if (divisor > 128)
329 return -EINVAL;
330
331 return DIV_ROUND_UP(*parent_rate, divisor);
332}
333
334static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
335 unsigned long parent_rate)
336{
337 struct clk_aic32x4 *div = to_clk_aic32x4(hw);
338
339 unsigned int val;
340
341 regmap_read(div->regmap, div->reg, &val);
342
343 return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
344}
345
346static const struct clk_ops aic32x4_div_ops = {
347 .prepare = clk_aic32x4_div_prepare,
348 .unprepare = clk_aic32x4_div_unprepare,
349 .set_rate = clk_aic32x4_div_set_rate,
350 .round_rate = clk_aic32x4_div_round_rate,
351 .recalc_rate = clk_aic32x4_div_recalc_rate,
352};
353
354static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
355{
356 struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
357
358 return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
359 AIC32X4_BDIVCLK_MASK, index);
360}
361
362static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
363{
364 struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
365 unsigned int val;
366
367 regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
368
369 return val & AIC32X4_BDIVCLK_MASK;
370}
371
372static const struct clk_ops aic32x4_bdiv_ops = {
373 .prepare = clk_aic32x4_div_prepare,
374 .unprepare = clk_aic32x4_div_unprepare,
375 .set_parent = clk_aic32x4_bdiv_set_parent,
376 .get_parent = clk_aic32x4_bdiv_get_parent,
377 .set_rate = clk_aic32x4_div_set_rate,
378 .round_rate = clk_aic32x4_div_round_rate,
379 .recalc_rate = clk_aic32x4_div_recalc_rate,
380};
381
382static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
383 {
384 .name = "pll",
385 .parent_names =
386 (const char* []) { "mclk", "bclk", "gpio", "din" },
387 .num_parents = 4,
388 .ops = &aic32x4_pll_ops,
389 .reg = 0,
390 },
391 {
392 .name = "codec_clkin",
393 .parent_names =
394 (const char *[]) { "mclk", "bclk", "gpio", "pll" },
395 .num_parents = 4,
396 .ops = &aic32x4_codec_clkin_ops,
397 .reg = 0,
398 },
399 {
400 .name = "ndac",
401 .parent_names = (const char * []) { "codec_clkin" },
402 .num_parents = 1,
403 .ops = &aic32x4_div_ops,
404 .reg = AIC32X4_NDAC,
405 },
406 {
407 .name = "mdac",
408 .parent_names = (const char * []) { "ndac" },
409 .num_parents = 1,
410 .ops = &aic32x4_div_ops,
411 .reg = AIC32X4_MDAC,
412 },
413 {
414 .name = "nadc",
415 .parent_names = (const char * []) { "codec_clkin" },
416 .num_parents = 1,
417 .ops = &aic32x4_div_ops,
418 .reg = AIC32X4_NADC,
419 },
420 {
421 .name = "madc",
422 .parent_names = (const char * []) { "nadc" },
423 .num_parents = 1,
424 .ops = &aic32x4_div_ops,
425 .reg = AIC32X4_MADC,
426 },
427 {
428 .name = "bdiv",
429 .parent_names =
430 (const char *[]) { "ndac", "mdac", "nadc", "madc" },
431 .num_parents = 4,
432 .ops = &aic32x4_bdiv_ops,
433 .reg = AIC32X4_BCLKN,
434 },
435};
436
437static struct clk *aic32x4_register_clk(struct device *dev,
438 struct aic32x4_clkdesc *desc)
439{
440 struct clk_init_data init;
441 struct clk_aic32x4 *priv;
442 const char *devname = dev_name(dev);
443
444 init.ops = desc->ops;
445 init.name = desc->name;
446 init.parent_names = desc->parent_names;
447 init.num_parents = desc->num_parents;
448 init.flags = 0;
449
450 priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
451 if (priv == NULL)
452 return (struct clk *) -ENOMEM;
453
454 priv->dev = dev;
455 priv->hw.init = &init;
456 priv->regmap = dev_get_regmap(dev, NULL);
457 priv->reg = desc->reg;
458
459 clk_hw_register_clkdev(&priv->hw, desc->name, devname);
460 return devm_clk_register(dev, &priv->hw);
461}
462
463int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
464{
465 int i;
466
467 /*
468 * These lines are here to preserve the current functionality of
469 * the driver with regard to the DT. These should eventually be set
470 * by DT nodes so that the connections can be set up in configuration
471 * rather than code.
472 */
473 aic32x4_clkdesc_array[0].parent_names =
474 (const char* []) { mclk_name, "bclk", "gpio", "din" };
475 aic32x4_clkdesc_array[1].parent_names =
476 (const char *[]) { mclk_name, "bclk", "gpio", "pll" };
477
478 for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
479 aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
480
481 return 0;
482}
483EXPORT_SYMBOL_GPL(aic32x4_register_clocks);
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
index 22c3a6bc0b6c..6d54cbf70a0b 100644
--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -1,21 +1,11 @@
1/* 1/* SPDX-License-Identifier: GPL-2.0
2 * linux/sound/soc/codecs/tlv320aic32x4-i2c.c
3 * 2 *
4 * Copyright 2011 NW Digital Radio 3 * Copyright 2011-2019 NW Digital Radio
5 * 4 *
6 * Author: Annaliese McDermond <nh6z@nh6z.net> 5 * Author: Annaliese McDermond <nh6z@nh6z.net>
7 * 6 *
8 * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. 7 * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
9 * 8 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 */ 9 */
20 10
21#include <linux/i2c.h> 11#include <linux/i2c.h>
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
index aa5b7ba0254b..a22e7700bfc8 100644
--- a/sound/soc/codecs/tlv320aic32x4-spi.c
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -1,21 +1,11 @@
1/* 1/* SPDX-License-Identifier: GPL-2.0
2 * linux/sound/soc/codecs/tlv320aic32x4-spi.c
3 * 2 *
4 * Copyright 2011 NW Digital Radio 3 * Copyright 2011-2019 NW Digital Radio
5 * 4 *
6 * Author: Annaliese McDermond <nh6z@nh6z.net> 5 * Author: Annaliese McDermond <nh6z@nh6z.net>
7 * 6 *
8 * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. 7 * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
9 * 8 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 */ 9 */
20 10
21#include <linux/spi/spi.h> 11#include <linux/spi/spi.h>
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 5520044929f4..83608f386aef 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -14,7 +14,7 @@
14 * 14 *
15 * This program is distributed in the hope that it will be useful, 15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details. 18 * GNU General Public License for more details.
19 * 19 *
20 * You should have received a copy of the GNU General Public License 20 * You should have received a copy of the GNU General Public License
@@ -33,6 +33,7 @@
33#include <linux/cdev.h> 33#include <linux/cdev.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/clk.h> 35#include <linux/clk.h>
36#include <linux/of_clk.h>
36#include <linux/regulator/consumer.h> 37#include <linux/regulator/consumer.h>
37 38
38#include <sound/tlv320aic32x4.h> 39#include <sound/tlv320aic32x4.h>
@@ -46,29 +47,13 @@
46 47
47#include "tlv320aic32x4.h" 48#include "tlv320aic32x4.h"
48 49
49struct aic32x4_rate_divs {
50 u32 mclk;
51 u32 rate;
52 u8 p_val;
53 u8 pll_j;
54 u16 pll_d;
55 u16 dosr;
56 u8 ndac;
57 u8 mdac;
58 u8 aosr;
59 u8 nadc;
60 u8 madc;
61 u8 blck_N;
62};
63
64struct aic32x4_priv { 50struct aic32x4_priv {
65 struct regmap *regmap; 51 struct regmap *regmap;
66 u32 sysclk;
67 u32 power_cfg; 52 u32 power_cfg;
68 u32 micpga_routing; 53 u32 micpga_routing;
69 bool swapdacs; 54 bool swapdacs;
70 int rstn_gpio; 55 int rstn_gpio;
71 struct clk *mclk; 56 const char *mclk_name;
72 57
73 struct regulator *supply_ldo; 58 struct regulator *supply_ldo;
74 struct regulator *supply_iov; 59 struct regulator *supply_iov;
@@ -257,9 +242,24 @@ static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
257/* -12dB min, 0.5dB steps */ 242/* -12dB min, 0.5dB steps */
258static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0); 243static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
259 244
245static const char * const lo_cm_text[] = {
246 "Full Chip", "1.65V",
247};
248
249static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
250
251static const char * const ptm_text[] = {
252 "P3", "P2", "P1",
253};
254
255static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
256static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
257
260static const struct snd_kcontrol_new aic32x4_snd_controls[] = { 258static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
261 SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, 259 SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
262 AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), 260 AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
261 SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
262 SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
263 SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, 263 SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
264 AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, 264 AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
265 tlv_driver_gain), 265 tlv_driver_gain),
@@ -270,6 +270,7 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
270 AIC32X4_HPRGAIN, 6, 0x01, 1), 270 AIC32X4_HPRGAIN, 6, 0x01, 1),
271 SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, 271 SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
272 AIC32X4_LORGAIN, 6, 0x01, 1), 272 AIC32X4_LORGAIN, 6, 0x01, 1),
273 SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
273 SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL, 274 SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
274 AIC32X4_RMICPGAVOL, 7, 0x01, 1), 275 AIC32X4_RMICPGAVOL, 7, 0x01, 1),
275 276
@@ -305,38 +306,6 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
305 0, 0x0F, 0), 306 0, 0x0F, 0),
306}; 307};
307 308
308static const struct aic32x4_rate_divs aic32x4_divs[] = {
309 /* 8k rate */
310 {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
311 {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
312 {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
313 /* 11.025k rate */
314 {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
315 {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
316 /* 16k rate */
317 {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
318 {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
319 {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
320 /* 22.05k rate */
321 {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
322 {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
323 {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
324 /* 32k rate */
325 {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
326 {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
327 /* 44.1k rate */
328 {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
329 {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
330 {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
331 /* 48k rate */
332 {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
333 {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
334 {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
335
336 /* 96k rate */
337 {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
338};
339
340static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { 309static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
341 SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0), 310 SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
342 SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0), 311 SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
@@ -391,7 +360,7 @@ static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
391 SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum), 360 SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
392}; 361};
393 362
394/* Right mixer pins */ 363/* Right mixer pins */
395static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text); 364static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
396static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text); 365static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
397static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text); 366static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
@@ -595,7 +564,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
595static const struct regmap_range_cfg aic32x4_regmap_pages[] = { 564static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
596 { 565 {
597 .selector_reg = 0, 566 .selector_reg = 0,
598 .selector_mask = 0xff, 567 .selector_mask = 0xff,
599 .window_start = 0, 568 .window_start = 0,
600 .window_len = 128, 569 .window_len = 128,
601 .range_min = 0, 570 .range_min = 0,
@@ -610,35 +579,17 @@ const struct regmap_config aic32x4_regmap_config = {
610}; 579};
611EXPORT_SYMBOL(aic32x4_regmap_config); 580EXPORT_SYMBOL(aic32x4_regmap_config);
612 581
613static inline int aic32x4_get_divs(int mclk, int rate)
614{
615 int i;
616
617 for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
618 if ((aic32x4_divs[i].rate == rate)
619 && (aic32x4_divs[i].mclk == mclk)) {
620 return i;
621 }
622 }
623 printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
624 return -EINVAL;
625}
626
627static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, 582static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
628 int clk_id, unsigned int freq, int dir) 583 int clk_id, unsigned int freq, int dir)
629{ 584{
630 struct snd_soc_component *component = codec_dai->component; 585 struct snd_soc_component *component = codec_dai->component;
631 struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); 586 struct clk *mclk;
587 struct clk *pll;
632 588
633 switch (freq) { 589 pll = devm_clk_get(component->dev, "pll");
634 case 12000000: 590 mclk = clk_get_parent(pll);
635 case 24000000: 591
636 case 25000000: 592 return clk_set_rate(mclk, freq);
637 aic32x4->sysclk = freq;
638 return 0;
639 }
640 printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
641 return -EINVAL;
642} 593}
643 594
644static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 595static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
@@ -688,103 +639,175 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
688 } 639 }
689 640
690 snd_soc_component_update_bits(component, AIC32X4_IFACE1, 641 snd_soc_component_update_bits(component, AIC32X4_IFACE1,
691 AIC32X4_IFACE1_DATATYPE_MASK | 642 AIC32X4_IFACE1_DATATYPE_MASK |
692 AIC32X4_IFACE1_MASTER_MASK, iface_reg_1); 643 AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
693 snd_soc_component_update_bits(component, AIC32X4_IFACE2, 644 snd_soc_component_update_bits(component, AIC32X4_IFACE2,
694 AIC32X4_DATA_OFFSET_MASK, iface_reg_2); 645 AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
695 snd_soc_component_update_bits(component, AIC32X4_IFACE3, 646 snd_soc_component_update_bits(component, AIC32X4_IFACE3,
696 AIC32X4_BCLKINV_MASK, iface_reg_3); 647 AIC32X4_BCLKINV_MASK, iface_reg_3);
697 648
698 return 0; 649 return 0;
699} 650}
700 651
701static int aic32x4_hw_params(struct snd_pcm_substream *substream, 652static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
702 struct snd_pcm_hw_params *params,
703 struct snd_soc_dai *dai)
704{ 653{
705 struct snd_soc_component *component = dai->component; 654 return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
706 struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); 655}
707 u8 iface1_reg = 0;
708 u8 dacsetup_reg = 0;
709 int i;
710
711 i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
712 if (i < 0) {
713 printk(KERN_ERR "aic32x4: sampling rate not supported\n");
714 return i;
715 }
716 656
717 /* MCLK as PLL_CLKIN */ 657static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
718 snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK, 658{
719 AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT); 659 snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
720 /* PLL as CODEC_CLKIN */ 660 snd_soc_component_write(component, AIC32X4_DOSRLSB,
721 snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK, 661 (dosr & 0xff));
722 AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
723 /* DAC_MOD_CLK as BDIV_CLKIN */
724 snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
725 AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
726 662
727 /* We will fix R value to 1 and will make P & J=K.D as variable */ 663 return 0;
728 snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01); 664}
729 665
730 /* PLL P value */ 666static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
731 snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK, 667 u8 r_block, u8 p_block)
732 aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT); 668{
669 if (r_block > 18 || p_block > 25)
670 return -EINVAL;
733 671
734 /* PLL J value */ 672 snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
735 snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j); 673 snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
736 674
737 /* PLL D value */ 675 return 0;
738 snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8)); 676}
739 snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
740 677
741 /* NDAC divider value */ 678static int aic32x4_setup_clocks(struct snd_soc_component *component,
742 snd_soc_component_update_bits(component, AIC32X4_NDAC, 679 unsigned int sample_rate)
743 AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac); 680{
681 u8 aosr;
682 u16 dosr;
683 u8 adc_resource_class, dac_resource_class;
684 u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
685 u8 dosr_increment;
686 u16 max_dosr, min_dosr;
687 unsigned long adc_clock_rate, dac_clock_rate;
688 int ret;
744 689
745 /* MDAC divider value */ 690 struct clk_bulk_data clocks[] = {
746 snd_soc_component_update_bits(component, AIC32X4_MDAC, 691 { .id = "pll" },
747 AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac); 692 { .id = "nadc" },
693 { .id = "madc" },
694 { .id = "ndac" },
695 { .id = "mdac" },
696 { .id = "bdiv" },
697 };
698 ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
699 if (ret)
700 return ret;
748 701
749 /* DOSR MSB & LSB values */ 702 if (sample_rate <= 48000) {
750 snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8); 703 aosr = 128;
751 snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff)); 704 adc_resource_class = 6;
705 dac_resource_class = 8;
706 dosr_increment = 8;
707 aic32x4_set_processing_blocks(component, 1, 1);
708 } else if (sample_rate <= 96000) {
709 aosr = 64;
710 adc_resource_class = 6;
711 dac_resource_class = 8;
712 dosr_increment = 4;
713 aic32x4_set_processing_blocks(component, 1, 9);
714 } else if (sample_rate == 192000) {
715 aosr = 32;
716 adc_resource_class = 3;
717 dac_resource_class = 4;
718 dosr_increment = 2;
719 aic32x4_set_processing_blocks(component, 13, 19);
720 } else {
721 dev_err(component->dev, "Sampling rate not supported\n");
722 return -EINVAL;
723 }
752 724
753 /* NADC divider value */ 725 madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
754 snd_soc_component_update_bits(component, AIC32X4_NADC, 726 max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
755 AIC32X4_NADC_MASK, aic32x4_divs[i].nadc); 727 dosr_increment;
728 min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
729 dosr_increment;
730 max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
731
732 for (nadc = max_nadc; nadc > 0; --nadc) {
733 adc_clock_rate = nadc * madc * aosr * sample_rate;
734 for (dosr = max_dosr; dosr >= min_dosr;
735 dosr -= dosr_increment) {
736 min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
737 max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
738 (min_mdac * dosr * sample_rate);
739 for (mdac = min_mdac; mdac <= 128; ++mdac) {
740 for (ndac = max_ndac; ndac > 0; --ndac) {
741 dac_clock_rate = ndac * mdac * dosr *
742 sample_rate;
743 if (dac_clock_rate == adc_clock_rate) {
744 if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
745 continue;
746
747 clk_set_rate(clocks[0].clk,
748 dac_clock_rate);
749
750 clk_set_rate(clocks[1].clk,
751 sample_rate * aosr *
752 madc);
753 clk_set_rate(clocks[2].clk,
754 sample_rate * aosr);
755 aic32x4_set_aosr(component,
756 aosr);
757
758 clk_set_rate(clocks[3].clk,
759 sample_rate * dosr *
760 mdac);
761 clk_set_rate(clocks[4].clk,
762 sample_rate * dosr);
763 aic32x4_set_dosr(component,
764 dosr);
765
766 clk_set_rate(clocks[5].clk,
767 sample_rate * 32);
768 return 0;
769 }
770 }
771 }
772 }
773 }
756 774
757 /* MADC divider value */ 775 dev_err(component->dev,
758 snd_soc_component_update_bits(component, AIC32X4_MADC, 776 "Could not set clocks to support sample rate.\n");
759 AIC32X4_MADC_MASK, aic32x4_divs[i].madc); 777 return -EINVAL;
778}
760 779
761 /* AOSR value */ 780static int aic32x4_hw_params(struct snd_pcm_substream *substream,
762 snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr); 781 struct snd_pcm_hw_params *params,
782 struct snd_soc_dai *dai)
783{
784 struct snd_soc_component *component = dai->component;
785 struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
786 u8 iface1_reg = 0;
787 u8 dacsetup_reg = 0;
763 788
764 /* BCLK N divider */ 789 aic32x4_setup_clocks(component, params_rate(params));
765 snd_soc_component_update_bits(component, AIC32X4_BCLKN,
766 AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
767 790
768 switch (params_width(params)) { 791 switch (params_width(params)) {
769 case 16: 792 case 16:
770 iface1_reg |= (AIC32X4_WORD_LEN_16BITS << 793 iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
771 AIC32X4_IFACE1_DATALEN_SHIFT); 794 AIC32X4_IFACE1_DATALEN_SHIFT);
772 break; 795 break;
773 case 20: 796 case 20:
774 iface1_reg |= (AIC32X4_WORD_LEN_20BITS << 797 iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
775 AIC32X4_IFACE1_DATALEN_SHIFT); 798 AIC32X4_IFACE1_DATALEN_SHIFT);
776 break; 799 break;
777 case 24: 800 case 24:
778 iface1_reg |= (AIC32X4_WORD_LEN_24BITS << 801 iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
779 AIC32X4_IFACE1_DATALEN_SHIFT); 802 AIC32X4_IFACE1_DATALEN_SHIFT);
780 break; 803 break;
781 case 32: 804 case 32:
782 iface1_reg |= (AIC32X4_WORD_LEN_32BITS << 805 iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
783 AIC32X4_IFACE1_DATALEN_SHIFT); 806 AIC32X4_IFACE1_DATALEN_SHIFT);
784 break; 807 break;
785 } 808 }
786 snd_soc_component_update_bits(component, AIC32X4_IFACE1, 809 snd_soc_component_update_bits(component, AIC32X4_IFACE1,
787 AIC32X4_IFACE1_DATALEN_MASK, iface1_reg); 810 AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
788 811
789 if (params_channels(params) == 1) { 812 if (params_channels(params) == 1) {
790 dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; 813 dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
@@ -795,7 +818,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
795 dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; 818 dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
796 } 819 }
797 snd_soc_component_update_bits(component, AIC32X4_DACSETUP, 820 snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
798 AIC32X4_DAC_CHAN_MASK, dacsetup_reg); 821 AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
799 822
800 return 0; 823 return 0;
801} 824}
@@ -805,7 +828,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
805 struct snd_soc_component *component = dai->component; 828 struct snd_soc_component *component = dai->component;
806 829
807 snd_soc_component_update_bits(component, AIC32X4_DACMUTE, 830 snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
808 AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0); 831 AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
809 832
810 return 0; 833 return 0;
811} 834}
@@ -813,41 +836,25 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
813static int aic32x4_set_bias_level(struct snd_soc_component *component, 836static int aic32x4_set_bias_level(struct snd_soc_component *component,
814 enum snd_soc_bias_level level) 837 enum snd_soc_bias_level level)
815{ 838{
816 struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
817 int ret; 839 int ret;
818 840
841 struct clk_bulk_data clocks[] = {
842 { .id = "madc" },
843 { .id = "mdac" },
844 { .id = "bdiv" },
845 };
846
847 ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
848 if (ret)
849 return ret;
850
819 switch (level) { 851 switch (level) {
820 case SND_SOC_BIAS_ON: 852 case SND_SOC_BIAS_ON:
821 /* Switch on master clock */ 853 ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
822 ret = clk_prepare_enable(aic32x4->mclk);
823 if (ret) { 854 if (ret) {
824 dev_err(component->dev, "Failed to enable master clock\n"); 855 dev_err(component->dev, "Failed to enable clocks\n");
825 return ret; 856 return ret;
826 } 857 }
827
828 /* Switch on PLL */
829 snd_soc_component_update_bits(component, AIC32X4_PLLPR,
830 AIC32X4_PLLEN, AIC32X4_PLLEN);
831
832 /* Switch on NDAC Divider */
833 snd_soc_component_update_bits(component, AIC32X4_NDAC,
834 AIC32X4_NDACEN, AIC32X4_NDACEN);
835
836 /* Switch on MDAC Divider */
837 snd_soc_component_update_bits(component, AIC32X4_MDAC,
838 AIC32X4_MDACEN, AIC32X4_MDACEN);
839
840 /* Switch on NADC Divider */
841 snd_soc_component_update_bits(component, AIC32X4_NADC,
842 AIC32X4_NADCEN, AIC32X4_NADCEN);
843
844 /* Switch on MADC Divider */
845 snd_soc_component_update_bits(component, AIC32X4_MADC,
846 AIC32X4_MADCEN, AIC32X4_MADCEN);
847
848 /* Switch on BCLK_N Divider */
849 snd_soc_component_update_bits(component, AIC32X4_BCLKN,
850 AIC32X4_BCLKEN, AIC32X4_BCLKEN);
851 break; 858 break;
852 case SND_SOC_BIAS_PREPARE: 859 case SND_SOC_BIAS_PREPARE:
853 break; 860 break;
@@ -856,32 +863,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
856 if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) 863 if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
857 break; 864 break;
858 865
859 /* Switch off BCLK_N Divider */ 866 clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
860 snd_soc_component_update_bits(component, AIC32X4_BCLKN,
861 AIC32X4_BCLKEN, 0);
862
863 /* Switch off MADC Divider */
864 snd_soc_component_update_bits(component, AIC32X4_MADC,
865 AIC32X4_MADCEN, 0);
866
867 /* Switch off NADC Divider */
868 snd_soc_component_update_bits(component, AIC32X4_NADC,
869 AIC32X4_NADCEN, 0);
870
871 /* Switch off MDAC Divider */
872 snd_soc_component_update_bits(component, AIC32X4_MDAC,
873 AIC32X4_MDACEN, 0);
874
875 /* Switch off NDAC Divider */
876 snd_soc_component_update_bits(component, AIC32X4_NDAC,
877 AIC32X4_NDACEN, 0);
878
879 /* Switch off PLL */
880 snd_soc_component_update_bits(component, AIC32X4_PLLPR,
881 AIC32X4_PLLEN, 0);
882
883 /* Switch off master clock */
884 clk_disable_unprepare(aic32x4->mclk);
885 break; 867 break;
886 case SND_SOC_BIAS_OFF: 868 case SND_SOC_BIAS_OFF:
887 break; 869 break;
@@ -889,8 +871,8 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
889 return 0; 871 return 0;
890} 872}
891 873
892#define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000 874#define AIC32X4_RATES SNDRV_PCM_RATE_8000_192000
893#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ 875#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
894 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) 876 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
895 877
896static const struct snd_soc_dai_ops aic32x4_ops = { 878static const struct snd_soc_dai_ops aic32x4_ops = {
@@ -903,17 +885,17 @@ static const struct snd_soc_dai_ops aic32x4_ops = {
903static struct snd_soc_dai_driver aic32x4_dai = { 885static struct snd_soc_dai_driver aic32x4_dai = {
904 .name = "tlv320aic32x4-hifi", 886 .name = "tlv320aic32x4-hifi",
905 .playback = { 887 .playback = {
906 .stream_name = "Playback", 888 .stream_name = "Playback",
907 .channels_min = 1, 889 .channels_min = 1,
908 .channels_max = 2, 890 .channels_max = 2,
909 .rates = AIC32X4_RATES, 891 .rates = AIC32X4_RATES,
910 .formats = AIC32X4_FORMATS,}, 892 .formats = AIC32X4_FORMATS,},
911 .capture = { 893 .capture = {
912 .stream_name = "Capture", 894 .stream_name = "Capture",
913 .channels_min = 1, 895 .channels_min = 1,
914 .channels_max = 2, 896 .channels_max = 2,
915 .rates = AIC32X4_RATES, 897 .rates = AIC32X4_RATES,
916 .formats = AIC32X4_FORMATS,}, 898 .formats = AIC32X4_FORMATS,},
917 .ops = &aic32x4_ops, 899 .ops = &aic32x4_ops,
918 .symmetric_rates = 1, 900 .symmetric_rates = 1,
919}; 901};
@@ -926,7 +908,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
926 /* MFP1 */ 908 /* MFP1 */
927 if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) { 909 if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
928 snd_soc_component_write(component, AIC32X4_DINCTL, 910 snd_soc_component_write(component, AIC32X4_DINCTL,
929 aic32x4->setup->gpio_func[0]); 911 aic32x4->setup->gpio_func[0]);
930 snd_soc_add_component_controls(component, aic32x4_mfp1, 912 snd_soc_add_component_controls(component, aic32x4_mfp1,
931 ARRAY_SIZE(aic32x4_mfp1)); 913 ARRAY_SIZE(aic32x4_mfp1));
932 } 914 }
@@ -934,7 +916,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
934 /* MFP2 */ 916 /* MFP2 */
935 if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) { 917 if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
936 snd_soc_component_write(component, AIC32X4_DOUTCTL, 918 snd_soc_component_write(component, AIC32X4_DOUTCTL,
937 aic32x4->setup->gpio_func[1]); 919 aic32x4->setup->gpio_func[1]);
938 snd_soc_add_component_controls(component, aic32x4_mfp2, 920 snd_soc_add_component_controls(component, aic32x4_mfp2,
939 ARRAY_SIZE(aic32x4_mfp2)); 921 ARRAY_SIZE(aic32x4_mfp2));
940 } 922 }
@@ -942,7 +924,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
942 /* MFP3 */ 924 /* MFP3 */
943 if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) { 925 if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
944 snd_soc_component_write(component, AIC32X4_SCLKCTL, 926 snd_soc_component_write(component, AIC32X4_SCLKCTL,
945 aic32x4->setup->gpio_func[2]); 927 aic32x4->setup->gpio_func[2]);
946 snd_soc_add_component_controls(component, aic32x4_mfp3, 928 snd_soc_add_component_controls(component, aic32x4_mfp3,
947 ARRAY_SIZE(aic32x4_mfp3)); 929 ARRAY_SIZE(aic32x4_mfp3));
948 } 930 }
@@ -950,7 +932,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
950 /* MFP4 */ 932 /* MFP4 */
951 if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) { 933 if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
952 snd_soc_component_write(component, AIC32X4_MISOCTL, 934 snd_soc_component_write(component, AIC32X4_MISOCTL,
953 aic32x4->setup->gpio_func[3]); 935 aic32x4->setup->gpio_func[3]);
954 snd_soc_add_component_controls(component, aic32x4_mfp4, 936 snd_soc_add_component_controls(component, aic32x4_mfp4,
955 ARRAY_SIZE(aic32x4_mfp4)); 937 ARRAY_SIZE(aic32x4_mfp4));
956 } 938 }
@@ -958,7 +940,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
958 /* MFP5 */ 940 /* MFP5 */
959 if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) { 941 if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
960 snd_soc_component_write(component, AIC32X4_GPIOCTL, 942 snd_soc_component_write(component, AIC32X4_GPIOCTL,
961 aic32x4->setup->gpio_func[4]); 943 aic32x4->setup->gpio_func[4]);
962 snd_soc_add_component_controls(component, aic32x4_mfp5, 944 snd_soc_add_component_controls(component, aic32x4_mfp5,
963 ARRAY_SIZE(aic32x4_mfp5)); 945 ARRAY_SIZE(aic32x4_mfp5));
964 } 946 }
@@ -968,6 +950,18 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
968{ 950{
969 struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component); 951 struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
970 u32 tmp_reg; 952 u32 tmp_reg;
953 int ret;
954
955 struct clk_bulk_data clocks[] = {
956 { .id = "codec_clkin" },
957 { .id = "pll" },
958 { .id = "bdiv" },
959 { .id = "mdac" },
960 };
961
962 ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
963 if (ret)
964 return ret;
971 965
972 if (gpio_is_valid(aic32x4->rstn_gpio)) { 966 if (gpio_is_valid(aic32x4->rstn_gpio)) {
973 ndelay(10); 967 ndelay(10);
@@ -980,10 +974,13 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
980 if (aic32x4->setup) 974 if (aic32x4->setup)
981 aic32x4_setup_gpios(component); 975 aic32x4_setup_gpios(component);
982 976
977 clk_set_parent(clocks[0].clk, clocks[1].clk);
978 clk_set_parent(clocks[2].clk, clocks[3].clk);
979
983 /* Power platform configuration */ 980 /* Power platform configuration */
984 if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) { 981 if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
985 snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN | 982 snd_soc_component_write(component, AIC32X4_MICBIAS,
986 AIC32X4_MICBIAS_2075V); 983 AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
987 } 984 }
988 if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) 985 if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
989 snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE); 986 snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
@@ -1046,12 +1043,18 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
1046 struct device_node *np) 1043 struct device_node *np)
1047{ 1044{
1048 struct aic32x4_setup_data *aic32x4_setup; 1045 struct aic32x4_setup_data *aic32x4_setup;
1046 int ret;
1049 1047
1050 aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup), 1048 aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
1051 GFP_KERNEL); 1049 GFP_KERNEL);
1052 if (!aic32x4_setup) 1050 if (!aic32x4_setup)
1053 return -ENOMEM; 1051 return -ENOMEM;
1054 1052
1053 ret = of_property_match_string(np, "clock-names", "mclk");
1054 if (ret < 0)
1055 return -EINVAL;
1056 aic32x4->mclk_name = of_clk_get_parent_name(np, ret);
1057
1055 aic32x4->swapdacs = false; 1058 aic32x4->swapdacs = false;
1056 aic32x4->micpga_routing = 0; 1059 aic32x4->micpga_routing = 0;
1057 aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0); 1060 aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
@@ -1173,7 +1176,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
1173 return PTR_ERR(regmap); 1176 return PTR_ERR(regmap);
1174 1177
1175 aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), 1178 aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
1176 GFP_KERNEL); 1179 GFP_KERNEL);
1177 if (aic32x4 == NULL) 1180 if (aic32x4 == NULL)
1178 return -ENOMEM; 1181 return -ENOMEM;
1179 1182
@@ -1185,6 +1188,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
1185 aic32x4->swapdacs = pdata->swapdacs; 1188 aic32x4->swapdacs = pdata->swapdacs;
1186 aic32x4->micpga_routing = pdata->micpga_routing; 1189 aic32x4->micpga_routing = pdata->micpga_routing;
1187 aic32x4->rstn_gpio = pdata->rstn_gpio; 1190 aic32x4->rstn_gpio = pdata->rstn_gpio;
1191 aic32x4->mclk_name = "mclk";
1188 } else if (np) { 1192 } else if (np) {
1189 ret = aic32x4_parse_dt(aic32x4, np); 1193 ret = aic32x4_parse_dt(aic32x4, np);
1190 if (ret) { 1194 if (ret) {
@@ -1196,13 +1200,12 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
1196 aic32x4->swapdacs = false; 1200 aic32x4->swapdacs = false;
1197 aic32x4->micpga_routing = 0; 1201 aic32x4->micpga_routing = 0;
1198 aic32x4->rstn_gpio = -1; 1202 aic32x4->rstn_gpio = -1;
1203 aic32x4->mclk_name = "mclk";
1199 } 1204 }
1200 1205
1201 aic32x4->mclk = devm_clk_get(dev, "mclk"); 1206 ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
1202 if (IS_ERR(aic32x4->mclk)) { 1207 if (ret)
1203 dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); 1208 return ret;
1204 return PTR_ERR(aic32x4->mclk);
1205 }
1206 1209
1207 if (gpio_is_valid(aic32x4->rstn_gpio)) { 1210 if (gpio_is_valid(aic32x4->rstn_gpio)) {
1208 ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio, 1211 ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index c2d74025bf4b..40734211bc0e 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -16,6 +16,7 @@ struct regmap_config;
16extern const struct regmap_config aic32x4_regmap_config; 16extern const struct regmap_config aic32x4_regmap_config;
17int aic32x4_probe(struct device *dev, struct regmap *regmap); 17int aic32x4_probe(struct device *dev, struct regmap *regmap);
18int aic32x4_remove(struct device *dev); 18int aic32x4_remove(struct device *dev);
19int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
19 20
20/* tlv320aic32x4 register space (in decimal to match datasheet) */ 21/* tlv320aic32x4 register space (in decimal to match datasheet) */
21 22
@@ -77,6 +78,8 @@ int aic32x4_remove(struct device *dev);
77 78
78#define AIC32X4_PWRCFG AIC32X4_REG(1, 1) 79#define AIC32X4_PWRCFG AIC32X4_REG(1, 1)
79#define AIC32X4_LDOCTL AIC32X4_REG(1, 2) 80#define AIC32X4_LDOCTL AIC32X4_REG(1, 2)
81#define AIC32X4_LPLAYBACK AIC32X4_REG(1, 3)
82#define AIC32X4_RPLAYBACK AIC32X4_REG(1, 4)
80#define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9) 83#define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9)
81#define AIC32X4_CMMODE AIC32X4_REG(1, 10) 84#define AIC32X4_CMMODE AIC32X4_REG(1, 10)
82#define AIC32X4_HPLROUTE AIC32X4_REG(1, 12) 85#define AIC32X4_HPLROUTE AIC32X4_REG(1, 12)
@@ -205,4 +208,14 @@ int aic32x4_remove(struct device *dev);
205#define AIC32X4_RMICPGANIN_IN1L_10K 0x10 208#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
206#define AIC32X4_RMICPGANIN_CM1R_10K 0x40 209#define AIC32X4_RMICPGANIN_CM1R_10K 0x40
207 210
211/* Common mask and enable for all of the dividers */
212#define AIC32X4_DIVEN BIT(7)
213#define AIC32X4_DIV_MASK GENMASK(6, 0)
214
215/* Clock Limits */
216#define AIC32X4_MAX_DOSR_FREQ 6200000
217#define AIC32X4_MIN_DOSR_FREQ 2800000
218#define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000
219#define AIC32X4_MAX_PLL_CLKIN 20000000
220
208#endif /* _TLV320AIC32X4_H */ 221#endif /* _TLV320AIC32X4_H */
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 981f88a5f615..a04a7cedd99d 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5188,6 +5188,7 @@ static int wcd9335_slim_status(struct slim_device *sdev,
5188 5188
5189 wcd->slim = sdev; 5189 wcd->slim = sdev;
5190 wcd->slim_ifc_dev = of_slim_get_device(sdev->ctrl, ifc_dev_np); 5190 wcd->slim_ifc_dev = of_slim_get_device(sdev->ctrl, ifc_dev_np);
5191 of_node_put(ifc_dev_np);
5191 if (!wcd->slim_ifc_dev) { 5192 if (!wcd->slim_ifc_dev) {
5192 dev_err(dev, "Unable to get SLIM Interface device\n"); 5193 dev_err(dev, "Unable to get SLIM Interface device\n");
5193 return -EINVAL; 5194 return -EINVAL;
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 4466e195b66d..b32e8313954d 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -646,6 +646,8 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
646 return ret; 646 return ret;
647 } 647 }
648 } 648 }
649
650 wm_adsp2_set_dspclk(w, v);
649 break; 651 break;
650 652
651 case SND_SOC_DAPM_POST_PMD: 653 case SND_SOC_DAPM_POST_PMD:
@@ -659,7 +661,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
659 break; 661 break;
660 } 662 }
661 663
662 return wm_adsp2_early_event(w, kcontrol, event, v); 664 return wm_adsp_early_event(w, kcontrol, event);
663} 665}
664 666
665static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, 667static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index b25877fa529d..1f500cc8d96a 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -211,7 +211,9 @@ static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
211 211
212 v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; 212 v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
213 213
214 return wm_adsp2_early_event(w, kcontrol, event, v); 214 wm_adsp2_set_dspclk(w, v);
215
216 return wm_adsp_early_event(w, kcontrol, event);
215} 217}
216 218
217static const struct reg_sequence wm5110_no_dre_left_enable[] = { 219static const struct reg_sequence wm5110_no_dre_left_enable[] = {
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index b0b48eb9c7c9..b26e6b825a90 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -227,6 +227,89 @@
227 */ 227 */
228#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001 228#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001
229 229
230/*
231 * HALO system info
232 */
233#define HALO_AHBM_WINDOW_DEBUG_0 0x02040
234#define HALO_AHBM_WINDOW_DEBUG_1 0x02044
235
236/*
237 * HALO core
238 */
239#define HALO_SCRATCH1 0x005c0
240#define HALO_SCRATCH2 0x005c8
241#define HALO_SCRATCH3 0x005d0
242#define HALO_SCRATCH4 0x005d8
243#define HALO_CCM_CORE_CONTROL 0x41000
244#define HALO_CORE_SOFT_RESET 0x00010
245#define HALO_WDT_CONTROL 0x47000
246
247/*
248 * HALO MPU banks
249 */
250#define HALO_MPU_XMEM_ACCESS_0 0x43000
251#define HALO_MPU_YMEM_ACCESS_0 0x43004
252#define HALO_MPU_WINDOW_ACCESS_0 0x43008
253#define HALO_MPU_XREG_ACCESS_0 0x4300C
254#define HALO_MPU_YREG_ACCESS_0 0x43014
255#define HALO_MPU_XMEM_ACCESS_1 0x43018
256#define HALO_MPU_YMEM_ACCESS_1 0x4301C
257#define HALO_MPU_WINDOW_ACCESS_1 0x43020
258#define HALO_MPU_XREG_ACCESS_1 0x43024
259#define HALO_MPU_YREG_ACCESS_1 0x4302C
260#define HALO_MPU_XMEM_ACCESS_2 0x43030
261#define HALO_MPU_YMEM_ACCESS_2 0x43034
262#define HALO_MPU_WINDOW_ACCESS_2 0x43038
263#define HALO_MPU_XREG_ACCESS_2 0x4303C
264#define HALO_MPU_YREG_ACCESS_2 0x43044
265#define HALO_MPU_XMEM_ACCESS_3 0x43048
266#define HALO_MPU_YMEM_ACCESS_3 0x4304C
267#define HALO_MPU_WINDOW_ACCESS_3 0x43050
268#define HALO_MPU_XREG_ACCESS_3 0x43054
269#define HALO_MPU_YREG_ACCESS_3 0x4305C
270#define HALO_MPU_XM_VIO_ADDR 0x43100
271#define HALO_MPU_XM_VIO_STATUS 0x43104
272#define HALO_MPU_YM_VIO_ADDR 0x43108
273#define HALO_MPU_YM_VIO_STATUS 0x4310C
274#define HALO_MPU_PM_VIO_ADDR 0x43110
275#define HALO_MPU_PM_VIO_STATUS 0x43114
276#define HALO_MPU_LOCK_CONFIG 0x43140
277
278/*
279 * HALO_AHBM_WINDOW_DEBUG_1
280 */
281#define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00
282#define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8
283#define HALO_AHBM_FLAGS_ERR_MASK 0x000000ff
284
285/*
286 * HALO_CCM_CORE_CONTROL
287 */
288#define HALO_CORE_EN 0x00000001
289
290/*
291 * HALO_CORE_SOFT_RESET
292 */
293#define HALO_CORE_SOFT_RESET_MASK 0x00000001
294
295/*
296 * HALO_WDT_CONTROL
297 */
298#define HALO_WDT_EN_MASK 0x00000001
299
300/*
301 * HALO_MPU_?M_VIO_STATUS
302 */
303#define HALO_MPU_VIO_STS_MASK 0x007e0000
304#define HALO_MPU_VIO_STS_SHIFT 17
305#define HALO_MPU_VIO_ERR_WR_MASK 0x00008000
306#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff
307#define HALO_MPU_VIO_ERR_SRC_SHIFT 0
308
309static struct wm_adsp_ops wm_adsp1_ops;
310static struct wm_adsp_ops wm_adsp2_ops[];
311static struct wm_adsp_ops wm_halo_ops;
312
230struct wm_adsp_buf { 313struct wm_adsp_buf {
231 struct list_head list; 314 struct list_head list;
232 void *buf; 315 void *buf;
@@ -306,6 +389,12 @@ struct wm_adsp_system_config_xm_hdr {
306 __be32 build_job_number; 389 __be32 build_job_number;
307}; 390};
308 391
392struct wm_halo_system_config_xm_hdr {
393 __be32 halo_heartbeat;
394 __be32 build_job_name[3];
395 __be32 build_job_number;
396};
397
309struct wm_adsp_alg_xm_struct { 398struct wm_adsp_alg_xm_struct {
310 __be32 magic; 399 __be32 magic;
311 __be32 smoothing; 400 __be32 smoothing;
@@ -532,12 +621,18 @@ static const char *wm_adsp_mem_region_name(unsigned int type)
532 switch (type) { 621 switch (type) {
533 case WMFW_ADSP1_PM: 622 case WMFW_ADSP1_PM:
534 return "PM"; 623 return "PM";
624 case WMFW_HALO_PM_PACKED:
625 return "PM_PACKED";
535 case WMFW_ADSP1_DM: 626 case WMFW_ADSP1_DM:
536 return "DM"; 627 return "DM";
537 case WMFW_ADSP2_XM: 628 case WMFW_ADSP2_XM:
538 return "XM"; 629 return "XM";
630 case WMFW_HALO_XM_PACKED:
631 return "XM_PACKED";
539 case WMFW_ADSP2_YM: 632 case WMFW_ADSP2_YM:
540 return "YM"; 633 return "YM";
634 case WMFW_HALO_YM_PACKED:
635 return "YM_PACKED";
541 case WMFW_ADSP1_ZM: 636 case WMFW_ADSP1_ZM:
542 return "ZM"; 637 return "ZM";
543 default: 638 default:
@@ -769,17 +864,12 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
769static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem, 864static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
770 unsigned int offset) 865 unsigned int offset)
771{ 866{
772 if (WARN_ON(!mem))
773 return offset;
774 switch (mem->type) { 867 switch (mem->type) {
775 case WMFW_ADSP1_PM: 868 case WMFW_ADSP1_PM:
776 return mem->base + (offset * 3); 869 return mem->base + (offset * 3);
777 case WMFW_ADSP1_DM: 870 case WMFW_ADSP1_DM:
778 return mem->base + (offset * 2);
779 case WMFW_ADSP2_XM: 871 case WMFW_ADSP2_XM:
780 return mem->base + (offset * 2);
781 case WMFW_ADSP2_YM: 872 case WMFW_ADSP2_YM:
782 return mem->base + (offset * 2);
783 case WMFW_ADSP1_ZM: 873 case WMFW_ADSP1_ZM:
784 return mem->base + (offset * 2); 874 return mem->base + (offset * 2);
785 default: 875 default:
@@ -788,49 +878,72 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
788 } 878 }
789} 879}
790 880
791static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) 881static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem,
882 unsigned int offset)
883{
884 switch (mem->type) {
885 case WMFW_ADSP2_XM:
886 case WMFW_ADSP2_YM:
887 return mem->base + (offset * 4);
888 case WMFW_HALO_XM_PACKED:
889 case WMFW_HALO_YM_PACKED:
890 return (mem->base + (offset * 3)) & ~0x3;
891 case WMFW_HALO_PM_PACKED:
892 return mem->base + (offset * 5);
893 default:
894 WARN(1, "Unknown memory region type");
895 return offset;
896 }
897}
898
899static void wm_adsp_read_fw_status(struct wm_adsp *dsp,
900 int noffs, unsigned int *offs)
792{ 901{
793 unsigned int scratch[4];
794 unsigned int addr = dsp->base + ADSP2_SCRATCH0;
795 unsigned int i; 902 unsigned int i;
796 int ret; 903 int ret;
797 904
798 for (i = 0; i < ARRAY_SIZE(scratch); ++i) { 905 for (i = 0; i < noffs; ++i) {
799 ret = regmap_read(dsp->regmap, addr + i, &scratch[i]); 906 ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
800 if (ret) { 907 if (ret) {
801 adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret); 908 adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
802 return; 909 return;
803 } 910 }
804 } 911 }
912}
913
914static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
915{
916 unsigned int offs[] = {
917 ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
918 };
919
920 wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
805 921
806 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", 922 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
807 scratch[0], scratch[1], scratch[2], scratch[3]); 923 offs[0], offs[1], offs[2], offs[3]);
808} 924}
809 925
810static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp) 926static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
811{ 927{
812 unsigned int scratch[2]; 928 unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
813 int ret;
814 929
815 ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1, 930 wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
816 &scratch[0]);
817 if (ret) {
818 adsp_err(dsp, "Failed to read SCRATCH0_1: %d\n", ret);
819 return;
820 }
821 931
822 ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH2_3, 932 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
823 &scratch[1]); 933 offs[0] & 0xFFFF, offs[0] >> 16,
824 if (ret) { 934 offs[1] & 0xFFFF, offs[1] >> 16);
825 adsp_err(dsp, "Failed to read SCRATCH2_3: %d\n", ret); 935}
826 return; 936
827 } 937static void wm_halo_show_fw_status(struct wm_adsp *dsp)
938{
939 unsigned int offs[] = {
940 HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
941 };
942
943 wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
828 944
829 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", 945 adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
830 scratch[0] & 0xFFFF, 946 offs[0], offs[1], offs[2], offs[3]);
831 scratch[0] >> 16,
832 scratch[1] & 0xFFFF,
833 scratch[1] >> 16);
834} 947}
835 948
836static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) 949static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
@@ -851,7 +964,7 @@ static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg)
851 return -EINVAL; 964 return -EINVAL;
852 } 965 }
853 966
854 *reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset); 967 *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
855 968
856 return 0; 969 return 0;
857} 970}
@@ -1339,28 +1452,33 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
1339 case 1: 1452 case 1:
1340 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x", 1453 snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
1341 dsp->name, region_name, alg_region->alg); 1454 dsp->name, region_name, alg_region->alg);
1455 subname = NULL; /* don't append subname */
1342 break; 1456 break;
1343 default: 1457 case 2:
1344 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, 1458 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1345 "%s%c %.12s %x", dsp->name, *region_name, 1459 "%s%c %.12s %x", dsp->name, *region_name,
1346 wm_adsp_fw_text[dsp->fw], alg_region->alg); 1460 wm_adsp_fw_text[dsp->fw], alg_region->alg);
1461 break;
1462 default:
1463 ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
1464 "%s %.12s %x", dsp->name,
1465 wm_adsp_fw_text[dsp->fw], alg_region->alg);
1466 break;
1467 }
1347 1468
1348 /* Truncate the subname from the start if it is too long */ 1469 if (subname) {
1349 if (subname) { 1470 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
1350 int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; 1471 int skip = 0;
1351 int skip = 0;
1352 1472
1353 if (dsp->component->name_prefix) 1473 if (dsp->component->name_prefix)
1354 avail -= strlen(dsp->component->name_prefix) + 1; 1474 avail -= strlen(dsp->component->name_prefix) + 1;
1355 1475
1356 if (subname_len > avail) 1476 /* Truncate the subname from the start if it is too long */
1357 skip = subname_len - avail; 1477 if (subname_len > avail)
1478 skip = subname_len - avail;
1358 1479
1359 snprintf(name + ret, 1480 snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
1360 SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s", 1481 " %.*s", subname_len - skip, subname + skip);
1361 subname_len - skip, subname + skip);
1362 }
1363 break;
1364 } 1482 }
1365 1483
1366 list_for_each_entry(ctl, &dsp->ctl_list, list) { 1484 list_for_each_entry(ctl, &dsp->ctl_list, list) {
@@ -1647,6 +1765,62 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
1647 return 0; 1765 return 0;
1648} 1766}
1649 1767
1768static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
1769 const char * const file,
1770 unsigned int pos,
1771 const struct firmware *firmware)
1772{
1773 const struct wmfw_adsp1_sizes *adsp1_sizes;
1774
1775 adsp1_sizes = (void *)&firmware->data[pos];
1776
1777 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
1778 le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
1779 le32_to_cpu(adsp1_sizes->zm));
1780
1781 return pos + sizeof(*adsp1_sizes);
1782}
1783
1784static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
1785 const char * const file,
1786 unsigned int pos,
1787 const struct firmware *firmware)
1788{
1789 const struct wmfw_adsp2_sizes *adsp2_sizes;
1790
1791 adsp2_sizes = (void *)&firmware->data[pos];
1792
1793 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
1794 le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
1795 le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
1796
1797 return pos + sizeof(*adsp2_sizes);
1798}
1799
1800static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
1801{
1802 switch (version) {
1803 case 0:
1804 adsp_warn(dsp, "Deprecated file format %d\n", version);
1805 return true;
1806 case 1:
1807 case 2:
1808 return true;
1809 default:
1810 return false;
1811 }
1812}
1813
1814static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version)
1815{
1816 switch (version) {
1817 case 3:
1818 return true;
1819 default:
1820 return false;
1821 }
1822}
1823
1650static int wm_adsp_load(struct wm_adsp *dsp) 1824static int wm_adsp_load(struct wm_adsp *dsp)
1651{ 1825{
1652 LIST_HEAD(buf_list); 1826 LIST_HEAD(buf_list);
@@ -1655,7 +1829,6 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1655 unsigned int pos = 0; 1829 unsigned int pos = 0;
1656 const struct wmfw_header *header; 1830 const struct wmfw_header *header;
1657 const struct wmfw_adsp1_sizes *adsp1_sizes; 1831 const struct wmfw_adsp1_sizes *adsp1_sizes;
1658 const struct wmfw_adsp2_sizes *adsp2_sizes;
1659 const struct wmfw_footer *footer; 1832 const struct wmfw_footer *footer;
1660 const struct wmfw_region *region; 1833 const struct wmfw_region *region;
1661 const struct wm_adsp_region *mem; 1834 const struct wm_adsp_region *mem;
@@ -1664,7 +1837,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1664 struct wm_adsp_buf *buf; 1837 struct wm_adsp_buf *buf;
1665 unsigned int reg; 1838 unsigned int reg;
1666 int regions = 0; 1839 int regions = 0;
1667 int ret, offset, type, sizes; 1840 int ret, offset, type;
1668 1841
1669 file = kzalloc(PAGE_SIZE, GFP_KERNEL); 1842 file = kzalloc(PAGE_SIZE, GFP_KERNEL);
1670 if (file == NULL) 1843 if (file == NULL)
@@ -1695,15 +1868,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1695 goto out_fw; 1868 goto out_fw;
1696 } 1869 }
1697 1870
1698 switch (header->ver) { 1871 if (!dsp->ops->validate_version(dsp, header->ver)) {
1699 case 0:
1700 adsp_warn(dsp, "%s: Depreciated file format %d\n",
1701 file, header->ver);
1702 break;
1703 case 1:
1704 case 2:
1705 break;
1706 default:
1707 adsp_err(dsp, "%s: unknown file format %d\n", 1872 adsp_err(dsp, "%s: unknown file format %d\n",
1708 file, header->ver); 1873 file, header->ver);
1709 goto out_fw; 1874 goto out_fw;
@@ -1718,39 +1883,13 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1718 goto out_fw; 1883 goto out_fw;
1719 } 1884 }
1720 1885
1721 switch (dsp->type) { 1886 pos = sizeof(*header);
1722 case WMFW_ADSP1: 1887 pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
1723 pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1724 adsp1_sizes = (void *)&(header[1]);
1725 footer = (void *)&(adsp1_sizes[1]);
1726 sizes = sizeof(*adsp1_sizes);
1727 1888
1728 adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", 1889 footer = (void *)&firmware->data[pos];
1729 file, le32_to_cpu(adsp1_sizes->dm), 1890 pos += sizeof(*footer);
1730 le32_to_cpu(adsp1_sizes->pm),
1731 le32_to_cpu(adsp1_sizes->zm));
1732 break;
1733
1734 case WMFW_ADSP2:
1735 pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
1736 adsp2_sizes = (void *)&(header[1]);
1737 footer = (void *)&(adsp2_sizes[1]);
1738 sizes = sizeof(*adsp2_sizes);
1739
1740 adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
1741 file, le32_to_cpu(adsp2_sizes->xm),
1742 le32_to_cpu(adsp2_sizes->ym),
1743 le32_to_cpu(adsp2_sizes->pm),
1744 le32_to_cpu(adsp2_sizes->zm));
1745 break;
1746
1747 default:
1748 WARN(1, "Unknown DSP type");
1749 goto out_fw;
1750 }
1751 1891
1752 if (le32_to_cpu(header->len) != sizeof(*header) + 1892 if (le32_to_cpu(header->len) != pos) {
1753 sizes + sizeof(*footer)) {
1754 adsp_err(dsp, "%s: unexpected header length %d\n", 1893 adsp_err(dsp, "%s: unexpected header length %d\n",
1755 file, le32_to_cpu(header->len)); 1894 file, le32_to_cpu(header->len));
1756 goto out_fw; 1895 goto out_fw;
@@ -1767,7 +1906,6 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1767 text = NULL; 1906 text = NULL;
1768 offset = le32_to_cpu(region->offset) & 0xffffff; 1907 offset = le32_to_cpu(region->offset) & 0xffffff;
1769 type = be32_to_cpu(region->type) & 0xff; 1908 type = be32_to_cpu(region->type) & 0xff;
1770 mem = wm_adsp_find_region(dsp, type);
1771 1909
1772 switch (type) { 1910 switch (type) {
1773 case WMFW_NAME_TEXT: 1911 case WMFW_NAME_TEXT:
@@ -1795,8 +1933,17 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1795 case WMFW_ADSP2_XM: 1933 case WMFW_ADSP2_XM:
1796 case WMFW_ADSP2_YM: 1934 case WMFW_ADSP2_YM:
1797 case WMFW_ADSP1_ZM: 1935 case WMFW_ADSP1_ZM:
1936 case WMFW_HALO_PM_PACKED:
1937 case WMFW_HALO_XM_PACKED:
1938 case WMFW_HALO_YM_PACKED:
1939 mem = wm_adsp_find_region(dsp, type);
1940 if (!mem) {
1941 adsp_err(dsp, "No region of type: %x\n", type);
1942 goto out_fw;
1943 }
1944
1798 region_name = wm_adsp_mem_region_name(type); 1945 region_name = wm_adsp_mem_region_name(type);
1799 reg = wm_adsp_region_to_reg(mem, offset); 1946 reg = dsp->ops->region_to_reg(mem, offset);
1800 break; 1947 break;
1801 default: 1948 default:
1802 adsp_warn(dsp, 1949 adsp_warn(dsp,
@@ -1909,7 +2056,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
1909 } 2056 }
1910 2057
1911 /* Read the terminator first to validate the length */ 2058 /* Read the terminator first to validate the length */
1912 reg = wm_adsp_region_to_reg(mem, pos + len); 2059 reg = dsp->ops->region_to_reg(mem, pos + len);
1913 2060
1914 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); 2061 ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
1915 if (ret != 0) { 2062 if (ret != 0) {
@@ -1929,7 +2076,7 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
1929 if (!alg) 2076 if (!alg)
1930 return ERR_PTR(-ENOMEM); 2077 return ERR_PTR(-ENOMEM);
1931 2078
1932 reg = wm_adsp_region_to_reg(mem, pos); 2079 reg = dsp->ops->region_to_reg(mem, pos);
1933 2080
1934 ret = regmap_raw_read(dsp->regmap, reg, alg, len); 2081 ret = regmap_raw_read(dsp->regmap, reg, alg, len);
1935 if (ret != 0) { 2082 if (ret != 0) {
@@ -1989,6 +2136,47 @@ static void wm_adsp_free_alg_regions(struct wm_adsp *dsp)
1989 } 2136 }
1990} 2137}
1991 2138
2139static void wmfw_parse_id_header(struct wm_adsp *dsp,
2140 struct wmfw_id_hdr *fw, int nalgs)
2141{
2142 dsp->fw_id = be32_to_cpu(fw->id);
2143 dsp->fw_id_version = be32_to_cpu(fw->ver);
2144
2145 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
2146 dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
2147 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2148 nalgs);
2149}
2150
2151static void wmfw_v3_parse_id_header(struct wm_adsp *dsp,
2152 struct wmfw_v3_id_hdr *fw, int nalgs)
2153{
2154 dsp->fw_id = be32_to_cpu(fw->id);
2155 dsp->fw_id_version = be32_to_cpu(fw->ver);
2156 dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
2157
2158 adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
2159 dsp->fw_id, dsp->fw_vendor_id,
2160 (dsp->fw_id_version & 0xff0000) >> 16,
2161 (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
2162 nalgs);
2163}
2164
2165static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions,
2166 int *type, __be32 *base)
2167{
2168 struct wm_adsp_alg_region *alg_region;
2169 int i;
2170
2171 for (i = 0; i < nregions; i++) {
2172 alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]);
2173 if (IS_ERR(alg_region))
2174 return PTR_ERR(alg_region);
2175 }
2176
2177 return 0;
2178}
2179
1992static int wm_adsp1_setup_algs(struct wm_adsp *dsp) 2180static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
1993{ 2181{
1994 struct wmfw_adsp1_id_hdr adsp1_id; 2182 struct wmfw_adsp1_id_hdr adsp1_id;
@@ -2012,13 +2200,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
2012 } 2200 }
2013 2201
2014 n_algs = be32_to_cpu(adsp1_id.n_algs); 2202 n_algs = be32_to_cpu(adsp1_id.n_algs);
2015 dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); 2203
2016 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", 2204 wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs);
2017 dsp->fw_id,
2018 (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
2019 (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
2020 be32_to_cpu(adsp1_id.fw.ver) & 0xff,
2021 n_algs);
2022 2205
2023 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, 2206 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
2024 adsp1_id.fw.id, adsp1_id.zm); 2207 adsp1_id.fw.id, adsp1_id.zm);
@@ -2118,14 +2301,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
2118 } 2301 }
2119 2302
2120 n_algs = be32_to_cpu(adsp2_id.n_algs); 2303 n_algs = be32_to_cpu(adsp2_id.n_algs);
2121 dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); 2304
2122 dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver); 2305 wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs);
2123 adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
2124 dsp->fw_id,
2125 (dsp->fw_id_version & 0xff0000) >> 16,
2126 (dsp->fw_id_version & 0xff00) >> 8,
2127 dsp->fw_id_version & 0xff,
2128 n_algs);
2129 2306
2130 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, 2307 alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
2131 adsp2_id.fw.id, adsp2_id.xm); 2308 adsp2_id.fw.id, adsp2_id.xm);
@@ -2230,6 +2407,78 @@ out:
2230 return ret; 2407 return ret;
2231} 2408}
2232 2409
2410static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id,
2411 __be32 xm_base, __be32 ym_base)
2412{
2413 int types[] = {
2414 WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
2415 WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
2416 };
2417 __be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
2418
2419 return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
2420}
2421
2422static int wm_halo_setup_algs(struct wm_adsp *dsp)
2423{
2424 struct wmfw_halo_id_hdr halo_id;
2425 struct wmfw_halo_alg_hdr *halo_alg;
2426 const struct wm_adsp_region *mem;
2427 unsigned int pos, len;
2428 size_t n_algs;
2429 int i, ret;
2430
2431 mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
2432 if (WARN_ON(!mem))
2433 return -EINVAL;
2434
2435 ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
2436 sizeof(halo_id));
2437 if (ret != 0) {
2438 adsp_err(dsp, "Failed to read algorithm info: %d\n",
2439 ret);
2440 return ret;
2441 }
2442
2443 n_algs = be32_to_cpu(halo_id.n_algs);
2444
2445 wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs);
2446
2447 ret = wm_halo_create_regions(dsp, halo_id.fw.id,
2448 halo_id.xm_base, halo_id.ym_base);
2449 if (ret)
2450 return ret;
2451
2452 /* Calculate offset and length in DSP words */
2453 pos = sizeof(halo_id) / sizeof(u32);
2454 len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
2455
2456 halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
2457 if (IS_ERR(halo_alg))
2458 return PTR_ERR(halo_alg);
2459
2460 for (i = 0; i < n_algs; i++) {
2461 adsp_info(dsp,
2462 "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
2463 i, be32_to_cpu(halo_alg[i].alg.id),
2464 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
2465 (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
2466 be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
2467 be32_to_cpu(halo_alg[i].xm_base),
2468 be32_to_cpu(halo_alg[i].ym_base));
2469
2470 ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id,
2471 halo_alg[i].xm_base,
2472 halo_alg[i].ym_base);
2473 if (ret)
2474 goto out;
2475 }
2476
2477out:
2478 kfree(halo_alg);
2479 return ret;
2480}
2481
2233static int wm_adsp_load_coeff(struct wm_adsp *dsp) 2482static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2234{ 2483{
2235 LIST_HEAD(buf_list); 2484 LIST_HEAD(buf_list);
@@ -2324,7 +2573,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2324 adsp_err(dsp, "No ZM\n"); 2573 adsp_err(dsp, "No ZM\n");
2325 break; 2574 break;
2326 } 2575 }
2327 reg = wm_adsp_region_to_reg(mem, 0); 2576 reg = dsp->ops->region_to_reg(mem, 0);
2328 2577
2329 } else { 2578 } else {
2330 region_name = "register"; 2579 region_name = "register";
@@ -2336,6 +2585,9 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2336 case WMFW_ADSP1_ZM: 2585 case WMFW_ADSP1_ZM:
2337 case WMFW_ADSP2_XM: 2586 case WMFW_ADSP2_XM:
2338 case WMFW_ADSP2_YM: 2587 case WMFW_ADSP2_YM:
2588 case WMFW_HALO_XM_PACKED:
2589 case WMFW_HALO_YM_PACKED:
2590 case WMFW_HALO_PM_PACKED:
2339 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", 2591 adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
2340 file, blocks, le32_to_cpu(blk->len), 2592 file, blocks, le32_to_cpu(blk->len),
2341 type, le32_to_cpu(blk->id)); 2593 type, le32_to_cpu(blk->id));
@@ -2350,7 +2602,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2350 le32_to_cpu(blk->id)); 2602 le32_to_cpu(blk->id));
2351 if (alg_region) { 2603 if (alg_region) {
2352 reg = alg_region->base; 2604 reg = alg_region->base;
2353 reg = wm_adsp_region_to_reg(mem, reg); 2605 reg = dsp->ops->region_to_reg(mem, reg);
2354 reg += offset; 2606 reg += offset;
2355 } else { 2607 } else {
2356 adsp_err(dsp, "No %x for algorithm %x\n", 2608 adsp_err(dsp, "No %x for algorithm %x\n",
@@ -2464,6 +2716,8 @@ static int wm_adsp_common_init(struct wm_adsp *dsp)
2464 2716
2465int wm_adsp1_init(struct wm_adsp *dsp) 2717int wm_adsp1_init(struct wm_adsp *dsp)
2466{ 2718{
2719 dsp->ops = &wm_adsp1_ops;
2720
2467 return wm_adsp_common_init(dsp); 2721 return wm_adsp_common_init(dsp);
2468} 2722}
2469EXPORT_SYMBOL_GPL(wm_adsp1_init); 2723EXPORT_SYMBOL_GPL(wm_adsp1_init);
@@ -2583,23 +2837,11 @@ err_mutex:
2583} 2837}
2584EXPORT_SYMBOL_GPL(wm_adsp1_event); 2838EXPORT_SYMBOL_GPL(wm_adsp1_event);
2585 2839
2586static int wm_adsp2_ena(struct wm_adsp *dsp) 2840static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
2587{ 2841{
2588 unsigned int val; 2842 unsigned int val;
2589 int ret, count; 2843 int ret, count;
2590 2844
2591 switch (dsp->rev) {
2592 case 0:
2593 ret = regmap_update_bits_async(dsp->regmap,
2594 dsp->base + ADSP2_CONTROL,
2595 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2596 if (ret != 0)
2597 return ret;
2598 break;
2599 default:
2600 break;
2601 }
2602
2603 /* Wait for the RAM to start, should be near instantaneous */ 2845 /* Wait for the RAM to start, should be near instantaneous */
2604 for (count = 0; count < 10; ++count) { 2846 for (count = 0; count < 10; ++count) {
2605 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); 2847 ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
@@ -2622,7 +2864,78 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
2622 return 0; 2864 return 0;
2623} 2865}
2624 2866
2625static void wm_adsp2_boot_work(struct work_struct *work) 2867static int wm_adsp2_enable_core(struct wm_adsp *dsp)
2868{
2869 int ret;
2870
2871 ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
2872 ADSP2_SYS_ENA, ADSP2_SYS_ENA);
2873 if (ret != 0)
2874 return ret;
2875
2876 return wm_adsp2v2_enable_core(dsp);
2877}
2878
2879static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
2880{
2881 struct regmap *regmap = dsp->regmap;
2882 unsigned int code0, code1, lock_reg;
2883
2884 if (!(lock_regions & WM_ADSP2_REGION_ALL))
2885 return 0;
2886
2887 lock_regions &= WM_ADSP2_REGION_ALL;
2888 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
2889
2890 while (lock_regions) {
2891 code0 = code1 = 0;
2892 if (lock_regions & BIT(0)) {
2893 code0 = ADSP2_LOCK_CODE_0;
2894 code1 = ADSP2_LOCK_CODE_1;
2895 }
2896 if (lock_regions & BIT(1)) {
2897 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
2898 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
2899 }
2900 regmap_write(regmap, lock_reg, code0);
2901 regmap_write(regmap, lock_reg, code1);
2902 lock_regions >>= 2;
2903 lock_reg += 2;
2904 }
2905
2906 return 0;
2907}
2908
2909static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
2910{
2911 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2912 ADSP2_MEM_ENA, ADSP2_MEM_ENA);
2913}
2914
2915static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
2916{
2917 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2918 ADSP2_MEM_ENA, 0);
2919}
2920
2921static void wm_adsp2_disable_core(struct wm_adsp *dsp)
2922{
2923 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2924 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2925 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2926
2927 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2928 ADSP2_SYS_ENA, 0);
2929}
2930
2931static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
2932{
2933 regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2934 regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2935 regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
2936}
2937
2938static void wm_adsp_boot_work(struct work_struct *work)
2626{ 2939{
2627 struct wm_adsp *dsp = container_of(work, 2940 struct wm_adsp *dsp = container_of(work,
2628 struct wm_adsp, 2941 struct wm_adsp,
@@ -2631,20 +2944,23 @@ static void wm_adsp2_boot_work(struct work_struct *work)
2631 2944
2632 mutex_lock(&dsp->pwr_lock); 2945 mutex_lock(&dsp->pwr_lock);
2633 2946
2634 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2947 if (dsp->ops->enable_memory) {
2635 ADSP2_MEM_ENA, ADSP2_MEM_ENA); 2948 ret = dsp->ops->enable_memory(dsp);
2636 if (ret != 0) 2949 if (ret != 0)
2637 goto err_mutex; 2950 goto err_mutex;
2951 }
2638 2952
2639 ret = wm_adsp2_ena(dsp); 2953 if (dsp->ops->enable_core) {
2640 if (ret != 0) 2954 ret = dsp->ops->enable_core(dsp);
2641 goto err_mem; 2955 if (ret != 0)
2956 goto err_mem;
2957 }
2642 2958
2643 ret = wm_adsp_load(dsp); 2959 ret = wm_adsp_load(dsp);
2644 if (ret != 0) 2960 if (ret != 0)
2645 goto err_ena; 2961 goto err_ena;
2646 2962
2647 ret = wm_adsp2_setup_algs(dsp); 2963 ret = dsp->ops->setup_algs(dsp);
2648 if (ret != 0) 2964 if (ret != 0)
2649 goto err_ena; 2965 goto err_ena;
2650 2966
@@ -2657,17 +2973,8 @@ static void wm_adsp2_boot_work(struct work_struct *work)
2657 if (ret != 0) 2973 if (ret != 0)
2658 goto err_ena; 2974 goto err_ena;
2659 2975
2660 switch (dsp->rev) { 2976 if (dsp->ops->disable_core)
2661 case 0: 2977 dsp->ops->disable_core(dsp);
2662 /* Turn DSP back off until we are ready to run */
2663 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
2664 ADSP2_SYS_ENA, 0);
2665 if (ret != 0)
2666 goto err_ena;
2667 break;
2668 default:
2669 break;
2670 }
2671 2978
2672 dsp->booted = true; 2979 dsp->booted = true;
2673 2980
@@ -2676,35 +2983,62 @@ static void wm_adsp2_boot_work(struct work_struct *work)
2676 return; 2983 return;
2677 2984
2678err_ena: 2985err_ena:
2679 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2986 if (dsp->ops->disable_core)
2680 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 2987 dsp->ops->disable_core(dsp);
2681err_mem: 2988err_mem:
2682 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 2989 if (dsp->ops->disable_memory)
2683 ADSP2_MEM_ENA, 0); 2990 dsp->ops->disable_memory(dsp);
2684err_mutex: 2991err_mutex:
2685 mutex_unlock(&dsp->pwr_lock); 2992 mutex_unlock(&dsp->pwr_lock);
2686} 2993}
2687 2994
2688static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq) 2995static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions)
2996{
2997 struct reg_sequence config[] = {
2998 { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 },
2999 { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA },
3000 { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF },
3001 { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF },
3002 { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
3003 { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions },
3004 { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions },
3005 { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF },
3006 { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF },
3007 { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
3008 { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions },
3009 { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions },
3010 { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF },
3011 { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF },
3012 { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
3013 { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions },
3014 { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions },
3015 { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF },
3016 { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF },
3017 { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
3018 { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions },
3019 { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions },
3020 { dsp->base + HALO_MPU_LOCK_CONFIG, 0 },
3021 };
3022
3023 return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
3024}
3025
3026int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
2689{ 3027{
3028 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
3029 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
3030 struct wm_adsp *dsp = &dsps[w->shift];
2690 int ret; 3031 int ret;
2691 3032
2692 switch (dsp->rev) { 3033 ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
2693 case 0: 3034 ADSP2_CLK_SEL_MASK,
2694 ret = regmap_update_bits_async(dsp->regmap, 3035 freq << ADSP2_CLK_SEL_SHIFT);
2695 dsp->base + ADSP2_CLOCKING, 3036 if (ret)
2696 ADSP2_CLK_SEL_MASK, 3037 adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2697 freq << ADSP2_CLK_SEL_SHIFT); 3038
2698 if (ret) { 3039 return ret;
2699 adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2700 return;
2701 }
2702 break;
2703 default:
2704 /* clock is handled by parent codec driver */
2705 break;
2706 }
2707} 3040}
3041EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
2708 3042
2709int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, 3043int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
2710 struct snd_ctl_elem_value *ucontrol) 3044 struct snd_ctl_elem_value *ucontrol)
@@ -2751,19 +3085,18 @@ EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
2751 3085
2752static void wm_adsp_stop_watchdog(struct wm_adsp *dsp) 3086static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
2753{ 3087{
2754 switch (dsp->rev) { 3088 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
2755 case 0: 3089 ADSP2_WDT_ENA_MASK, 0);
2756 case 1:
2757 return;
2758 default:
2759 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
2760 ADSP2_WDT_ENA_MASK, 0);
2761 }
2762} 3090}
2763 3091
2764int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 3092static void wm_halo_stop_watchdog(struct wm_adsp *dsp)
2765 struct snd_kcontrol *kcontrol, int event, 3093{
2766 unsigned int freq) 3094 regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
3095 HALO_WDT_EN_MASK, 0);
3096}
3097
3098int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
3099 struct snd_kcontrol *kcontrol, int event)
2767{ 3100{
2768 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 3101 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2769 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3102 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
@@ -2772,7 +3105,6 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
2772 3105
2773 switch (event) { 3106 switch (event) {
2774 case SND_SOC_DAPM_PRE_PMU: 3107 case SND_SOC_DAPM_PRE_PMU:
2775 wm_adsp2_set_dspclk(dsp, freq);
2776 queue_work(system_unbound_wq, &dsp->boot_work); 3108 queue_work(system_unbound_wq, &dsp->boot_work);
2777 break; 3109 break;
2778 case SND_SOC_DAPM_PRE_PMD: 3110 case SND_SOC_DAPM_PRE_PMD:
@@ -2785,8 +3117,8 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
2785 3117
2786 dsp->booted = false; 3118 dsp->booted = false;
2787 3119
2788 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 3120 if (dsp->ops->disable_memory)
2789 ADSP2_MEM_ENA, 0); 3121 dsp->ops->disable_memory(dsp);
2790 3122
2791 list_for_each_entry(ctl, &dsp->ctl_list, list) 3123 list_for_each_entry(ctl, &dsp->ctl_list, list)
2792 ctl->enabled = 0; 3124 ctl->enabled = 0;
@@ -2803,10 +3135,23 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
2803 3135
2804 return 0; 3136 return 0;
2805} 3137}
2806EXPORT_SYMBOL_GPL(wm_adsp2_early_event); 3138EXPORT_SYMBOL_GPL(wm_adsp_early_event);
3139
3140static int wm_adsp2_start_core(struct wm_adsp *dsp)
3141{
3142 return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3143 ADSP2_CORE_ENA | ADSP2_START,
3144 ADSP2_CORE_ENA | ADSP2_START);
3145}
2807 3146
2808int wm_adsp2_event(struct snd_soc_dapm_widget *w, 3147static void wm_adsp2_stop_core(struct wm_adsp *dsp)
2809 struct snd_kcontrol *kcontrol, int event) 3148{
3149 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
3150 ADSP2_CORE_ENA | ADSP2_START, 0);
3151}
3152
3153int wm_adsp_event(struct snd_soc_dapm_widget *w,
3154 struct snd_kcontrol *kcontrol, int event)
2810{ 3155{
2811 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 3156 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
2812 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component); 3157 struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
@@ -2824,23 +3169,31 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
2824 goto err; 3169 goto err;
2825 } 3170 }
2826 3171
2827 ret = wm_adsp2_ena(dsp); 3172 if (dsp->ops->enable_core) {
2828 if (ret != 0) 3173 ret = dsp->ops->enable_core(dsp);
2829 goto err; 3174 if (ret != 0)
3175 goto err;
3176 }
2830 3177
2831 /* Sync set controls */ 3178 /* Sync set controls */
2832 ret = wm_coeff_sync_controls(dsp); 3179 ret = wm_coeff_sync_controls(dsp);
2833 if (ret != 0) 3180 if (ret != 0)
2834 goto err; 3181 goto err;
2835 3182
2836 wm_adsp2_lock(dsp, dsp->lock_regions); 3183 if (dsp->ops->lock_memory) {
3184 ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
3185 if (ret != 0) {
3186 adsp_err(dsp, "Error configuring MPU: %d\n",
3187 ret);
3188 goto err;
3189 }
3190 }
2837 3191
2838 ret = regmap_update_bits(dsp->regmap, 3192 if (dsp->ops->start_core) {
2839 dsp->base + ADSP2_CONTROL, 3193 ret = dsp->ops->start_core(dsp);
2840 ADSP2_CORE_ENA | ADSP2_START, 3194 if (ret != 0)
2841 ADSP2_CORE_ENA | ADSP2_START); 3195 goto err;
2842 if (ret != 0) 3196 }
2843 goto err;
2844 3197
2845 if (wm_adsp_fw[dsp->fw].num_caps != 0) { 3198 if (wm_adsp_fw[dsp->fw].num_caps != 0) {
2846 ret = wm_adsp_buffer_init(dsp); 3199 ret = wm_adsp_buffer_init(dsp);
@@ -2851,56 +3204,27 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
2851 dsp->running = true; 3204 dsp->running = true;
2852 3205
2853 mutex_unlock(&dsp->pwr_lock); 3206 mutex_unlock(&dsp->pwr_lock);
2854
2855 break; 3207 break;
2856 3208
2857 case SND_SOC_DAPM_PRE_PMD: 3209 case SND_SOC_DAPM_PRE_PMD:
2858 /* Tell the firmware to cleanup */ 3210 /* Tell the firmware to cleanup */
2859 wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); 3211 wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
2860 3212
2861 wm_adsp_stop_watchdog(dsp); 3213 if (dsp->ops->stop_watchdog)
3214 dsp->ops->stop_watchdog(dsp);
2862 3215
2863 /* Log firmware state, it can be useful for analysis */ 3216 /* Log firmware state, it can be useful for analysis */
2864 switch (dsp->rev) { 3217 if (dsp->ops->show_fw_status)
2865 case 0: 3218 dsp->ops->show_fw_status(dsp);
2866 wm_adsp2_show_fw_status(dsp);
2867 break;
2868 default:
2869 wm_adsp2v2_show_fw_status(dsp);
2870 break;
2871 }
2872 3219
2873 mutex_lock(&dsp->pwr_lock); 3220 mutex_lock(&dsp->pwr_lock);
2874 3221
2875 dsp->running = false; 3222 dsp->running = false;
2876 3223
2877 regmap_update_bits(dsp->regmap, 3224 if (dsp->ops->stop_core)
2878 dsp->base + ADSP2_CONTROL, 3225 dsp->ops->stop_core(dsp);
2879 ADSP2_CORE_ENA | ADSP2_START, 0); 3226 if (dsp->ops->disable_core)
2880 3227 dsp->ops->disable_core(dsp);
2881 /* Make sure DMAs are quiesced */
2882 switch (dsp->rev) {
2883 case 0:
2884 regmap_write(dsp->regmap,
2885 dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2886 regmap_write(dsp->regmap,
2887 dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2888 regmap_write(dsp->regmap,
2889 dsp->base + ADSP2_WDMA_CONFIG_2, 0);
2890
2891 regmap_update_bits(dsp->regmap,
2892 dsp->base + ADSP2_CONTROL,
2893 ADSP2_SYS_ENA, 0);
2894 break;
2895 default:
2896 regmap_write(dsp->regmap,
2897 dsp->base + ADSP2_RDMA_CONFIG_1, 0);
2898 regmap_write(dsp->regmap,
2899 dsp->base + ADSP2_WDMA_CONFIG_1, 0);
2900 regmap_write(dsp->regmap,
2901 dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
2902 break;
2903 }
2904 3228
2905 if (wm_adsp_fw[dsp->fw].num_caps != 0) 3229 if (wm_adsp_fw[dsp->fw].num_caps != 0)
2906 wm_adsp_buffer_free(dsp); 3230 wm_adsp_buffer_free(dsp);
@@ -2918,12 +3242,31 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
2918 3242
2919 return 0; 3243 return 0;
2920err: 3244err:
2921 regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, 3245 if (dsp->ops->stop_core)
2922 ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); 3246 dsp->ops->stop_core(dsp);
3247 if (dsp->ops->disable_core)
3248 dsp->ops->disable_core(dsp);
2923 mutex_unlock(&dsp->pwr_lock); 3249 mutex_unlock(&dsp->pwr_lock);
2924 return ret; 3250 return ret;
2925} 3251}
2926EXPORT_SYMBOL_GPL(wm_adsp2_event); 3252EXPORT_SYMBOL_GPL(wm_adsp_event);
3253
3254static int wm_halo_start_core(struct wm_adsp *dsp)
3255{
3256 return regmap_update_bits(dsp->regmap,
3257 dsp->base + HALO_CCM_CORE_CONTROL,
3258 HALO_CORE_EN, HALO_CORE_EN);
3259}
3260
3261static void wm_halo_stop_core(struct wm_adsp *dsp)
3262{
3263 regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
3264 HALO_CORE_EN, 0);
3265
3266 /* reset halo core with CORE_SOFT_RESET */
3267 regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
3268 HALO_CORE_SOFT_RESET_MASK, 1);
3269}
2927 3270
2928int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component) 3271int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
2929{ 3272{
@@ -2969,17 +3312,39 @@ int wm_adsp2_init(struct wm_adsp *dsp)
2969 "Failed to clear memory retention: %d\n", ret); 3312 "Failed to clear memory retention: %d\n", ret);
2970 return ret; 3313 return ret;
2971 } 3314 }
3315
3316 dsp->ops = &wm_adsp2_ops[0];
3317 break;
3318 case 1:
3319 dsp->ops = &wm_adsp2_ops[1];
2972 break; 3320 break;
2973 default: 3321 default:
3322 dsp->ops = &wm_adsp2_ops[2];
2974 break; 3323 break;
2975 } 3324 }
2976 3325
2977 INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); 3326 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
2978 3327
2979 return 0; 3328 return 0;
2980} 3329}
2981EXPORT_SYMBOL_GPL(wm_adsp2_init); 3330EXPORT_SYMBOL_GPL(wm_adsp2_init);
2982 3331
3332int wm_halo_init(struct wm_adsp *dsp)
3333{
3334 int ret;
3335
3336 ret = wm_adsp_common_init(dsp);
3337 if (ret)
3338 return ret;
3339
3340 dsp->ops = &wm_halo_ops;
3341
3342 INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
3343
3344 return 0;
3345}
3346EXPORT_SYMBOL_GPL(wm_halo_init);
3347
2983void wm_adsp2_remove(struct wm_adsp *dsp) 3348void wm_adsp2_remove(struct wm_adsp *dsp)
2984{ 3349{
2985 struct wm_coeff_ctl *ctl; 3350 struct wm_coeff_ctl *ctl;
@@ -3016,7 +3381,7 @@ static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
3016 return -EINVAL; 3381 return -EINVAL;
3017 3382
3018 compr->buf = buf; 3383 compr->buf = buf;
3019 compr->buf->compr = compr; 3384 buf->compr = compr;
3020 3385
3021 return 0; 3386 return 0;
3022} 3387}
@@ -3224,7 +3589,7 @@ static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type,
3224 if (!mem) 3589 if (!mem)
3225 return -EINVAL; 3590 return -EINVAL;
3226 3591
3227 reg = wm_adsp_region_to_reg(mem, mem_addr); 3592 reg = dsp->ops->region_to_reg(mem, mem_addr);
3228 3593
3229 ret = regmap_raw_read(dsp->regmap, reg, data, 3594 ret = regmap_raw_read(dsp->regmap, reg, data,
3230 sizeof(*data) * num_words); 3595 sizeof(*data) * num_words);
@@ -3252,7 +3617,7 @@ static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type,
3252 if (!mem) 3617 if (!mem)
3253 return -EINVAL; 3618 return -EINVAL;
3254 3619
3255 reg = wm_adsp_region_to_reg(mem, mem_addr); 3620 reg = dsp->ops->region_to_reg(mem, mem_addr);
3256 3621
3257 data = cpu_to_be32(data & 0x00ffffffu); 3622 data = cpu_to_be32(data & 0x00ffffffu);
3258 3623
@@ -3363,7 +3728,7 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
3363 return -ENOMEM; 3728 return -ENOMEM;
3364 3729
3365 alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); 3730 alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
3366 xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32); 3731 xmalg = dsp->ops->sys_config_size / sizeof(__be32);
3367 3732
3368 addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); 3733 addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
3369 ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); 3734 ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
@@ -3522,8 +3887,7 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp)
3522 struct wm_adsp_compr_buf *buf, *tmp; 3887 struct wm_adsp_compr_buf *buf, *tmp;
3523 3888
3524 list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) { 3889 list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
3525 if (buf->compr) 3890 wm_adsp_compr_detach(buf->compr);
3526 wm_adsp_compr_detach(buf->compr);
3527 3891
3528 kfree(buf->name); 3892 kfree(buf->name);
3529 kfree(buf->regions); 3893 kfree(buf->regions);
@@ -3728,7 +4092,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
3728 4092
3729 buf = compr->buf; 4093 buf = compr->buf;
3730 4094
3731 if (!compr->buf || compr->buf->error) { 4095 if (dsp->fatal_error || !buf || buf->error) {
3732 snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); 4096 snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
3733 ret = -EIO; 4097 ret = -EIO;
3734 goto out; 4098 goto out;
@@ -3748,7 +4112,7 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream,
3748 if (buf->avail < wm_adsp_compr_frag_words(compr)) { 4112 if (buf->avail < wm_adsp_compr_frag_words(compr)) {
3749 ret = wm_adsp_buffer_get_error(buf); 4113 ret = wm_adsp_buffer_get_error(buf);
3750 if (ret < 0) { 4114 if (ret < 0) {
3751 if (compr->buf->error) 4115 if (buf->error)
3752 snd_compr_stop_error(stream, 4116 snd_compr_stop_error(stream,
3753 SNDRV_PCM_STATE_XRUN); 4117 SNDRV_PCM_STATE_XRUN);
3754 goto out; 4118 goto out;
@@ -3832,12 +4196,13 @@ static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
3832static int wm_adsp_compr_read(struct wm_adsp_compr *compr, 4196static int wm_adsp_compr_read(struct wm_adsp_compr *compr,
3833 char __user *buf, size_t count) 4197 char __user *buf, size_t count)
3834{ 4198{
4199 struct wm_adsp *dsp = compr->dsp;
3835 int ntotal = 0; 4200 int ntotal = 0;
3836 int nwords, nbytes; 4201 int nwords, nbytes;
3837 4202
3838 compr_dbg(compr, "Requested read of %zu bytes\n", count); 4203 compr_dbg(compr, "Requested read of %zu bytes\n", count);
3839 4204
3840 if (!compr->buf || compr->buf->error) { 4205 if (dsp->fatal_error || !compr->buf || compr->buf->error) {
3841 snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); 4206 snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
3842 return -EIO; 4207 return -EIO;
3843 } 4208 }
@@ -3891,37 +4256,6 @@ int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf,
3891} 4256}
3892EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); 4257EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
3893 4258
3894int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
3895{
3896 struct regmap *regmap = dsp->regmap;
3897 unsigned int code0, code1, lock_reg;
3898
3899 if (!(lock_regions & WM_ADSP2_REGION_ALL))
3900 return 0;
3901
3902 lock_regions &= WM_ADSP2_REGION_ALL;
3903 lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
3904
3905 while (lock_regions) {
3906 code0 = code1 = 0;
3907 if (lock_regions & BIT(0)) {
3908 code0 = ADSP2_LOCK_CODE_0;
3909 code1 = ADSP2_LOCK_CODE_1;
3910 }
3911 if (lock_regions & BIT(1)) {
3912 code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
3913 code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
3914 }
3915 regmap_write(regmap, lock_reg, code0);
3916 regmap_write(regmap, lock_reg, code1);
3917 lock_regions >>= 2;
3918 lock_reg += 2;
3919 }
3920
3921 return 0;
3922}
3923EXPORT_SYMBOL_GPL(wm_adsp2_lock);
3924
3925static void wm_adsp_fatal_error(struct wm_adsp *dsp) 4259static void wm_adsp_fatal_error(struct wm_adsp *dsp)
3926{ 4260{
3927 struct wm_adsp_compr *compr; 4261 struct wm_adsp_compr *compr;
@@ -3929,11 +4263,8 @@ static void wm_adsp_fatal_error(struct wm_adsp *dsp)
3929 dsp->fatal_error = true; 4263 dsp->fatal_error = true;
3930 4264
3931 list_for_each_entry(compr, &dsp->compr_list, list) { 4265 list_for_each_entry(compr, &dsp->compr_list, list) {
3932 if (compr->stream) { 4266 if (compr->stream)
3933 snd_compr_stop_error(compr->stream,
3934 SNDRV_PCM_STATE_XRUN);
3935 snd_compr_fragment_elapsed(compr->stream); 4267 snd_compr_fragment_elapsed(compr->stream);
3936 }
3937 } 4268 }
3938} 4269}
3939 4270
@@ -3954,7 +4285,7 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
3954 4285
3955 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { 4286 if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
3956 adsp_err(dsp, "watchdog timeout error\n"); 4287 adsp_err(dsp, "watchdog timeout error\n");
3957 wm_adsp_stop_watchdog(dsp); 4288 dsp->ops->stop_watchdog(dsp);
3958 wm_adsp_fatal_error(dsp); 4289 wm_adsp_fatal_error(dsp);
3959 } 4290 }
3960 4291
@@ -4002,4 +4333,159 @@ error:
4002} 4333}
4003EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); 4334EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
4004 4335
4336irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp)
4337{
4338 struct regmap *regmap = dsp->regmap;
4339 unsigned int fault[6];
4340 struct reg_sequence clear[] = {
4341 { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 },
4342 { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 },
4343 { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 },
4344 };
4345 int ret;
4346
4347 mutex_lock(&dsp->pwr_lock);
4348
4349 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
4350 fault);
4351 if (ret) {
4352 adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
4353 goto exit_unlock;
4354 }
4355
4356 adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
4357 *fault & HALO_AHBM_FLAGS_ERR_MASK,
4358 (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
4359 HALO_AHBM_CORE_ERR_ADDR_SHIFT);
4360
4361 ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
4362 fault);
4363 if (ret) {
4364 adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
4365 goto exit_unlock;
4366 }
4367
4368 adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
4369
4370 ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
4371 fault, ARRAY_SIZE(fault));
4372 if (ret) {
4373 adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
4374 goto exit_unlock;
4375 }
4376
4377 adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
4378 adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
4379 adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
4380
4381 ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
4382 if (ret)
4383 adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
4384
4385exit_unlock:
4386 mutex_unlock(&dsp->pwr_lock);
4387
4388 return IRQ_HANDLED;
4389}
4390EXPORT_SYMBOL_GPL(wm_halo_bus_error);
4391
4392irqreturn_t wm_halo_wdt_expire(int irq, void *data)
4393{
4394 struct wm_adsp *dsp = data;
4395
4396 mutex_lock(&dsp->pwr_lock);
4397
4398 adsp_warn(dsp, "WDT Expiry Fault\n");
4399 dsp->ops->stop_watchdog(dsp);
4400 wm_adsp_fatal_error(dsp);
4401
4402 mutex_unlock(&dsp->pwr_lock);
4403
4404 return IRQ_HANDLED;
4405}
4406EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
4407
4408static struct wm_adsp_ops wm_adsp1_ops = {
4409 .validate_version = wm_adsp_validate_version,
4410 .parse_sizes = wm_adsp1_parse_sizes,
4411 .region_to_reg = wm_adsp_region_to_reg,
4412};
4413
4414static struct wm_adsp_ops wm_adsp2_ops[] = {
4415 {
4416 .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4417 .parse_sizes = wm_adsp2_parse_sizes,
4418 .validate_version = wm_adsp_validate_version,
4419 .setup_algs = wm_adsp2_setup_algs,
4420 .region_to_reg = wm_adsp_region_to_reg,
4421
4422 .show_fw_status = wm_adsp2_show_fw_status,
4423
4424 .enable_memory = wm_adsp2_enable_memory,
4425 .disable_memory = wm_adsp2_disable_memory,
4426
4427 .enable_core = wm_adsp2_enable_core,
4428 .disable_core = wm_adsp2_disable_core,
4429
4430 .start_core = wm_adsp2_start_core,
4431 .stop_core = wm_adsp2_stop_core,
4432
4433 },
4434 {
4435 .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4436 .parse_sizes = wm_adsp2_parse_sizes,
4437 .validate_version = wm_adsp_validate_version,
4438 .setup_algs = wm_adsp2_setup_algs,
4439 .region_to_reg = wm_adsp_region_to_reg,
4440
4441 .show_fw_status = wm_adsp2v2_show_fw_status,
4442
4443 .enable_memory = wm_adsp2_enable_memory,
4444 .disable_memory = wm_adsp2_disable_memory,
4445 .lock_memory = wm_adsp2_lock,
4446
4447 .enable_core = wm_adsp2v2_enable_core,
4448 .disable_core = wm_adsp2v2_disable_core,
4449
4450 .start_core = wm_adsp2_start_core,
4451 .stop_core = wm_adsp2_stop_core,
4452 },
4453 {
4454 .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
4455 .parse_sizes = wm_adsp2_parse_sizes,
4456 .validate_version = wm_adsp_validate_version,
4457 .setup_algs = wm_adsp2_setup_algs,
4458 .region_to_reg = wm_adsp_region_to_reg,
4459
4460 .show_fw_status = wm_adsp2v2_show_fw_status,
4461 .stop_watchdog = wm_adsp_stop_watchdog,
4462
4463 .enable_memory = wm_adsp2_enable_memory,
4464 .disable_memory = wm_adsp2_disable_memory,
4465 .lock_memory = wm_adsp2_lock,
4466
4467 .enable_core = wm_adsp2v2_enable_core,
4468 .disable_core = wm_adsp2v2_disable_core,
4469
4470 .start_core = wm_adsp2_start_core,
4471 .stop_core = wm_adsp2_stop_core,
4472 },
4473};
4474
4475static struct wm_adsp_ops wm_halo_ops = {
4476 .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr),
4477 .parse_sizes = wm_adsp2_parse_sizes,
4478 .validate_version = wm_halo_validate_version,
4479 .setup_algs = wm_halo_setup_algs,
4480 .region_to_reg = wm_halo_region_to_reg,
4481
4482 .show_fw_status = wm_halo_show_fw_status,
4483 .stop_watchdog = wm_halo_stop_watchdog,
4484
4485 .lock_memory = wm_halo_configure_mpu,
4486
4487 .start_core = wm_halo_start_core,
4488 .stop_core = wm_halo_stop_core,
4489};
4490
4005MODULE_LICENSE("GPL v2"); 4491MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 8f09b4419a91..3631c9200c5d 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -54,6 +54,7 @@ struct wm_adsp_alg_region {
54 54
55struct wm_adsp_compr; 55struct wm_adsp_compr;
56struct wm_adsp_compr_buf; 56struct wm_adsp_compr_buf;
57struct wm_adsp_ops;
57 58
58struct wm_adsp { 59struct wm_adsp {
59 const char *part; 60 const char *part;
@@ -66,7 +67,10 @@ struct wm_adsp {
66 struct regmap *regmap; 67 struct regmap *regmap;
67 struct snd_soc_component *component; 68 struct snd_soc_component *component;
68 69
70 struct wm_adsp_ops *ops;
71
69 unsigned int base; 72 unsigned int base;
73 unsigned int base_sysinfo;
70 unsigned int sysclk_reg; 74 unsigned int sysclk_reg;
71 unsigned int sysclk_mask; 75 unsigned int sysclk_mask;
72 unsigned int sysclk_shift; 76 unsigned int sysclk_shift;
@@ -75,6 +79,7 @@ struct wm_adsp {
75 79
76 unsigned int fw_id; 80 unsigned int fw_id;
77 unsigned int fw_id_version; 81 unsigned int fw_id_version;
82 unsigned int fw_vendor_id;
78 83
79 const struct wm_adsp_region *mem; 84 const struct wm_adsp_region *mem;
80 int num_mems; 85 int num_mems;
@@ -106,6 +111,32 @@ struct wm_adsp {
106 111
107}; 112};
108 113
114struct wm_adsp_ops {
115 unsigned int sys_config_size;
116
117 bool (*validate_version)(struct wm_adsp *dsp, unsigned int version);
118 unsigned int (*parse_sizes)(struct wm_adsp *dsp,
119 const char * const file,
120 unsigned int pos,
121 const struct firmware *firmware);
122 int (*setup_algs)(struct wm_adsp *dsp);
123 unsigned int (*region_to_reg)(struct wm_adsp_region const *mem,
124 unsigned int offset);
125
126 void (*show_fw_status)(struct wm_adsp *dsp);
127 void (*stop_watchdog)(struct wm_adsp *dsp);
128
129 int (*enable_memory)(struct wm_adsp *dsp);
130 void (*disable_memory)(struct wm_adsp *dsp);
131 int (*lock_memory)(struct wm_adsp *dsp, unsigned int lock_regions);
132
133 int (*enable_core)(struct wm_adsp *dsp);
134 void (*disable_core)(struct wm_adsp *dsp);
135
136 int (*start_core)(struct wm_adsp *dsp);
137 void (*stop_core)(struct wm_adsp *dsp);
138};
139
109#define WM_ADSP1(wname, num) \ 140#define WM_ADSP1(wname, num) \
110 SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ 141 SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
111 wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) 142 wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
@@ -121,7 +152,7 @@ struct wm_adsp {
121 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ 152 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
122 .subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \ 153 .subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \
123{ .id = snd_soc_dapm_out_drv, .name = wname, \ 154{ .id = snd_soc_dapm_out_drv, .name = wname, \
124 .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ 155 .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp_event, \
125 .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } 156 .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
126 157
127#define WM_ADSP_FW_CONTROL(dspname, num) \ 158#define WM_ADSP_FW_CONTROL(dspname, num) \
@@ -135,17 +166,22 @@ int wm_adsp2_init(struct wm_adsp *dsp);
135void wm_adsp2_remove(struct wm_adsp *dsp); 166void wm_adsp2_remove(struct wm_adsp *dsp);
136int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component); 167int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component);
137int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component); 168int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component);
169int wm_halo_init(struct wm_adsp *dsp);
170
138int wm_adsp1_event(struct snd_soc_dapm_widget *w, 171int wm_adsp1_event(struct snd_soc_dapm_widget *w,
139 struct snd_kcontrol *kcontrol, int event); 172 struct snd_kcontrol *kcontrol, int event);
140int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
141 struct snd_kcontrol *kcontrol, int event,
142 unsigned int freq);
143 173
144int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions); 174int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
175 struct snd_kcontrol *kcontrol, int event);
176
145irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp); 177irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
178irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp);
179irqreturn_t wm_halo_wdt_expire(int irq, void *data);
146 180
147int wm_adsp2_event(struct snd_soc_dapm_widget *w, 181int wm_adsp_event(struct snd_soc_dapm_widget *w,
148 struct snd_kcontrol *kcontrol, int event); 182 struct snd_kcontrol *kcontrol, int event);
183
184int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq);
149 185
150int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, 186int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
151 struct snd_ctl_elem_value *ucontrol); 187 struct snd_ctl_elem_value *ucontrol);
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index 0c3f50acb8b1..14b2d1a2fc59 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -73,6 +73,14 @@ struct wmfw_id_hdr {
73 __be32 ver; 73 __be32 ver;
74} __packed; 74} __packed;
75 75
76struct wmfw_v3_id_hdr {
77 __be32 core_id;
78 __be32 block_rev;
79 __be32 vendor_id;
80 __be32 id;
81 __be32 ver;
82} __packed;
83
76struct wmfw_adsp1_id_hdr { 84struct wmfw_adsp1_id_hdr {
77 struct wmfw_id_hdr fw; 85 struct wmfw_id_hdr fw;
78 __be32 zm; 86 __be32 zm;
@@ -88,6 +96,15 @@ struct wmfw_adsp2_id_hdr {
88 __be32 n_algs; 96 __be32 n_algs;
89} __packed; 97} __packed;
90 98
99struct wmfw_halo_id_hdr {
100 struct wmfw_v3_id_hdr fw;
101 __be32 xm_base;
102 __be32 xm_size;
103 __be32 ym_base;
104 __be32 ym_size;
105 __be32 n_algs;
106} __packed;
107
91struct wmfw_alg_hdr { 108struct wmfw_alg_hdr {
92 __be32 id; 109 __be32 id;
93 __be32 ver; 110 __be32 ver;
@@ -106,6 +123,14 @@ struct wmfw_adsp2_alg_hdr {
106 __be32 ym; 123 __be32 ym;
107} __packed; 124} __packed;
108 125
126struct wmfw_halo_alg_hdr {
127 struct wmfw_alg_hdr alg;
128 __be32 xm_base;
129 __be32 xm_size;
130 __be32 ym_base;
131 __be32 ym_size;
132} __packed;
133
109struct wmfw_adsp_alg_data { 134struct wmfw_adsp_alg_data {
110 __le32 id; 135 __le32 id;
111 u8 name[WMFW_MAX_ALG_NAME]; 136 u8 name[WMFW_MAX_ALG_NAME];
@@ -154,6 +179,7 @@ struct wmfw_coeff_item {
154 179
155#define WMFW_ADSP1 1 180#define WMFW_ADSP1 1
156#define WMFW_ADSP2 2 181#define WMFW_ADSP2 2
182#define WMFW_HALO 4
157 183
158#define WMFW_ABSOLUTE 0xf0 184#define WMFW_ABSOLUTE 0xf0
159#define WMFW_ALGORITHM_DATA 0xf2 185#define WMFW_ALGORITHM_DATA 0xf2
@@ -169,4 +195,8 @@ struct wmfw_coeff_item {
169#define WMFW_ADSP2_XM 5 195#define WMFW_ADSP2_XM 5
170#define WMFW_ADSP2_YM 6 196#define WMFW_ADSP2_YM 6
171 197
198#define WMFW_HALO_PM_PACKED 0x10
199#define WMFW_HALO_XM_PACKED 0x11
200#define WMFW_HALO_YM_PACKED 0x12
201
172#endif 202#endif
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 7b1d9970be8b..55ed47c599e2 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -24,6 +24,13 @@ config SND_SOC_FSL_SAI
24 This option is only useful for out-of-tree drivers since 24 This option is only useful for out-of-tree drivers since
25 in-tree drivers select it automatically. 25 in-tree drivers select it automatically.
26 26
27config SND_SOC_FSL_AUDMIX
28 tristate "Audio Mixer (AUDMIX) module support"
29 select REGMAP_MMIO
30 help
31 Say Y if you want to add Audio Mixer (AUDMIX)
32 support for the NXP iMX CPUs.
33
27config SND_SOC_FSL_SSI 34config SND_SOC_FSL_SSI
28 tristate "Synchronous Serial Interface module (SSI) support" 35 tristate "Synchronous Serial Interface module (SSI) support"
29 select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n 36 select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
@@ -182,16 +189,17 @@ config SND_MPC52xx_SOC_EFIKA
182 189
183endif # SND_POWERPC_SOC 190endif # SND_POWERPC_SOC
184 191
192config SND_SOC_IMX_PCM_FIQ
193 tristate
194 default y if SND_SOC_IMX_SSI=y && (SND_SOC_FSL_SSI=m || SND_SOC_FSL_SPDIF=m) && (MXC_TZIC || MXC_AVIC)
195 select FIQ
196
185if SND_IMX_SOC 197if SND_IMX_SOC
186 198
187config SND_SOC_IMX_SSI 199config SND_SOC_IMX_SSI
188 tristate 200 tristate
189 select SND_SOC_FSL_UTILS 201 select SND_SOC_FSL_UTILS
190 202
191config SND_SOC_IMX_PCM_FIQ
192 tristate
193 select FIQ
194
195comment "SoC Audio support for Freescale i.MX boards:" 203comment "SoC Audio support for Freescale i.MX boards:"
196 204
197config SND_MXC_SOC_WM1133_EV1 205config SND_MXC_SOC_WM1133_EV1
@@ -296,6 +304,15 @@ config SND_SOC_FSL_ASOC_CARD
296 CS4271, CS4272 and SGTL5000. 304 CS4271, CS4272 and SGTL5000.
297 Say Y if you want to add support for Freescale Generic ASoC Sound Card. 305 Say Y if you want to add support for Freescale Generic ASoC Sound Card.
298 306
307config SND_SOC_IMX_AUDMIX
308 tristate "SoC Audio support for i.MX boards with AUDMIX"
309 select SND_SOC_FSL_AUDMIX
310 select SND_SOC_FSL_SAI
311 help
312 SoC Audio support for i.MX boards with Audio Mixer
313 Say Y if you want to add support for SoC audio on an i.MX board with
314 an Audio Mixer.
315
299endif # SND_IMX_SOC 316endif # SND_IMX_SOC
300 317
301endmenu 318endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 3c0ff315b971..c0dd04422fe9 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -12,6 +12,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o
12obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o 12obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
13 13
14# Freescale SSI/DMA/SAI/SPDIF Support 14# Freescale SSI/DMA/SAI/SPDIF Support
15snd-soc-fsl-audmix-objs := fsl_audmix.o
15snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o 16snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
16snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o 17snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
17snd-soc-fsl-sai-objs := fsl_sai.o 18snd-soc-fsl-sai-objs := fsl_sai.o
@@ -22,6 +23,8 @@ snd-soc-fsl-esai-objs := fsl_esai.o
22snd-soc-fsl-micfil-objs := fsl_micfil.o 23snd-soc-fsl-micfil-objs := fsl_micfil.o
23snd-soc-fsl-utils-objs := fsl_utils.o 24snd-soc-fsl-utils-objs := fsl_utils.o
24snd-soc-fsl-dma-objs := fsl_dma.o 25snd-soc-fsl-dma-objs := fsl_dma.o
26
27obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
25obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o 28obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
26obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o 29obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
27obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o 30obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
@@ -59,6 +62,7 @@ snd-soc-imx-es8328-objs := imx-es8328.o
59snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o 62snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
60snd-soc-imx-spdif-objs := imx-spdif.o 63snd-soc-imx-spdif-objs := imx-spdif.o
61snd-soc-imx-mc13783-objs := imx-mc13783.o 64snd-soc-imx-mc13783-objs := imx-mc13783.o
65snd-soc-imx-audmix-objs := imx-audmix.o
62 66
63obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o 67obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
64obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o 68obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
@@ -68,3 +72,4 @@ obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
68obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o 72obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
69obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o 73obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
70obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o 74obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
75obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 191426a6d9ad..d648268cb454 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -1,19 +1,13 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode 2//
3 * 3// eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode
4 * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com> 4//
5 * 5// Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com>
6 * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c 6//
7 * which is Copyright 2009 Simtec Electronics 7// based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
8 * and on sound/soc/imx/phycore-ac97.c which is 8// which is Copyright 2009 Simtec Electronics
9 * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 9// and on sound/soc/imx/phycore-ac97.c which is
10 * 10// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 */
17 11
18#include <linux/errno.h> 12#include <linux/errno.h>
19#include <linux/module.h> 13#include <linux/module.h>
@@ -118,13 +112,13 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
118 if (ret) { 112 if (ret) {
119 dev_err(&pdev->dev, 113 dev_err(&pdev->dev,
120 "fsl,mux-int-port node missing or invalid.\n"); 114 "fsl,mux-int-port node missing or invalid.\n");
121 return ret; 115 goto err;
122 } 116 }
123 ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port); 117 ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port);
124 if (ret) { 118 if (ret) {
125 dev_err(&pdev->dev, 119 dev_err(&pdev->dev,
126 "fsl,mux-ext-port node missing or invalid.\n"); 120 "fsl,mux-ext-port node missing or invalid.\n");
127 return ret; 121 goto err;
128 } 122 }
129 123
130 /* 124 /*
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
new file mode 100644
index 000000000000..3897a54a11fe
--- /dev/null
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -0,0 +1,578 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * NXP AUDMIX ALSA SoC Digital Audio Interface (DAI) driver
4 *
5 * Copyright 2017 NXP
6 */
7
8#include <linux/clk.h>
9#include <linux/module.h>
10#include <linux/of_platform.h>
11#include <linux/pm_runtime.h>
12#include <sound/soc.h>
13#include <sound/pcm_params.h>
14
15#include "fsl_audmix.h"
16
17#define SOC_ENUM_SINGLE_S(xreg, xshift, xtexts) \
18 SOC_ENUM_SINGLE(xreg, xshift, ARRAY_SIZE(xtexts), xtexts)
19
20static const char
21 *tdm_sel[] = { "TDM1", "TDM2", },
22 *mode_sel[] = { "Disabled", "TDM1", "TDM2", "Mixed", },
23 *width_sel[] = { "16b", "18b", "20b", "24b", "32b", },
24 *endis_sel[] = { "Disabled", "Enabled", },
25 *updn_sel[] = { "Downward", "Upward", },
26 *mask_sel[] = { "Unmask", "Mask", };
27
28static const struct soc_enum fsl_audmix_enum[] = {
29/* FSL_AUDMIX_CTR enums */
30SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_MIXCLK_SHIFT, tdm_sel),
31SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_OUTSRC_SHIFT, mode_sel),
32SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_OUTWIDTH_SHIFT, width_sel),
33SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_MASKRTDF_SHIFT, mask_sel),
34SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_MASKCKDF_SHIFT, mask_sel),
35SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_SYNCMODE_SHIFT, endis_sel),
36SOC_ENUM_SINGLE_S(FSL_AUDMIX_CTR, FSL_AUDMIX_CTR_SYNCSRC_SHIFT, tdm_sel),
37/* FSL_AUDMIX_ATCR0 enums */
38SOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR0, 0, endis_sel),
39SOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR0, 1, updn_sel),
40/* FSL_AUDMIX_ATCR1 enums */
41SOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR1, 0, endis_sel),
42SOC_ENUM_SINGLE_S(FSL_AUDMIX_ATCR1, 1, updn_sel),
43};
44
45struct fsl_audmix_state {
46 u8 tdms;
47 u8 clk;
48 char msg[64];
49};
50
51static const struct fsl_audmix_state prms[4][4] = {{
52 /* DIS->DIS, do nothing */
53 { .tdms = 0, .clk = 0, .msg = "" },
54 /* DIS->TDM1*/
55 { .tdms = 1, .clk = 1, .msg = "DIS->TDM1: TDM1 not started!\n" },
56 /* DIS->TDM2*/
57 { .tdms = 2, .clk = 2, .msg = "DIS->TDM2: TDM2 not started!\n" },
58 /* DIS->MIX */
59 { .tdms = 3, .clk = 0, .msg = "DIS->MIX: Please start both TDMs!\n" }
60}, { /* TDM1->DIS */
61 { .tdms = 1, .clk = 0, .msg = "TDM1->DIS: TDM1 not started!\n" },
62 /* TDM1->TDM1, do nothing */
63 { .tdms = 0, .clk = 0, .msg = "" },
64 /* TDM1->TDM2 */
65 { .tdms = 3, .clk = 2, .msg = "TDM1->TDM2: Please start both TDMs!\n" },
66 /* TDM1->MIX */
67 { .tdms = 3, .clk = 0, .msg = "TDM1->MIX: Please start both TDMs!\n" }
68}, { /* TDM2->DIS */
69 { .tdms = 2, .clk = 0, .msg = "TDM2->DIS: TDM2 not started!\n" },
70 /* TDM2->TDM1 */
71 { .tdms = 3, .clk = 1, .msg = "TDM2->TDM1: Please start both TDMs!\n" },
72 /* TDM2->TDM2, do nothing */
73 { .tdms = 0, .clk = 0, .msg = "" },
74 /* TDM2->MIX */
75 { .tdms = 3, .clk = 0, .msg = "TDM2->MIX: Please start both TDMs!\n" }
76}, { /* MIX->DIS */
77 { .tdms = 3, .clk = 0, .msg = "MIX->DIS: Please start both TDMs!\n" },
78 /* MIX->TDM1 */
79 { .tdms = 3, .clk = 1, .msg = "MIX->TDM1: Please start both TDMs!\n" },
80 /* MIX->TDM2 */
81 { .tdms = 3, .clk = 2, .msg = "MIX->TDM2: Please start both TDMs!\n" },
82 /* MIX->MIX, do nothing */
83 { .tdms = 0, .clk = 0, .msg = "" }
84}, };
85
86static int fsl_audmix_state_trans(struct snd_soc_component *comp,
87 unsigned int *mask, unsigned int *ctr,
88 const struct fsl_audmix_state prm)
89{
90 struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
91 /* Enforce all required TDMs are started */
92 if ((priv->tdms & prm.tdms) != prm.tdms) {
93 dev_dbg(comp->dev, "%s", prm.msg);
94 return -EINVAL;
95 }
96
97 switch (prm.clk) {
98 case 1:
99 case 2:
100 /* Set mix clock */
101 (*mask) |= FSL_AUDMIX_CTR_MIXCLK_MASK;
102 (*ctr) |= FSL_AUDMIX_CTR_MIXCLK(prm.clk - 1);
103 break;
104 default:
105 break;
106 }
107
108 return 0;
109}
110
111static int fsl_audmix_put_mix_clk_src(struct snd_kcontrol *kcontrol,
112 struct snd_ctl_elem_value *ucontrol)
113{
114 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
115 struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
116 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
117 unsigned int *item = ucontrol->value.enumerated.item;
118 unsigned int reg_val, val, mix_clk;
119 int ret = 0;
120
121 /* Get current state */
122 ret = snd_soc_component_read(comp, FSL_AUDMIX_CTR, &reg_val);
123 if (ret)
124 return ret;
125
126 mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
127 >> FSL_AUDMIX_CTR_MIXCLK_SHIFT);
128 val = snd_soc_enum_item_to_val(e, item[0]);
129
130 dev_dbg(comp->dev, "TDMs=x%08x, val=x%08x\n", priv->tdms, val);
131
132 /**
133 * Ensure the current selected mixer clock is available
134 * for configuration propagation
135 */
136 if (!(priv->tdms & BIT(mix_clk))) {
137 dev_err(comp->dev,
138 "Started TDM%d needed for config propagation!\n",
139 mix_clk + 1);
140 return -EINVAL;
141 }
142
143 if (!(priv->tdms & BIT(val))) {
144 dev_err(comp->dev,
145 "The selected clock source has no TDM%d enabled!\n",
146 val + 1);
147 return -EINVAL;
148 }
149
150 return snd_soc_put_enum_double(kcontrol, ucontrol);
151}
152
153static int fsl_audmix_put_out_src(struct snd_kcontrol *kcontrol,
154 struct snd_ctl_elem_value *ucontrol)
155{
156 struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
157 struct fsl_audmix *priv = snd_soc_component_get_drvdata(comp);
158 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
159 unsigned int *item = ucontrol->value.enumerated.item;
160 u32 out_src, mix_clk;
161 unsigned int reg_val, val, mask = 0, ctr = 0;
162 int ret = 0;
163
164 /* Get current state */
165 ret = snd_soc_component_read(comp, FSL_AUDMIX_CTR, &reg_val);
166 if (ret)
167 return ret;
168
169 /* "From" state */
170 out_src = ((reg_val & FSL_AUDMIX_CTR_OUTSRC_MASK)
171 >> FSL_AUDMIX_CTR_OUTSRC_SHIFT);
172 mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
173 >> FSL_AUDMIX_CTR_MIXCLK_SHIFT);
174
175 /* "To" state */
176 val = snd_soc_enum_item_to_val(e, item[0]);
177
178 dev_dbg(comp->dev, "TDMs=x%08x, val=x%08x\n", priv->tdms, val);
179
180 /* Check if state is changing ... */
181 if (out_src == val)
182 return 0;
183 /**
184 * Ensure the current selected mixer clock is available
185 * for configuration propagation
186 */
187 if (!(priv->tdms & BIT(mix_clk))) {
188 dev_err(comp->dev,
189 "Started TDM%d needed for config propagation!\n",
190 mix_clk + 1);
191 return -EINVAL;
192 }
193
194 /* Check state transition constraints */
195 ret = fsl_audmix_state_trans(comp, &mask, &ctr, prms[out_src][val]);
196 if (ret)
197 return ret;
198
199 /* Complete transition to new state */
200 mask |= FSL_AUDMIX_CTR_OUTSRC_MASK;
201 ctr |= FSL_AUDMIX_CTR_OUTSRC(val);
202
203 return snd_soc_component_update_bits(comp, FSL_AUDMIX_CTR, mask, ctr);
204}
205
206static const struct snd_kcontrol_new fsl_audmix_snd_controls[] = {
207 /* FSL_AUDMIX_CTR controls */
208 SOC_ENUM_EXT("Mixing Clock Source", fsl_audmix_enum[0],
209 snd_soc_get_enum_double, fsl_audmix_put_mix_clk_src),
210 SOC_ENUM_EXT("Output Source", fsl_audmix_enum[1],
211 snd_soc_get_enum_double, fsl_audmix_put_out_src),
212 SOC_ENUM("Output Width", fsl_audmix_enum[2]),
213 SOC_ENUM("Frame Rate Diff Error", fsl_audmix_enum[3]),
214 SOC_ENUM("Clock Freq Diff Error", fsl_audmix_enum[4]),
215 SOC_ENUM("Sync Mode Config", fsl_audmix_enum[5]),
216 SOC_ENUM("Sync Mode Clk Source", fsl_audmix_enum[6]),
217 /* TDM1 Attenuation controls */
218 SOC_ENUM("TDM1 Attenuation", fsl_audmix_enum[7]),
219 SOC_ENUM("TDM1 Attenuation Direction", fsl_audmix_enum[8]),
220 SOC_SINGLE("TDM1 Attenuation Step Divider", FSL_AUDMIX_ATCR0,
221 2, 0x00fff, 0),
222 SOC_SINGLE("TDM1 Attenuation Initial Value", FSL_AUDMIX_ATIVAL0,
223 0, 0x3ffff, 0),
224 SOC_SINGLE("TDM1 Attenuation Step Up Factor", FSL_AUDMIX_ATSTPUP0,
225 0, 0x3ffff, 0),
226 SOC_SINGLE("TDM1 Attenuation Step Down Factor", FSL_AUDMIX_ATSTPDN0,
227 0, 0x3ffff, 0),
228 SOC_SINGLE("TDM1 Attenuation Step Target", FSL_AUDMIX_ATSTPTGT0,
229 0, 0x3ffff, 0),
230 /* TDM2 Attenuation controls */
231 SOC_ENUM("TDM2 Attenuation", fsl_audmix_enum[9]),
232 SOC_ENUM("TDM2 Attenuation Direction", fsl_audmix_enum[10]),
233 SOC_SINGLE("TDM2 Attenuation Step Divider", FSL_AUDMIX_ATCR1,
234 2, 0x00fff, 0),
235 SOC_SINGLE("TDM2 Attenuation Initial Value", FSL_AUDMIX_ATIVAL1,
236 0, 0x3ffff, 0),
237 SOC_SINGLE("TDM2 Attenuation Step Up Factor", FSL_AUDMIX_ATSTPUP1,
238 0, 0x3ffff, 0),
239 SOC_SINGLE("TDM2 Attenuation Step Down Factor", FSL_AUDMIX_ATSTPDN1,
240 0, 0x3ffff, 0),
241 SOC_SINGLE("TDM2 Attenuation Step Target", FSL_AUDMIX_ATSTPTGT1,
242 0, 0x3ffff, 0),
243};
244
245static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
246{
247 struct snd_soc_component *comp = dai->component;
248 u32 mask = 0, ctr = 0;
249
250 /* AUDMIX is working in DSP_A format only */
251 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
252 case SND_SOC_DAIFMT_DSP_A:
253 break;
254 default:
255 return -EINVAL;
256 }
257
258 /* For playback the AUDMIX is slave, and for record is master */
259 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
260 case SND_SOC_DAIFMT_CBM_CFM:
261 case SND_SOC_DAIFMT_CBS_CFS:
262 break;
263 default:
264 return -EINVAL;
265 }
266
267 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
268 case SND_SOC_DAIFMT_IB_NF:
269 /* Output data will be written on positive edge of the clock */
270 ctr |= FSL_AUDMIX_CTR_OUTCKPOL(0);
271 break;
272 case SND_SOC_DAIFMT_NB_NF:
273 /* Output data will be written on negative edge of the clock */
274 ctr |= FSL_AUDMIX_CTR_OUTCKPOL(1);
275 break;
276 default:
277 return -EINVAL;
278 }
279
280 mask |= FSL_AUDMIX_CTR_OUTCKPOL_MASK;
281
282 return snd_soc_component_update_bits(comp, FSL_AUDMIX_CTR, mask, ctr);
283}
284
285static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
286 struct snd_soc_dai *dai)
287{
288 struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai);
289
290 /* Capture stream shall not be handled */
291 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
292 return 0;
293
294 switch (cmd) {
295 case SNDRV_PCM_TRIGGER_START:
296 case SNDRV_PCM_TRIGGER_RESUME:
297 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
298 priv->tdms |= BIT(dai->driver->id);
299 break;
300 case SNDRV_PCM_TRIGGER_STOP:
301 case SNDRV_PCM_TRIGGER_SUSPEND:
302 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
303 priv->tdms &= ~BIT(dai->driver->id);
304 break;
305 default:
306 return -EINVAL;
307 }
308
309 return 0;
310}
311
312static const struct snd_soc_dai_ops fsl_audmix_dai_ops = {
313 .set_fmt = fsl_audmix_dai_set_fmt,
314 .trigger = fsl_audmix_dai_trigger,
315};
316
317static struct snd_soc_dai_driver fsl_audmix_dai[] = {
318 {
319 .id = 0,
320 .name = "audmix-0",
321 .playback = {
322 .stream_name = "AUDMIX-Playback-0",
323 .channels_min = 8,
324 .channels_max = 8,
325 .rate_min = 8000,
326 .rate_max = 96000,
327 .rates = SNDRV_PCM_RATE_8000_96000,
328 .formats = FSL_AUDMIX_FORMATS,
329 },
330 .capture = {
331 .stream_name = "AUDMIX-Capture-0",
332 .channels_min = 8,
333 .channels_max = 8,
334 .rate_min = 8000,
335 .rate_max = 96000,
336 .rates = SNDRV_PCM_RATE_8000_96000,
337 .formats = FSL_AUDMIX_FORMATS,
338 },
339 .ops = &fsl_audmix_dai_ops,
340 },
341 {
342 .id = 1,
343 .name = "audmix-1",
344 .playback = {
345 .stream_name = "AUDMIX-Playback-1",
346 .channels_min = 8,
347 .channels_max = 8,
348 .rate_min = 8000,
349 .rate_max = 96000,
350 .rates = SNDRV_PCM_RATE_8000_96000,
351 .formats = FSL_AUDMIX_FORMATS,
352 },
353 .capture = {
354 .stream_name = "AUDMIX-Capture-1",
355 .channels_min = 8,
356 .channels_max = 8,
357 .rate_min = 8000,
358 .rate_max = 96000,
359 .rates = SNDRV_PCM_RATE_8000_96000,
360 .formats = FSL_AUDMIX_FORMATS,
361 },
362 .ops = &fsl_audmix_dai_ops,
363 },
364};
365
366static const struct snd_soc_component_driver fsl_audmix_component = {
367 .name = "fsl-audmix-dai",
368 .controls = fsl_audmix_snd_controls,
369 .num_controls = ARRAY_SIZE(fsl_audmix_snd_controls),
370};
371
372static bool fsl_audmix_readable_reg(struct device *dev, unsigned int reg)
373{
374 switch (reg) {
375 case FSL_AUDMIX_CTR:
376 case FSL_AUDMIX_STR:
377 case FSL_AUDMIX_ATCR0:
378 case FSL_AUDMIX_ATIVAL0:
379 case FSL_AUDMIX_ATSTPUP0:
380 case FSL_AUDMIX_ATSTPDN0:
381 case FSL_AUDMIX_ATSTPTGT0:
382 case FSL_AUDMIX_ATTNVAL0:
383 case FSL_AUDMIX_ATSTP0:
384 case FSL_AUDMIX_ATCR1:
385 case FSL_AUDMIX_ATIVAL1:
386 case FSL_AUDMIX_ATSTPUP1:
387 case FSL_AUDMIX_ATSTPDN1:
388 case FSL_AUDMIX_ATSTPTGT1:
389 case FSL_AUDMIX_ATTNVAL1:
390 case FSL_AUDMIX_ATSTP1:
391 return true;
392 default:
393 return false;
394 }
395}
396
397static bool fsl_audmix_writeable_reg(struct device *dev, unsigned int reg)
398{
399 switch (reg) {
400 case FSL_AUDMIX_CTR:
401 case FSL_AUDMIX_ATCR0:
402 case FSL_AUDMIX_ATIVAL0:
403 case FSL_AUDMIX_ATSTPUP0:
404 case FSL_AUDMIX_ATSTPDN0:
405 case FSL_AUDMIX_ATSTPTGT0:
406 case FSL_AUDMIX_ATCR1:
407 case FSL_AUDMIX_ATIVAL1:
408 case FSL_AUDMIX_ATSTPUP1:
409 case FSL_AUDMIX_ATSTPDN1:
410 case FSL_AUDMIX_ATSTPTGT1:
411 return true;
412 default:
413 return false;
414 }
415}
416
417static const struct reg_default fsl_audmix_reg[] = {
418 { FSL_AUDMIX_CTR, 0x00060 },
419 { FSL_AUDMIX_STR, 0x00003 },
420 { FSL_AUDMIX_ATCR0, 0x00000 },
421 { FSL_AUDMIX_ATIVAL0, 0x3FFFF },
422 { FSL_AUDMIX_ATSTPUP0, 0x2AAAA },
423 { FSL_AUDMIX_ATSTPDN0, 0x30000 },
424 { FSL_AUDMIX_ATSTPTGT0, 0x00010 },
425 { FSL_AUDMIX_ATTNVAL0, 0x00000 },
426 { FSL_AUDMIX_ATSTP0, 0x00000 },
427 { FSL_AUDMIX_ATCR1, 0x00000 },
428 { FSL_AUDMIX_ATIVAL1, 0x3FFFF },
429 { FSL_AUDMIX_ATSTPUP1, 0x2AAAA },
430 { FSL_AUDMIX_ATSTPDN1, 0x30000 },
431 { FSL_AUDMIX_ATSTPTGT1, 0x00010 },
432 { FSL_AUDMIX_ATTNVAL1, 0x00000 },
433 { FSL_AUDMIX_ATSTP1, 0x00000 },
434};
435
436static const struct regmap_config fsl_audmix_regmap_config = {
437 .reg_bits = 32,
438 .reg_stride = 4,
439 .val_bits = 32,
440 .max_register = FSL_AUDMIX_ATSTP1,
441 .reg_defaults = fsl_audmix_reg,
442 .num_reg_defaults = ARRAY_SIZE(fsl_audmix_reg),
443 .readable_reg = fsl_audmix_readable_reg,
444 .writeable_reg = fsl_audmix_writeable_reg,
445 .cache_type = REGCACHE_FLAT,
446};
447
448static const struct of_device_id fsl_audmix_ids[] = {
449 {
450 .compatible = "fsl,imx8qm-audmix",
451 .data = "imx-audmix",
452 },
453 { /* sentinel */ }
454};
455MODULE_DEVICE_TABLE(of, fsl_audmix_ids);
456
457static int fsl_audmix_probe(struct platform_device *pdev)
458{
459 struct device *dev = &pdev->dev;
460 struct fsl_audmix *priv;
461 struct resource *res;
462 const char *mdrv;
463 const struct of_device_id *of_id;
464 void __iomem *regs;
465 int ret;
466
467 of_id = of_match_device(fsl_audmix_ids, dev);
468 if (!of_id || !of_id->data)
469 return -EINVAL;
470
471 mdrv = of_id->data;
472
473 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
474 if (!priv)
475 return -ENOMEM;
476
477 /* Get the addresses */
478 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
479 regs = devm_ioremap_resource(dev, res);
480 if (IS_ERR(regs))
481 return PTR_ERR(regs);
482
483 priv->regmap = devm_regmap_init_mmio_clk(dev, "ipg", regs,
484 &fsl_audmix_regmap_config);
485 if (IS_ERR(priv->regmap)) {
486 dev_err(dev, "failed to init regmap\n");
487 return PTR_ERR(priv->regmap);
488 }
489
490 priv->ipg_clk = devm_clk_get(dev, "ipg");
491 if (IS_ERR(priv->ipg_clk)) {
492 dev_err(dev, "failed to get ipg clock\n");
493 return PTR_ERR(priv->ipg_clk);
494 }
495
496 platform_set_drvdata(pdev, priv);
497 pm_runtime_enable(dev);
498
499 ret = devm_snd_soc_register_component(dev, &fsl_audmix_component,
500 fsl_audmix_dai,
501 ARRAY_SIZE(fsl_audmix_dai));
502 if (ret) {
503 dev_err(dev, "failed to register ASoC DAI\n");
504 return ret;
505 }
506
507 priv->pdev = platform_device_register_data(dev, mdrv, 0, NULL, 0);
508 if (IS_ERR(priv->pdev)) {
509 ret = PTR_ERR(priv->pdev);
510 dev_err(dev, "failed to register platform %s: %d\n", mdrv, ret);
511 }
512
513 return ret;
514}
515
516static int fsl_audmix_remove(struct platform_device *pdev)
517{
518 struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);
519
520 if (priv->pdev)
521 platform_device_unregister(priv->pdev);
522
523 return 0;
524}
525
526#ifdef CONFIG_PM
527static int fsl_audmix_runtime_resume(struct device *dev)
528{
529 struct fsl_audmix *priv = dev_get_drvdata(dev);
530 int ret;
531
532 ret = clk_prepare_enable(priv->ipg_clk);
533 if (ret) {
534 dev_err(dev, "Failed to enable IPG clock: %d\n", ret);
535 return ret;
536 }
537
538 regcache_cache_only(priv->regmap, false);
539 regcache_mark_dirty(priv->regmap);
540
541 return regcache_sync(priv->regmap);
542}
543
544static int fsl_audmix_runtime_suspend(struct device *dev)
545{
546 struct fsl_audmix *priv = dev_get_drvdata(dev);
547
548 regcache_cache_only(priv->regmap, true);
549
550 clk_disable_unprepare(priv->ipg_clk);
551
552 return 0;
553}
554#endif /* CONFIG_PM */
555
556static const struct dev_pm_ops fsl_audmix_pm = {
557 SET_RUNTIME_PM_OPS(fsl_audmix_runtime_suspend,
558 fsl_audmix_runtime_resume,
559 NULL)
560 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
561 pm_runtime_force_resume)
562};
563
564static struct platform_driver fsl_audmix_driver = {
565 .probe = fsl_audmix_probe,
566 .remove = fsl_audmix_remove,
567 .driver = {
568 .name = "fsl-audmix",
569 .of_match_table = fsl_audmix_ids,
570 .pm = &fsl_audmix_pm,
571 },
572};
573module_platform_driver(fsl_audmix_driver);
574
575MODULE_DESCRIPTION("NXP AUDMIX ASoC DAI driver");
576MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
577MODULE_ALIAS("platform:fsl-audmix");
578MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_audmix.h b/sound/soc/fsl/fsl_audmix.h
new file mode 100644
index 000000000000..7812ffec45c5
--- /dev/null
+++ b/sound/soc/fsl/fsl_audmix.h
@@ -0,0 +1,102 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * NXP AUDMIX ALSA SoC Digital Audio Interface (DAI) driver
4 *
5 * Copyright 2017 NXP
6 */
7
8#ifndef __FSL_AUDMIX_H
9#define __FSL_AUDMIX_H
10
11#define FSL_AUDMIX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
12 SNDRV_PCM_FMTBIT_S24_LE |\
13 SNDRV_PCM_FMTBIT_S32_LE)
14/* AUDMIX Registers */
15#define FSL_AUDMIX_CTR 0x200 /* Control */
16#define FSL_AUDMIX_STR 0x204 /* Status */
17
18#define FSL_AUDMIX_ATCR0 0x208 /* Attenuation Control */
19#define FSL_AUDMIX_ATIVAL0 0x20c /* Attenuation Initial Value */
20#define FSL_AUDMIX_ATSTPUP0 0x210 /* Attenuation step up factor */
21#define FSL_AUDMIX_ATSTPDN0 0x214 /* Attenuation step down factor */
22#define FSL_AUDMIX_ATSTPTGT0 0x218 /* Attenuation step target */
23#define FSL_AUDMIX_ATTNVAL0 0x21c /* Attenuation Value */
24#define FSL_AUDMIX_ATSTP0 0x220 /* Attenuation step number */
25
26#define FSL_AUDMIX_ATCR1 0x228 /* Attenuation Control */
27#define FSL_AUDMIX_ATIVAL1 0x22c /* Attenuation Initial Value */
28#define FSL_AUDMIX_ATSTPUP1 0x230 /* Attenuation step up factor */
29#define FSL_AUDMIX_ATSTPDN1 0x234 /* Attenuation step down factor */
30#define FSL_AUDMIX_ATSTPTGT1 0x238 /* Attenuation step target */
31#define FSL_AUDMIX_ATTNVAL1 0x23c /* Attenuation Value */
32#define FSL_AUDMIX_ATSTP1 0x240 /* Attenuation step number */
33
34/* AUDMIX Control Register */
35#define FSL_AUDMIX_CTR_MIXCLK_SHIFT 0
36#define FSL_AUDMIX_CTR_MIXCLK_MASK BIT(FSL_AUDMIX_CTR_MIXCLK_SHIFT)
37#define FSL_AUDMIX_CTR_MIXCLK(i) ((i) << FSL_AUDMIX_CTR_MIXCLK_SHIFT)
38#define FSL_AUDMIX_CTR_OUTSRC_SHIFT 1
39#define FSL_AUDMIX_CTR_OUTSRC_MASK (0x3 << FSL_AUDMIX_CTR_OUTSRC_SHIFT)
40#define FSL_AUDMIX_CTR_OUTSRC(i) (((i) << FSL_AUDMIX_CTR_OUTSRC_SHIFT)\
41 & FSL_AUDMIX_CTR_OUTSRC_MASK)
42#define FSL_AUDMIX_CTR_OUTWIDTH_SHIFT 3
43#define FSL_AUDMIX_CTR_OUTWIDTH_MASK (0x7 << FSL_AUDMIX_CTR_OUTWIDTH_SHIFT)
44#define FSL_AUDMIX_CTR_OUTWIDTH(i) (((i) << FSL_AUDMIX_CTR_OUTWIDTH_SHIFT)\
45 & FSL_AUDMIX_CTR_OUTWIDTH_MASK)
46#define FSL_AUDMIX_CTR_OUTCKPOL_SHIFT 6
47#define FSL_AUDMIX_CTR_OUTCKPOL_MASK BIT(FSL_AUDMIX_CTR_OUTCKPOL_SHIFT)
48#define FSL_AUDMIX_CTR_OUTCKPOL(i) ((i) << FSL_AUDMIX_CTR_OUTCKPOL_SHIFT)
49#define FSL_AUDMIX_CTR_MASKRTDF_SHIFT 7
50#define FSL_AUDMIX_CTR_MASKRTDF_MASK BIT(FSL_AUDMIX_CTR_MASKRTDF_SHIFT)
51#define FSL_AUDMIX_CTR_MASKRTDF(i) ((i) << FSL_AUDMIX_CTR_MASKRTDF_SHIFT)
52#define FSL_AUDMIX_CTR_MASKCKDF_SHIFT 8
53#define FSL_AUDMIX_CTR_MASKCKDF_MASK BIT(FSL_AUDMIX_CTR_MASKCKDF_SHIFT)
54#define FSL_AUDMIX_CTR_MASKCKDF(i) ((i) << FSL_AUDMIX_CTR_MASKCKDF_SHIFT)
55#define FSL_AUDMIX_CTR_SYNCMODE_SHIFT 9
56#define FSL_AUDMIX_CTR_SYNCMODE_MASK BIT(FSL_AUDMIX_CTR_SYNCMODE_SHIFT)
57#define FSL_AUDMIX_CTR_SYNCMODE(i) ((i) << FSL_AUDMIX_CTR_SYNCMODE_SHIFT)
58#define FSL_AUDMIX_CTR_SYNCSRC_SHIFT 10
59#define FSL_AUDMIX_CTR_SYNCSRC_MASK BIT(FSL_AUDMIX_CTR_SYNCSRC_SHIFT)
60#define FSL_AUDMIX_CTR_SYNCSRC(i) ((i) << FSL_AUDMIX_CTR_SYNCSRC_SHIFT)
61
62/* AUDMIX Status Register */
63#define FSL_AUDMIX_STR_RATEDIFF BIT(0)
64#define FSL_AUDMIX_STR_CLKDIFF BIT(1)
65#define FSL_AUDMIX_STR_MIXSTAT_SHIFT 2
66#define FSL_AUDMIX_STR_MIXSTAT_MASK (0x3 << FSL_AUDMIX_STR_MIXSTAT_SHIFT)
67#define FSL_AUDMIX_STR_MIXSTAT(i) (((i) & FSL_AUDMIX_STR_MIXSTAT_MASK) \
68 >> FSL_AUDMIX_STR_MIXSTAT_SHIFT)
69/* AUDMIX Attenuation Control Register */
70#define FSL_AUDMIX_ATCR_AT_EN BIT(0)
71#define FSL_AUDMIX_ATCR_AT_UPDN BIT(1)
72#define FSL_AUDMIX_ATCR_ATSTPDIF_SHIFT 2
73#define FSL_AUDMIX_ATCR_ATSTPDFI_MASK \
74 (0xfff << FSL_AUDMIX_ATCR_ATSTPDIF_SHIFT)
75
76/* AUDMIX Attenuation Initial Value Register */
77#define FSL_AUDMIX_ATIVAL_ATINVAL_MASK 0x3FFFF
78
79/* AUDMIX Attenuation Step Up Factor Register */
80#define FSL_AUDMIX_ATSTPUP_ATSTEPUP_MASK 0x3FFFF
81
82/* AUDMIX Attenuation Step Down Factor Register */
83#define FSL_AUDMIX_ATSTPDN_ATSTEPDN_MASK 0x3FFFF
84
85/* AUDMIX Attenuation Step Target Register */
86#define FSL_AUDMIX_ATSTPTGT_ATSTPTG_MASK 0x3FFFF
87
88/* AUDMIX Attenuation Value Register */
89#define FSL_AUDMIX_ATTNVAL_ATCURVAL_MASK 0x3FFFF
90
91/* AUDMIX Attenuation Step Number Register */
92#define FSL_AUDMIX_ATSTP_STPCTR_MASK 0x3FFFF
93
94#define FSL_AUDMIX_MAX_DAIS 2
95struct fsl_audmix {
96 struct platform_device *pdev;
97 struct regmap *regmap;
98 struct clk *ipg_clk;
99 u8 tdms;
100};
101
102#endif /* __FSL_AUDMIX_H */
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 78871de35086..e22508301412 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -1,18 +1,14 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * Freescale DMA ALSA SoC PCM driver 2//
3 * 3// Freescale DMA ALSA SoC PCM driver
4 * Author: Timur Tabi <timur@freescale.com> 4//
5 * 5// Author: Timur Tabi <timur@freescale.com>
6 * Copyright 2007-2010 Freescale Semiconductor, Inc. 6//
7 * 7// Copyright 2007-2010 Freescale Semiconductor, Inc.
8 * This file is licensed under the terms of the GNU General Public License 8//
9 * version 2. This program is licensed "as is" without any warranty of any 9// This driver implements ASoC support for the Elo DMA controller, which is
10 * kind, whether express or implied. 10// the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
11 * 11// the PCM driver is what handles the DMA buffer.
12 * This driver implements ASoC support for the Elo DMA controller, which is
13 * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
14 * the PCM driver is what handles the DMA buffer.
15 */
16 12
17#include <linux/module.h> 13#include <linux/module.h>
18#include <linux/init.h> 14#include <linux/init.h>
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
index 78fee97e8036..f19ae765b656 100644
--- a/sound/soc/fsl/fsl_dma.h
+++ b/sound/soc/fsl/fsl_dma.h
@@ -1,9 +1,6 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * mpc8610-pcm.h - ALSA PCM interface for the Freescale MPC8610 SoC 3 * mpc8610-pcm.h - ALSA PCM interface for the Freescale MPC8610 SoC
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */ 4 */
8 5
9#ifndef _MPC8610_PCM_H 6#ifndef _MPC8610_PCM_H
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 3623aa9a6f2e..bad0dfed6b68 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -218,7 +218,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
218{ 218{
219 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); 219 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
220 struct clk *clksrc = esai_priv->extalclk; 220 struct clk *clksrc = esai_priv->extalclk;
221 bool tx = clk_id <= ESAI_HCKT_EXTAL; 221 bool tx = (clk_id <= ESAI_HCKT_EXTAL || esai_priv->synchronous);
222 bool in = dir == SND_SOC_CLOCK_IN; 222 bool in = dir == SND_SOC_CLOCK_IN;
223 u32 ratio, ecr = 0; 223 u32 ratio, ecr = 0;
224 unsigned long clk_rate; 224 unsigned long clk_rate;
@@ -251,9 +251,9 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
251 break; 251 break;
252 case ESAI_HCKT_EXTAL: 252 case ESAI_HCKT_EXTAL:
253 ecr |= ESAI_ECR_ETI; 253 ecr |= ESAI_ECR_ETI;
254 /* fall through */ 254 break;
255 case ESAI_HCKR_EXTAL: 255 case ESAI_HCKR_EXTAL:
256 ecr |= ESAI_ECR_ERI; 256 ecr |= esai_priv->synchronous ? ESAI_ECR_ETI : ESAI_ECR_ERI;
257 break; 257 break;
258 default: 258 default:
259 return -EINVAL; 259 return -EINVAL;
@@ -537,10 +537,18 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
537 537
538 bclk = params_rate(params) * slot_width * esai_priv->slots; 538 bclk = params_rate(params) * slot_width * esai_priv->slots;
539 539
540 ret = fsl_esai_set_bclk(dai, tx, bclk); 540 ret = fsl_esai_set_bclk(dai, esai_priv->synchronous || tx, bclk);
541 if (ret) 541 if (ret)
542 return ret; 542 return ret;
543 543
544 mask = ESAI_xCR_xSWS_MASK;
545 val = ESAI_xCR_xSWS(slot_width, width);
546
547 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
548 /* Recording in synchronous mode needs to set TCR also */
549 if (!tx && esai_priv->synchronous)
550 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, val);
551
544 /* Use Normal mode to support monaural audio */ 552 /* Use Normal mode to support monaural audio */
545 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), 553 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
546 ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ? 554 ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?
@@ -556,10 +564,9 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
556 564
557 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); 565 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
558 566
559 mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); 567 if (tx)
560 val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0); 568 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
561 569 ESAI_xCR_PADC, ESAI_xCR_PADC);
562 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
563 570
564 /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */ 571 /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */
565 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, 572 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 40c07e756481..f7f2d29f1bfe 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -151,12 +151,9 @@ static inline int get_clk_div(struct fsl_micfil *micfil,
151{ 151{
152 u32 ctrl2_reg; 152 u32 ctrl2_reg;
153 long mclk_rate; 153 long mclk_rate;
154 int osr;
155 int clk_div; 154 int clk_div;
156 155
157 regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); 156 regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg);
158 osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR_MASK)
159 >> MICFIL_CTRL2_CICOSR_SHIFT);
160 157
161 mclk_rate = clk_get_rate(micfil->mclk); 158 mclk_rate = clk_get_rate(micfil->mclk);
162 159
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index db9e0872f73d..8593269156bd 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -9,6 +9,7 @@
9#include <linux/dmaengine.h> 9#include <linux/dmaengine.h>
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/of_address.h> 11#include <linux/of_address.h>
12#include <linux/pm_runtime.h>
12#include <linux/regmap.h> 13#include <linux/regmap.h>
13#include <linux/slab.h> 14#include <linux/slab.h>
14#include <linux/time.h> 15#include <linux/time.h>
@@ -268,12 +269,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
268 case SND_SOC_DAIFMT_CBS_CFS: 269 case SND_SOC_DAIFMT_CBS_CFS:
269 val_cr2 |= FSL_SAI_CR2_BCD_MSTR; 270 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
270 val_cr4 |= FSL_SAI_CR4_FSD_MSTR; 271 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
272 sai->is_slave_mode = false;
271 break; 273 break;
272 case SND_SOC_DAIFMT_CBM_CFM: 274 case SND_SOC_DAIFMT_CBM_CFM:
273 sai->is_slave_mode = true; 275 sai->is_slave_mode = true;
274 break; 276 break;
275 case SND_SOC_DAIFMT_CBS_CFM: 277 case SND_SOC_DAIFMT_CBS_CFM:
276 val_cr2 |= FSL_SAI_CR2_BCD_MSTR; 278 val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
279 sai->is_slave_mode = false;
277 break; 280 break;
278 case SND_SOC_DAIFMT_CBM_CFS: 281 case SND_SOC_DAIFMT_CBM_CFS:
279 val_cr4 |= FSL_SAI_CR4_FSD_MSTR; 282 val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
@@ -899,6 +902,8 @@ static int fsl_sai_probe(struct platform_device *pdev)
899 902
900 platform_set_drvdata(pdev, sai); 903 platform_set_drvdata(pdev, sai);
901 904
905 pm_runtime_enable(&pdev->dev);
906
902 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, 907 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
903 &fsl_sai_dai, 1); 908 &fsl_sai_dai, 1);
904 if (ret) 909 if (ret)
@@ -910,6 +915,13 @@ static int fsl_sai_probe(struct platform_device *pdev)
910 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 915 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
911} 916}
912 917
918static int fsl_sai_remove(struct platform_device *pdev)
919{
920 pm_runtime_disable(&pdev->dev);
921
922 return 0;
923}
924
913static const struct of_device_id fsl_sai_ids[] = { 925static const struct of_device_id fsl_sai_ids[] = {
914 { .compatible = "fsl,vf610-sai", }, 926 { .compatible = "fsl,vf610-sai", },
915 { .compatible = "fsl,imx6sx-sai", }, 927 { .compatible = "fsl,imx6sx-sai", },
@@ -918,8 +930,8 @@ static const struct of_device_id fsl_sai_ids[] = {
918}; 930};
919MODULE_DEVICE_TABLE(of, fsl_sai_ids); 931MODULE_DEVICE_TABLE(of, fsl_sai_ids);
920 932
921#ifdef CONFIG_PM_SLEEP 933#ifdef CONFIG_PM
922static int fsl_sai_suspend(struct device *dev) 934static int fsl_sai_runtime_suspend(struct device *dev)
923{ 935{
924 struct fsl_sai *sai = dev_get_drvdata(dev); 936 struct fsl_sai *sai = dev_get_drvdata(dev);
925 937
@@ -929,7 +941,7 @@ static int fsl_sai_suspend(struct device *dev)
929 return 0; 941 return 0;
930} 942}
931 943
932static int fsl_sai_resume(struct device *dev) 944static int fsl_sai_runtime_resume(struct device *dev)
933{ 945{
934 struct fsl_sai *sai = dev_get_drvdata(dev); 946 struct fsl_sai *sai = dev_get_drvdata(dev);
935 947
@@ -941,14 +953,18 @@ static int fsl_sai_resume(struct device *dev)
941 regmap_write(sai->regmap, FSL_SAI_RCSR, 0); 953 regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
942 return regcache_sync(sai->regmap); 954 return regcache_sync(sai->regmap);
943} 955}
944#endif /* CONFIG_PM_SLEEP */ 956#endif /* CONFIG_PM */
945 957
946static const struct dev_pm_ops fsl_sai_pm_ops = { 958static const struct dev_pm_ops fsl_sai_pm_ops = {
947 SET_SYSTEM_SLEEP_PM_OPS(fsl_sai_suspend, fsl_sai_resume) 959 SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend,
960 fsl_sai_runtime_resume, NULL)
961 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
962 pm_runtime_force_resume)
948}; 963};
949 964
950static struct platform_driver fsl_sai_driver = { 965static struct platform_driver fsl_sai_driver = {
951 .probe = fsl_sai_probe, 966 .probe = fsl_sai_probe,
967 .remove = fsl_sai_remove,
952 .driver = { 968 .driver = {
953 .name = "fsl-sai", 969 .name = "fsl-sai",
954 .pm = &fsl_sai_pm_ops, 970 .pm = &fsl_sai_pm_ops,
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index 9981668ab590..040d06b89f00 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -71,6 +71,7 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
71 iprop = of_get_property(dma_np, "cell-index", NULL); 71 iprop = of_get_property(dma_np, "cell-index", NULL);
72 if (!iprop) { 72 if (!iprop) {
73 of_node_put(dma_np); 73 of_node_put(dma_np);
74 of_node_put(dma_channel_np);
74 return -EINVAL; 75 return -EINVAL;
75 } 76 }
76 *dma_id = be32_to_cpup(iprop); 77 *dma_id = be32_to_cpup(iprop);
diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
new file mode 100644
index 000000000000..9aaf3e5b45b9
--- /dev/null
+++ b/sound/soc/fsl/imx-audmix.c
@@ -0,0 +1,331 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2017 NXP
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12
13#include <linux/module.h>
14#include <linux/of_platform.h>
15#include <linux/clk.h>
16#include <sound/soc.h>
17#include <sound/soc-dapm.h>
18#include <linux/pm_runtime.h>
19#include "fsl_sai.h"
20#include "fsl_audmix.h"
21
22struct imx_audmix {
23 struct platform_device *pdev;
24 struct snd_soc_card card;
25 struct platform_device *audmix_pdev;
26 struct platform_device *out_pdev;
27 struct clk *cpu_mclk;
28 int num_dai;
29 struct snd_soc_dai_link *dai;
30 int num_dai_conf;
31 struct snd_soc_codec_conf *dai_conf;
32 int num_dapm_routes;
33 struct snd_soc_dapm_route *dapm_routes;
34};
35
36static const u32 imx_audmix_rates[] = {
37 8000, 12000, 16000, 24000, 32000, 48000, 64000, 96000,
38};
39
40static const struct snd_pcm_hw_constraint_list imx_audmix_rate_constraints = {
41 .count = ARRAY_SIZE(imx_audmix_rates),
42 .list = imx_audmix_rates,
43};
44
45static int imx_audmix_fe_startup(struct snd_pcm_substream *substream)
46{
47 struct snd_soc_pcm_runtime *rtd = substream->private_data;
48 struct imx_audmix *priv = snd_soc_card_get_drvdata(rtd->card);
49 struct snd_pcm_runtime *runtime = substream->runtime;
50 struct device *dev = rtd->card->dev;
51 unsigned long clk_rate = clk_get_rate(priv->cpu_mclk);
52 int ret;
53
54 if (clk_rate % 24576000 == 0) {
55 ret = snd_pcm_hw_constraint_list(runtime, 0,
56 SNDRV_PCM_HW_PARAM_RATE,
57 &imx_audmix_rate_constraints);
58 if (ret < 0)
59 return ret;
60 } else {
61 dev_warn(dev, "mclk may be not supported %lu\n", clk_rate);
62 }
63
64 ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
65 1, 8);
66 if (ret < 0)
67 return ret;
68
69 return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
70 FSL_AUDMIX_FORMATS);
71}
72
73static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
74 struct snd_pcm_hw_params *params)
75{
76 struct snd_soc_pcm_runtime *rtd = substream->private_data;
77 struct device *dev = rtd->card->dev;
78 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
79 unsigned int fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF;
80 u32 channels = params_channels(params);
81 int ret, dir;
82
83 /* For playback the AUDMIX is slave, and for record is master */
84 fmt |= tx ? SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
85 dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN;
86
87 /* set DAI configuration */
88 ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
89 if (ret) {
90 dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
91 return ret;
92 }
93
94 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, FSL_SAI_CLK_MAST1, 0, dir);
95 if (ret) {
96 dev_err(dev, "failed to set cpu sysclk: %d\n", ret);
97 return ret;
98 }
99
100 /*
101 * Per datasheet, AUDMIX expects 8 slots and 32 bits
102 * for every slot in TDM mode.
103 */
104 ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, BIT(channels) - 1,
105 BIT(channels) - 1, 8, 32);
106 if (ret)
107 dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
108
109 return ret;
110}
111
112static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream,
113 struct snd_pcm_hw_params *params)
114{
115 struct snd_soc_pcm_runtime *rtd = substream->private_data;
116 struct device *dev = rtd->card->dev;
117 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
118 unsigned int fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF;
119 int ret;
120
121 if (!tx)
122 return 0;
123
124 /* For playback the AUDMIX is slave */
125 fmt |= SND_SOC_DAIFMT_CBM_CFM;
126
127 /* set AUDMIX DAI configuration */
128 ret = snd_soc_dai_set_fmt(rtd->cpu_dai, fmt);
129 if (ret)
130 dev_err(dev, "failed to set AUDMIX DAI fmt: %d\n", ret);
131
132 return ret;
133}
134
135static struct snd_soc_ops imx_audmix_fe_ops = {
136 .startup = imx_audmix_fe_startup,
137 .hw_params = imx_audmix_fe_hw_params,
138};
139
140static struct snd_soc_ops imx_audmix_be_ops = {
141 .hw_params = imx_audmix_be_hw_params,
142};
143
144static int imx_audmix_probe(struct platform_device *pdev)
145{
146 struct device_node *np = pdev->dev.of_node;
147 struct device_node *audmix_np = NULL, *out_cpu_np = NULL;
148 struct platform_device *audmix_pdev = NULL;
149 struct platform_device *cpu_pdev;
150 struct of_phandle_args args;
151 struct imx_audmix *priv;
152 int i, num_dai, ret;
153 const char *fe_name_pref = "HiFi-AUDMIX-FE-";
154 char *be_name, *be_pb, *be_cp, *dai_name, *capture_dai_name;
155
156 if (pdev->dev.parent) {
157 audmix_np = pdev->dev.parent->of_node;
158 } else {
159 dev_err(&pdev->dev, "Missing parent device.\n");
160 return -EINVAL;
161 }
162
163 if (!audmix_np) {
164 dev_err(&pdev->dev, "Missing DT node for parent device.\n");
165 return -EINVAL;
166 }
167
168 audmix_pdev = of_find_device_by_node(audmix_np);
169 if (!audmix_pdev) {
170 dev_err(&pdev->dev, "Missing AUDMIX platform device for %s\n",
171 np->full_name);
172 return -EINVAL;
173 }
174 put_device(&audmix_pdev->dev);
175
176 num_dai = of_count_phandle_with_args(audmix_np, "dais", NULL);
177 if (num_dai != FSL_AUDMIX_MAX_DAIS) {
178 dev_err(&pdev->dev, "Need 2 dais to be provided for %s\n",
179 audmix_np->full_name);
180 return -EINVAL;
181 }
182
183 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
184 if (!priv)
185 return -ENOMEM;
186
187 priv->num_dai = 2 * num_dai;
188 priv->dai = devm_kzalloc(&pdev->dev, priv->num_dai *
189 sizeof(struct snd_soc_dai_link), GFP_KERNEL);
190 if (!priv->dai)
191 return -ENOMEM;
192
193 priv->num_dai_conf = num_dai;
194 priv->dai_conf = devm_kzalloc(&pdev->dev, priv->num_dai_conf *
195 sizeof(struct snd_soc_codec_conf),
196 GFP_KERNEL);
197 if (!priv->dai_conf)
198 return -ENOMEM;
199
200 priv->num_dapm_routes = 3 * num_dai;
201 priv->dapm_routes = devm_kzalloc(&pdev->dev, priv->num_dapm_routes *
202 sizeof(struct snd_soc_dapm_route),
203 GFP_KERNEL);
204 if (!priv->dapm_routes)
205 return -ENOMEM;
206
207 for (i = 0; i < num_dai; i++) {
208 ret = of_parse_phandle_with_args(audmix_np, "dais", NULL, i,
209 &args);
210 if (ret < 0) {
211 dev_err(&pdev->dev, "of_parse_phandle_with_args failed\n");
212 return ret;
213 }
214
215 cpu_pdev = of_find_device_by_node(args.np);
216 if (!cpu_pdev) {
217 dev_err(&pdev->dev, "failed to find SAI platform device\n");
218 return -EINVAL;
219 }
220 put_device(&cpu_pdev->dev);
221
222 dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%s",
223 fe_name_pref, args.np->full_name + 1);
224
225 dev_info(pdev->dev.parent, "DAI FE name:%s\n", dai_name);
226
227 if (i == 0) {
228 out_cpu_np = args.np;
229 capture_dai_name =
230 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
231 dai_name, "CPU-Capture");
232 }
233
234 priv->dai[i].name = dai_name;
235 priv->dai[i].stream_name = "HiFi-AUDMIX-FE";
236 priv->dai[i].codec_dai_name = "snd-soc-dummy-dai";
237 priv->dai[i].codec_name = "snd-soc-dummy";
238 priv->dai[i].cpu_of_node = args.np;
239 priv->dai[i].cpu_dai_name = dev_name(&cpu_pdev->dev);
240 priv->dai[i].platform_of_node = args.np;
241 priv->dai[i].dynamic = 1;
242 priv->dai[i].dpcm_playback = 1;
243 priv->dai[i].dpcm_capture = (i == 0 ? 1 : 0);
244 priv->dai[i].ignore_pmdown_time = 1;
245 priv->dai[i].ops = &imx_audmix_fe_ops;
246
247 /* Add AUDMIX Backend */
248 be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
249 "audmix-%d", i);
250 be_pb = devm_kasprintf(&pdev->dev, GFP_KERNEL,
251 "AUDMIX-Playback-%d", i);
252 be_cp = devm_kasprintf(&pdev->dev, GFP_KERNEL,
253 "AUDMIX-Capture-%d", i);
254
255 priv->dai[num_dai + i].name = be_name;
256 priv->dai[num_dai + i].codec_dai_name = "snd-soc-dummy-dai";
257 priv->dai[num_dai + i].codec_name = "snd-soc-dummy";
258 priv->dai[num_dai + i].cpu_of_node = audmix_np;
259 priv->dai[num_dai + i].cpu_dai_name = be_name;
260 priv->dai[num_dai + i].platform_name = "snd-soc-dummy";
261 priv->dai[num_dai + i].no_pcm = 1;
262 priv->dai[num_dai + i].dpcm_playback = 1;
263 priv->dai[num_dai + i].dpcm_capture = 1;
264 priv->dai[num_dai + i].ignore_pmdown_time = 1;
265 priv->dai[num_dai + i].ops = &imx_audmix_be_ops;
266
267 priv->dai_conf[i].of_node = args.np;
268 priv->dai_conf[i].name_prefix = dai_name;
269
270 priv->dapm_routes[i].source =
271 devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s %s",
272 dai_name, "CPU-Playback");
273 priv->dapm_routes[i].sink = be_pb;
274 priv->dapm_routes[num_dai + i].source = be_pb;
275 priv->dapm_routes[num_dai + i].sink = be_cp;
276 priv->dapm_routes[2 * num_dai + i].source = be_cp;
277 priv->dapm_routes[2 * num_dai + i].sink = capture_dai_name;
278 }
279
280 cpu_pdev = of_find_device_by_node(out_cpu_np);
281 if (!cpu_pdev) {
282 dev_err(&pdev->dev, "failed to find SAI platform device\n");
283 return -EINVAL;
284 }
285 put_device(&cpu_pdev->dev);
286
287 priv->cpu_mclk = devm_clk_get(&cpu_pdev->dev, "mclk1");
288 if (IS_ERR(priv->cpu_mclk)) {
289 ret = PTR_ERR(priv->cpu_mclk);
290 dev_err(&cpu_pdev->dev, "failed to get DAI mclk1: %d\n", ret);
291 return -EINVAL;
292 }
293
294 priv->audmix_pdev = audmix_pdev;
295 priv->out_pdev = cpu_pdev;
296
297 priv->card.dai_link = priv->dai;
298 priv->card.num_links = priv->num_dai;
299 priv->card.codec_conf = priv->dai_conf;
300 priv->card.num_configs = priv->num_dai_conf;
301 priv->card.dapm_routes = priv->dapm_routes;
302 priv->card.num_dapm_routes = priv->num_dapm_routes;
303 priv->card.dev = pdev->dev.parent;
304 priv->card.owner = THIS_MODULE;
305 priv->card.name = "imx-audmix";
306
307 platform_set_drvdata(pdev, &priv->card);
308 snd_soc_card_set_drvdata(&priv->card, priv);
309
310 ret = devm_snd_soc_register_card(pdev->dev.parent, &priv->card);
311 if (ret) {
312 dev_err(&pdev->dev, "snd_soc_register_card failed\n");
313 return ret;
314 }
315
316 return ret;
317}
318
319static struct platform_driver imx_audmix_driver = {
320 .probe = imx_audmix_probe,
321 .driver = {
322 .name = "imx-audmix",
323 .pm = &snd_soc_pm_ops,
324 },
325};
326module_platform_driver(imx_audmix_driver);
327
328MODULE_DESCRIPTION("NXP AUDMIX ASoC machine driver");
329MODULE_AUTHOR("Viorel Suman <viorel.suman@nxp.com>");
330MODULE_ALIAS("platform:imx-audmix");
331MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 99e07b01a2ce..04e59e66711d 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -1,21 +1,11 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Copyright 2012 Freescale Semiconductor, Inc. 2//
3 * Copyright 2012 Linaro Ltd. 3// Copyright 2012 Freescale Semiconductor, Inc.
4 * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> 4// Copyright 2012 Linaro Ltd.
5 * 5// Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
6 * Initial development of this code was funded by 6//
7 * Phytec Messtechnik GmbH, http://www.phytec.de 7// Initial development of this code was funded by
8 * 8// Phytec Messtechnik GmbH, http://www.phytec.de
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19 9
20#include <linux/clk.h> 10#include <linux/clk.h>
21#include <linux/debugfs.h> 11#include <linux/debugfs.h>
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
index 9953438086e4..c9d8739b04a9 100644
--- a/sound/soc/fsl/imx-es8328.c
+++ b/sound/soc/fsl/imx-es8328.c
@@ -1,14 +1,7 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Copyright 2012 Freescale Semiconductor, Inc. 2//
3 * Copyright 2012 Linaro Ltd. 3// Copyright 2012 Freescale Semiconductor, Inc.
4 * 4// Copyright 2012 Linaro Ltd.
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12 5
13#include <linux/gpio.h> 6#include <linux/gpio.h>
14#include <linux/module.h> 7#include <linux/module.h>
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
index 9d19b808f634..545815a27074 100644
--- a/sound/soc/fsl/imx-mc13783.c
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -1,17 +1,11 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * imx-mc13783.c -- SoC audio for imx based boards with mc13783 codec 2//
3 * 3// imx-mc13783.c -- SoC audio for imx based boards with mc13783 codec
4 * Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch> 4//
5 * 5// Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
6 * Heavly based on phycore-mc13783: 6//
7 * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 7// Heavly based on phycore-mc13783:
8 * 8// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15 9
16#include <linux/module.h> 10#include <linux/module.h>
17#include <linux/moduleparam.h> 11#include <linux/moduleparam.h>
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 0578f3486847..c49aea4fba56 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -1,16 +1,11 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * imx-pcm-fiq.c -- ALSA Soc Audio Layer 2// imx-pcm-fiq.c -- ALSA Soc Audio Layer
3 * 3//
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> 4// Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
5 * 5//
6 * This code is based on code copyrighted by Freescale, 6// This code is based on code copyrighted by Freescale,
7 * Liam Girdwood, Javier Martin and probably others. 7// Liam Girdwood, Javier Martin and probably others.
8 * 8
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14#include <linux/clk.h> 9#include <linux/clk.h>
15#include <linux/delay.h> 10#include <linux/delay.h>
16#include <linux/device.h> 11#include <linux/device.h>
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index 133c4470acad..5dd406774d3e 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -1,13 +1,9 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
1/* 2/*
2 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> 3 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
3 * 4 *
4 * This code is based on code copyrighted by Freescale, 5 * This code is based on code copyrighted by Freescale,
5 * Liam Girdwood, Javier Martin and probably others. 6 * Liam Girdwood, Javier Martin and probably others.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */ 7 */
12 8
13#ifndef _IMX_PCM_H 9#ifndef _IMX_PCM_H
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
index 797d66e43d49..4f7f210beb18 100644
--- a/sound/soc/fsl/imx-spdif.c
+++ b/sound/soc/fsl/imx-spdif.c
@@ -1,13 +1,6 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Copyright (C) 2013 Freescale Semiconductor, Inc. 2//
3 * 3// Copyright (C) 2013 Freescale Semiconductor, Inc.
4 * The code contained herein is licensed under the GNU General Public
5 * License. You may obtain a copy of the GNU General Public License
6 * Version 2 or later at the following locations:
7 *
8 * http://www.opensource.org/licenses/gpl-license.html
9 * http://www.gnu.org/copyleft/gpl.html
10 */
11 4
12#include <linux/module.h> 5#include <linux/module.h>
13#include <linux/of_platform.h> 6#include <linux/of_platform.h>
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 06790615e04e..9038b61317be 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -1,35 +1,28 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * imx-ssi.c -- ALSA Soc Audio Layer 2//
3 * 3// imx-ssi.c -- ALSA Soc Audio Layer
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de> 4//
5 * 5// Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
6 * This code is based on code copyrighted by Freescale, 6//
7 * Liam Girdwood, Javier Martin and probably others. 7// This code is based on code copyrighted by Freescale,
8 * 8// Liam Girdwood, Javier Martin and probably others.
9 * This program is free software; you can redistribute it and/or modify it 9//
10 * under the terms of the GNU General Public License as published by the 10// The i.MX SSI core has some nasty limitations in AC97 mode. While most
11 * Free Software Foundation; either version 2 of the License, or (at your 11// sane processor vendors have a FIFO per AC97 slot, the i.MX has only
12 * option) any later version. 12// one FIFO which combines all valid receive slots. We cannot even select
13 * 13// which slots we want to receive. The WM9712 with which this driver
14 * 14// was developed with always sends GPIO status data in slot 12 which
15 * The i.MX SSI core has some nasty limitations in AC97 mode. While most 15// we receive in our (PCM-) data stream. The only chance we have is to
16 * sane processor vendors have a FIFO per AC97 slot, the i.MX has only 16// manually skip this data in the FIQ handler. With sampling rates different
17 * one FIFO which combines all valid receive slots. We cannot even select 17// from 48000Hz not every frame has valid receive data, so the ratio
18 * which slots we want to receive. The WM9712 with which this driver 18// between pcm data and GPIO status data changes. Our FIQ handler is not
19 * was developed with always sends GPIO status data in slot 12 which 19// able to handle this, hence this driver only works with 48000Hz sampling
20 * we receive in our (PCM-) data stream. The only chance we have is to 20// rate.
21 * manually skip this data in the FIQ handler. With sampling rates different 21// Reading and writing AC97 registers is another challenge. The core
22 * from 48000Hz not every frame has valid receive data, so the ratio 22// provides us status bits when the read register is updated with *another*
23 * between pcm data and GPIO status data changes. Our FIQ handler is not 23// value. When we read the same register two times (and the register still
24 * able to handle this, hence this driver only works with 48000Hz sampling 24// contains the same value) these status bits are not set. We work
25 * rate. 25// around this by not polling these bits but only wait a fixed delay.
26 * Reading and writing AC97 registers is another challenge. The core
27 * provides us status bits when the read register is updated with *another*
28 * value. When we read the same register two times (and the register still
29 * contains the same value) these status bits are not set. We work
30 * around this by not polling these bits but only wait a fixed delay.
31 *
32 */
33 26
34#include <linux/clk.h> 27#include <linux/clk.h>
35#include <linux/delay.h> 28#include <linux/delay.h>
diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
index be6562365b6a..19cd0937e740 100644
--- a/sound/soc/fsl/imx-ssi.h
+++ b/sound/soc/fsl/imx-ssi.h
@@ -1,8 +1,4 @@
1/* 1/* SPDX-License-Identifier: GPL-2.0 */
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 */
6 2
7#ifndef _IMX_SSI_H 3#ifndef _IMX_SSI_H
8#define _IMX_SSI_H 4#define _IMX_SSI_H
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index c1a4544eb16b..ccf9301889fe 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -1,10 +1,10 @@
1/* 1// SPDX-License-Identifier: GPL-2.0-only
2 * Freescale MPC5200 PSC DMA 2//
3 * ALSA SoC Platform driver 3// Freescale MPC5200 PSC DMA
4 * 4// ALSA SoC Platform driver
5 * Copyright (C) 2008 Secret Lab Technologies Ltd. 5//
6 * Copyright (C) 2009 Jon Smirl, Digispeaker 6// Copyright (C) 2008 Secret Lab Technologies Ltd.
7 */ 7// Copyright (C) 2009 Jon Smirl, Digispeaker
8 8
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/of_device.h> 10#include <linux/of_device.h>
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 07ee355ee385..e5b9c04d1565 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -1,13 +1,9 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip. 2//
3 * 3// linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
4 * Copyright (C) 2009 Jon Smirl, Digispeaker 4//
5 * Author: Jon Smirl <jonsmirl@gmail.com> 5// Copyright (C) 2009 Jon Smirl, Digispeaker
6 * 6// Author: Jon Smirl <jonsmirl@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11 7
12#include <linux/module.h> 8#include <linux/module.h>
13#include <linux/of_device.h> 9#include <linux/of_device.h>
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index d8232943ccb6..9bc01f374b39 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -1,10 +1,10 @@
1/* 1// SPDX-License-Identifier: GPL-2.0-only
2 * Freescale MPC5200 PSC in I2S mode 2//
3 * ALSA SoC Digital Audio Interface (DAI) driver 3// Freescale MPC5200 PSC in I2S mode
4 * 4// ALSA SoC Digital Audio Interface (DAI) driver
5 * Copyright (C) 2008 Secret Lab Technologies Ltd. 5//
6 * Copyright (C) 2009 Jon Smirl, Digispeaker 6// Copyright (C) 2008 Secret Lab Technologies Ltd.
7 */ 7// Copyright (C) 2009 Jon Smirl, Digispeaker
8 8
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/of_device.h> 10#include <linux/of_device.h>
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index a639b52c16f6..f6261a3eeb0f 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -1,14 +1,10 @@
1/** 1// SPDX-License-Identifier: GPL-2.0
2 * Freescale MPC8610HPCD ALSA SoC Machine driver 2//
3 * 3// Freescale MPC8610HPCD ALSA SoC Machine driver
4 * Author: Timur Tabi <timur@freescale.com> 4//
5 * 5// Author: Timur Tabi <timur@freescale.com>
6 * Copyright 2007-2010 Freescale Semiconductor, Inc. 6//
7 * 7// Copyright 2007-2010 Freescale Semiconductor, Inc.
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12 8
13#include <linux/module.h> 9#include <linux/module.h>
14#include <linux/interrupt.h> 10#include <linux/interrupt.h>
diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
index d7ec3d20065c..37a4520aef62 100644
--- a/sound/soc/fsl/mx27vis-aic32x4.c
+++ b/sound/soc/fsl/mx27vis-aic32x4.c
@@ -1,25 +1,10 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * mx27vis-aic32x4.c 2//
3 * 3// mx27vis-aic32x4.c
4 * Copyright 2011 Vista Silicon S.L. 4//
5 * 5// Copyright 2011 Vista Silicon S.L.
6 * Author: Javier Martin <javier.martin@vista-silicon.com> 6//
7 * 7// Author: Javier Martin <javier.martin@vista-silicon.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
22 */
23 8
24#include <linux/module.h> 9#include <linux/module.h>
25#include <linux/moduleparam.h> 10#include <linux/moduleparam.h>
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 41c623c55c16..80384f70878d 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -1,14 +1,10 @@
1/** 1// SPDX-License-Identifier: GPL-2.0
2 * Freescale P1022DS ALSA SoC Machine driver 2//
3 * 3// Freescale P1022DS ALSA SoC Machine driver
4 * Author: Timur Tabi <timur@freescale.com> 4//
5 * 5// Author: Timur Tabi <timur@freescale.com>
6 * Copyright 2010 Freescale Semiconductor, Inc. 6//
7 * 7// Copyright 2010 Freescale Semiconductor, Inc.
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12 8
13#include <linux/module.h> 9#include <linux/module.h>
14#include <linux/fsl/guts.h> 10#include <linux/fsl/guts.h>
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index 4afbdd610bfa..1c32c2d8c6b0 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -1,21 +1,17 @@
1/** 1// SPDX-License-Identifier: GPL-2.0
2 * Freescale P1022RDK ALSA SoC Machine driver 2//
3 * 3// Freescale P1022RDK ALSA SoC Machine driver
4 * Author: Timur Tabi <timur@freescale.com> 4//
5 * 5// Author: Timur Tabi <timur@freescale.com>
6 * Copyright 2012 Freescale Semiconductor, Inc. 6//
7 * 7// Copyright 2012 Freescale Semiconductor, Inc.
8 * This file is licensed under the terms of the GNU General Public License 8//
9 * version 2. This program is licensed "as is" without any warranty of any 9// Note: in order for audio to work correctly, the output controls need
10 * kind, whether express or implied. 10// to be enabled, because they control the clock. So for playback, for
11 * 11// example:
12 * Note: in order for audio to work correctly, the output controls need 12//
13 * to be enabled, because they control the clock. So for playback, for 13// amixer sset 'Left Output Mixer PCM' on
14 * example: 14// amixer sset 'Right Output Mixer PCM' on
15 *
16 * amixer sset 'Left Output Mixer PCM' on
17 * amixer sset 'Right Output Mixer PCM' on
18 */
19 15
20#include <linux/module.h> 16#include <linux/module.h>
21#include <linux/fsl/guts.h> 17#include <linux/fsl/guts.h>
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index e339f36cea95..a7fe4ad25c52 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -1,14 +1,10 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * Phytec pcm030 driver for the PSC of the Freescale MPC52xx 2//
3 * configured as AC97 interface 3// Phytec pcm030 driver for the PSC of the Freescale MPC52xx
4 * 4// configured as AC97 interface
5 * Copyright 2008 Jon Smirl, Digispeaker 5//
6 * Author: Jon Smirl <jonsmirl@gmail.com> 6// Copyright 2008 Jon Smirl, Digispeaker
7 * 7// Author: Jon Smirl <jonsmirl@gmail.com>
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12 8
13#include <linux/init.h> 9#include <linux/init.h>
14#include <linux/module.h> 10#include <linux/module.h>
diff --git a/sound/soc/fsl/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
index 66fb6c4614d2..fe7ba6db7c96 100644
--- a/sound/soc/fsl/phycore-ac97.c
+++ b/sound/soc/fsl/phycore-ac97.c
@@ -1,14 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * phycore-ac97.c -- SoC audio for imx_phycore in AC97 mode 2//
3 * 3// phycore-ac97.c -- SoC audio for imx_phycore in AC97 mode
4 * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 4//
5 * 5// Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 *
11 */
12 6
13#include <linux/module.h> 7#include <linux/module.h>
14#include <linux/moduleparam.h> 8#include <linux/moduleparam.h>
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
index 2f80b21b2921..aad24ccbef90 100644
--- a/sound/soc/fsl/wm1133-ev1.c
+++ b/sound/soc/fsl/wm1133-ev1.c
@@ -1,16 +1,11 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS 2//
3 * 3// wm1133-ev1.c - Audio for WM1133-EV1 on i.MX31ADS
4 * Copyright (c) 2010 Wolfson Microelectronics plc 4//
5 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 5// Copyright (c) 2010 Wolfson Microelectronics plc
6 * 6// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 * Based on an earlier driver for the same hardware by Liam Girdwood. 7//
8 * 8// Based on an earlier driver for the same hardware by Liam Girdwood.
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14 9
15#include <linux/platform_device.h> 10#include <linux/platform_device.h>
16#include <linux/clk.h> 11#include <linux/clk.h>
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 69bc4848d787..ec7e673ba475 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -22,37 +22,6 @@
22 22
23#define DPCM_SELECTABLE 1 23#define DPCM_SELECTABLE 1
24 24
25struct graph_priv {
26 struct snd_soc_card snd_card;
27 struct graph_dai_props {
28 struct asoc_simple_dai *cpu_dai;
29 struct asoc_simple_dai *codec_dai;
30 struct snd_soc_dai_link_component codecs; /* single codec */
31 struct snd_soc_dai_link_component platforms;
32 struct asoc_simple_card_data adata;
33 struct snd_soc_codec_conf *codec_conf;
34 unsigned int mclk_fs;
35 } *dai_props;
36 struct asoc_simple_jack hp_jack;
37 struct asoc_simple_jack mic_jack;
38 struct snd_soc_dai_link *dai_link;
39 struct asoc_simple_dai *dais;
40 struct snd_soc_codec_conf *codec_conf;
41 struct gpio_desc *pa_gpio;
42};
43
44struct link_info {
45 int dais; /* number of dai */
46 int link; /* number of link */
47 int conf; /* number of codec_conf */
48 int cpu; /* turn for CPU / Codec */
49};
50
51#define graph_priv_to_card(priv) (&(priv)->snd_card)
52#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i))
53#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev)
54#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i))
55
56#define PREFIX "audio-graph-card," 25#define PREFIX "audio-graph-card,"
57 26
58static int graph_outdrv_event(struct snd_soc_dapm_widget *w, 27static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
@@ -60,7 +29,7 @@ static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
60 int event) 29 int event)
61{ 30{
62 struct snd_soc_dapm_context *dapm = w->dapm; 31 struct snd_soc_dapm_context *dapm = w->dapm;
63 struct graph_priv *priv = snd_soc_card_get_drvdata(dapm->card); 32 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(dapm->card);
64 33
65 switch (event) { 34 switch (event) {
66 case SND_SOC_DAPM_POST_PMU: 35 case SND_SOC_DAPM_POST_PMU:
@@ -82,127 +51,156 @@ static const struct snd_soc_dapm_widget graph_dapm_widgets[] = {
82 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 51 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
83}; 52};
84 53
85static int graph_startup(struct snd_pcm_substream *substream) 54static const struct snd_soc_ops graph_ops = {
55 .startup = asoc_simple_startup,
56 .shutdown = asoc_simple_shutdown,
57 .hw_params = asoc_simple_hw_params,
58};
59
60static int graph_get_dai_id(struct device_node *ep)
86{ 61{
87 struct snd_soc_pcm_runtime *rtd = substream->private_data; 62 struct device_node *node;
88 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); 63 struct device_node *endpoint;
89 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); 64 struct of_endpoint info;
65 int i, id;
90 int ret; 66 int ret;
91 67
92 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); 68 /* use driver specified DAI ID if exist */
93 if (ret) 69 ret = snd_soc_get_dai_id(ep);
70 if (ret != -ENOTSUPP)
94 return ret; 71 return ret;
95 72
96 ret = asoc_simple_card_clk_enable(dai_props->codec_dai); 73 /* use endpoint/port reg if exist */
97 if (ret) 74 ret = of_graph_parse_endpoint(ep, &info);
98 asoc_simple_card_clk_disable(dai_props->cpu_dai); 75 if (ret == 0) {
76 /*
77 * Because it will count port/endpoint if it doesn't have "reg".
78 * But, we can't judge whether it has "no reg", or "reg = <0>"
79 * only of_graph_parse_endpoint().
80 * We need to check "reg" property
81 */
82 if (of_get_property(ep, "reg", NULL))
83 return info.id;
99 84
100 return ret; 85 node = of_get_parent(ep);
101} 86 of_node_put(node);
87 if (of_get_property(node, "reg", NULL))
88 return info.port;
89 }
90 node = of_graph_get_port_parent(ep);
102 91
103static void graph_shutdown(struct snd_pcm_substream *substream) 92 /*
104{ 93 * Non HDMI sound case, counting port/endpoint on its DT
105 struct snd_soc_pcm_runtime *rtd = substream->private_data; 94 * is enough. Let's count it.
106 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); 95 */
107 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); 96 i = 0;
97 id = -1;
98 for_each_endpoint_of_node(node, endpoint) {
99 if (endpoint == ep)
100 id = i;
101 i++;
102 }
108 103
109 asoc_simple_card_clk_disable(dai_props->cpu_dai); 104 of_node_put(node);
105
106 if (id < 0)
107 return -ENODEV;
110 108
111 asoc_simple_card_clk_disable(dai_props->codec_dai); 109 return id;
112} 110}
113 111
114static int graph_hw_params(struct snd_pcm_substream *substream, 112static int asoc_simple_parse_dai(struct device_node *ep,
115 struct snd_pcm_hw_params *params) 113 struct snd_soc_dai_link_component *dlc,
114 struct device_node **dai_of_node,
115 const char **dai_name,
116 int *is_single_link)
116{ 117{
117 struct snd_soc_pcm_runtime *rtd = substream->private_data; 118 struct device_node *node;
118 struct snd_soc_dai *codec_dai = rtd->codec_dai; 119 struct of_phandle_args args;
119 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 120 int ret;
120 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); 121
121 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); 122 /*
122 unsigned int mclk, mclk_fs = 0; 123 * Use snd_soc_dai_link_component instead of legacy style.
123 int ret = 0; 124 * It is only for codec, but cpu will be supported in the future.
124 125 * see
125 if (dai_props->mclk_fs) 126 * soc-core.c :: snd_soc_init_multicodec()
126 mclk_fs = dai_props->mclk_fs; 127 */
127 128 if (dlc) {
128 if (mclk_fs) { 129 dai_name = &dlc->dai_name;
129 mclk = params_rate(params) * mclk_fs; 130 dai_of_node = &dlc->of_node;
130 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
131 SND_SOC_CLOCK_IN);
132 if (ret && ret != -ENOTSUPP)
133 goto err;
134
135 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
136 SND_SOC_CLOCK_OUT);
137 if (ret && ret != -ENOTSUPP)
138 goto err;
139 } 131 }
140 return 0;
141err:
142 return ret;
143}
144 132
145static const struct snd_soc_ops graph_ops = { 133 if (!ep)
146 .startup = graph_startup, 134 return 0;
147 .shutdown = graph_shutdown, 135 if (!dai_name)
148 .hw_params = graph_hw_params, 136 return 0;
149};
150 137
151static int graph_dai_init(struct snd_soc_pcm_runtime *rtd) 138 node = of_graph_get_port_parent(ep);
152{
153 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
154 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
155 int ret = 0;
156 139
157 ret = asoc_simple_card_init_dai(rtd->codec_dai, 140 /* Get dai->name */
158 dai_props->codec_dai); 141 args.np = node;
159 if (ret < 0) 142 args.args[0] = graph_get_dai_id(ep);
160 return ret; 143 args.args_count = (of_graph_get_endpoint_count(node) > 1);
161 144
162 ret = asoc_simple_card_init_dai(rtd->cpu_dai, 145 ret = snd_soc_get_dai_name(&args, dai_name);
163 dai_props->cpu_dai);
164 if (ret < 0) 146 if (ret < 0)
165 return ret; 147 return ret;
166 148
167 return 0; 149 *dai_of_node = node;
168}
169
170static int graph_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
171 struct snd_pcm_hw_params *params)
172{
173 struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card);
174 struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num);
175 150
176 asoc_simple_card_convert_fixup(&dai_props->adata, params); 151 if (is_single_link)
152 *is_single_link = of_graph_get_endpoint_count(node) == 1;
177 153
178 return 0; 154 return 0;
179} 155}
180 156
181static void graph_get_conversion(struct device *dev, 157static void graph_parse_convert(struct device *dev,
182 struct device_node *ep, 158 struct device_node *ep,
183 struct asoc_simple_card_data *adata) 159 struct asoc_simple_data *adata)
184{ 160{
185 struct device_node *top = dev->of_node; 161 struct device_node *top = dev->of_node;
186 struct device_node *port = of_get_parent(ep); 162 struct device_node *port = of_get_parent(ep);
187 struct device_node *ports = of_get_parent(port); 163 struct device_node *ports = of_get_parent(port);
188 struct device_node *node = of_graph_get_port_parent(ep); 164 struct device_node *node = of_graph_get_port_parent(ep);
189 165
190 asoc_simple_card_parse_convert(dev, top, NULL, adata); 166 asoc_simple_parse_convert(dev, top, NULL, adata);
191 asoc_simple_card_parse_convert(dev, node, PREFIX, adata); 167 asoc_simple_parse_convert(dev, node, PREFIX, adata);
192 asoc_simple_card_parse_convert(dev, ports, NULL, adata); 168 asoc_simple_parse_convert(dev, ports, NULL, adata);
193 asoc_simple_card_parse_convert(dev, port, NULL, adata); 169 asoc_simple_parse_convert(dev, port, NULL, adata);
194 asoc_simple_card_parse_convert(dev, ep, NULL, adata); 170 asoc_simple_parse_convert(dev, ep, NULL, adata);
171
172 of_node_put(port);
173 of_node_put(ports);
174 of_node_put(node);
195} 175}
196 176
197static int graph_dai_link_of_dpcm(struct graph_priv *priv, 177static void graph_parse_mclk_fs(struct device_node *top,
178 struct device_node *ep,
179 struct simple_dai_props *props)
180{
181 struct device_node *port = of_get_parent(ep);
182 struct device_node *ports = of_get_parent(port);
183 struct device_node *node = of_graph_get_port_parent(ep);
184
185 of_property_read_u32(top, "mclk-fs", &props->mclk_fs);
186 of_property_read_u32(ports, "mclk-fs", &props->mclk_fs);
187 of_property_read_u32(port, "mclk-fs", &props->mclk_fs);
188 of_property_read_u32(ep, "mclk-fs", &props->mclk_fs);
189
190 of_node_put(port);
191 of_node_put(ports);
192 of_node_put(node);
193}
194
195static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv,
198 struct device_node *cpu_ep, 196 struct device_node *cpu_ep,
199 struct device_node *codec_ep, 197 struct device_node *codec_ep,
200 struct link_info *li, 198 struct link_info *li,
201 int dup_codec) 199 int dup_codec)
202{ 200{
203 struct device *dev = graph_priv_to_dev(priv); 201 struct device *dev = simple_priv_to_dev(priv);
204 struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); 202 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
205 struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); 203 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
206 struct device_node *top = dev->of_node; 204 struct device_node *top = dev->of_node;
207 struct device_node *ep = li->cpu ? cpu_ep : codec_ep; 205 struct device_node *ep = li->cpu ? cpu_ep : codec_ep;
208 struct device_node *port; 206 struct device_node *port;
@@ -224,18 +222,12 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv,
224 222
225 dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); 223 dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
226 224
227 of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
228 of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs);
229 of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs);
230 of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs);
231
232 graph_get_conversion(dev, ep, &dai_props->adata);
233
234 of_node_put(ports); 225 of_node_put(ports);
235 of_node_put(port); 226 of_node_put(port);
236 of_node_put(node); 227 of_node_put(node);
237 228
238 if (li->cpu) { 229 if (li->cpu) {
230 int is_single_links = 0;
239 231
240 /* BE is dummy */ 232 /* BE is dummy */
241 codecs->of_node = NULL; 233 codecs->of_node = NULL;
@@ -249,23 +241,22 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv,
249 dai = 241 dai =
250 dai_props->cpu_dai = &priv->dais[li->dais++]; 242 dai_props->cpu_dai = &priv->dais[li->dais++];
251 243
252 ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); 244 ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links);
253 if (ret) 245 if (ret)
254 return ret; 246 return ret;
255 247
256 ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); 248 ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai);
257 if (ret < 0) 249 if (ret < 0)
258 return ret; 250 return ret;
259 251
260 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 252 ret = asoc_simple_set_dailink_name(dev, dai_link,
261 "fe.%s", 253 "fe.%s",
262 dai_link->cpu_dai_name); 254 dai_link->cpu_dai_name);
263 if (ret < 0) 255 if (ret < 0)
264 return ret; 256 return ret;
265 257
266 /* card->num_links includes Codec */ 258 /* card->num_links includes Codec */
267 asoc_simple_card_canonicalize_cpu(dai_link, 259 asoc_simple_canonicalize_cpu(dai_link, is_single_links);
268 of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
269 } else { 260 } else {
270 struct snd_soc_codec_conf *cconf; 261 struct snd_soc_codec_conf *cconf;
271 262
@@ -276,7 +267,7 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv,
276 267
277 /* BE settings */ 268 /* BE settings */
278 dai_link->no_pcm = 1; 269 dai_link->no_pcm = 1;
279 dai_link->be_hw_params_fixup = graph_be_hw_params_fixup; 270 dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
280 271
281 dai = 272 dai =
282 dai_props->codec_dai = &priv->dais[li->dais++]; 273 dai_props->codec_dai = &priv->dais[li->dais++];
@@ -284,17 +275,17 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv,
284 cconf = 275 cconf =
285 dai_props->codec_conf = &priv->codec_conf[li->conf++]; 276 dai_props->codec_conf = &priv->codec_conf[li->conf++];
286 277
287 ret = asoc_simple_card_parse_graph_codec(ep, dai_link); 278 ret = asoc_simple_parse_codec(ep, dai_link);
288 if (ret < 0) 279 if (ret < 0)
289 return ret; 280 return ret;
290 281
291 ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); 282 ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai);
292 if (ret < 0) 283 if (ret < 0)
293 return ret; 284 return ret;
294 285
295 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 286 ret = asoc_simple_set_dailink_name(dev, dai_link,
296 "be.%s", 287 "be.%s",
297 codecs->dai_name); 288 codecs->dai_name);
298 if (ret < 0) 289 if (ret < 0)
299 return ret; 290 return ret;
300 291
@@ -309,51 +300,45 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv,
309 "prefix"); 300 "prefix");
310 } 301 }
311 302
312 asoc_simple_card_canonicalize_platform(dai_link); 303 graph_parse_convert(dev, ep, &dai_props->adata);
304 graph_parse_mclk_fs(top, ep, dai_props);
313 305
314 ret = asoc_simple_card_of_parse_tdm(ep, dai); 306 asoc_simple_canonicalize_platform(dai_link);
307
308 ret = asoc_simple_parse_tdm(ep, dai);
315 if (ret) 309 if (ret)
316 return ret; 310 return ret;
317 311
318 ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, 312 ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
319 NULL, &dai_link->dai_fmt); 313 NULL, &dai_link->dai_fmt);
320 if (ret < 0) 314 if (ret < 0)
321 return ret; 315 return ret;
322 316
323 dai_link->dpcm_playback = 1; 317 dai_link->dpcm_playback = 1;
324 dai_link->dpcm_capture = 1; 318 dai_link->dpcm_capture = 1;
325 dai_link->ops = &graph_ops; 319 dai_link->ops = &graph_ops;
326 dai_link->init = graph_dai_init; 320 dai_link->init = asoc_simple_dai_init;
327 321
328 return 0; 322 return 0;
329} 323}
330 324
331static int graph_dai_link_of(struct graph_priv *priv, 325static int graph_dai_link_of(struct asoc_simple_priv *priv,
332 struct device_node *cpu_ep, 326 struct device_node *cpu_ep,
333 struct device_node *codec_ep, 327 struct device_node *codec_ep,
334 struct link_info *li) 328 struct link_info *li)
335{ 329{
336 struct device *dev = graph_priv_to_dev(priv); 330 struct device *dev = simple_priv_to_dev(priv);
337 struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); 331 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
338 struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); 332 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
339 struct device_node *top = dev->of_node; 333 struct device_node *top = dev->of_node;
340 struct device_node *cpu_port;
341 struct device_node *cpu_ports;
342 struct device_node *codec_port;
343 struct device_node *codec_ports;
344 struct asoc_simple_dai *cpu_dai; 334 struct asoc_simple_dai *cpu_dai;
345 struct asoc_simple_dai *codec_dai; 335 struct asoc_simple_dai *codec_dai;
346 int ret; 336 int ret, single_cpu;
347 337
348 /* Do it only CPU turn */ 338 /* Do it only CPU turn */
349 if (!li->cpu) 339 if (!li->cpu)
350 return 0; 340 return 0;
351 341
352 cpu_port = of_get_parent(cpu_ep);
353 cpu_ports = of_get_parent(cpu_port);
354 codec_port = of_get_parent(codec_ep);
355 codec_ports = of_get_parent(codec_port);
356
357 dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); 342 dev_dbg(dev, "link_of (%pOF)\n", cpu_ep);
358 343
359 li->link++; 344 li->link++;
@@ -364,84 +349,74 @@ static int graph_dai_link_of(struct graph_priv *priv,
364 dai_props->codec_dai = &priv->dais[li->dais++]; 349 dai_props->codec_dai = &priv->dais[li->dais++];
365 350
366 /* Factor to mclk, used in hw_params() */ 351 /* Factor to mclk, used in hw_params() */
367 of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); 352 graph_parse_mclk_fs(top, cpu_ep, dai_props);
368 of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs); 353 graph_parse_mclk_fs(top, codec_ep, dai_props);
369 of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs); 354
370 of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs); 355 ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep,
371 of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs); 356 NULL, &dai_link->dai_fmt);
372 of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs);
373 of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs);
374 of_node_put(cpu_port);
375 of_node_put(cpu_ports);
376 of_node_put(codec_port);
377 of_node_put(codec_ports);
378
379 ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
380 NULL, &dai_link->dai_fmt);
381 if (ret < 0) 357 if (ret < 0)
382 return ret; 358 return ret;
383 359
384 ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); 360 ret = asoc_simple_parse_cpu(cpu_ep, dai_link, &single_cpu);
385 if (ret < 0) 361 if (ret < 0)
386 return ret; 362 return ret;
387 363
388 ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link); 364 ret = asoc_simple_parse_codec(codec_ep, dai_link);
389 if (ret < 0) 365 if (ret < 0)
390 return ret; 366 return ret;
391 367
392 ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai); 368 ret = asoc_simple_parse_tdm(cpu_ep, cpu_dai);
393 if (ret < 0) 369 if (ret < 0)
394 return ret; 370 return ret;
395 371
396 ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai); 372 ret = asoc_simple_parse_tdm(codec_ep, codec_dai);
397 if (ret < 0) 373 if (ret < 0)
398 return ret; 374 return ret;
399 375
400 ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai); 376 ret = asoc_simple_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
401 if (ret < 0) 377 if (ret < 0)
402 return ret; 378 return ret;
403 379
404 ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai); 380 ret = asoc_simple_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
405 if (ret < 0) 381 if (ret < 0)
406 return ret; 382 return ret;
407 383
408 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 384 ret = asoc_simple_set_dailink_name(dev, dai_link,
409 "%s-%s", 385 "%s-%s",
410 dai_link->cpu_dai_name, 386 dai_link->cpu_dai_name,
411 dai_link->codecs->dai_name); 387 dai_link->codecs->dai_name);
412 if (ret < 0) 388 if (ret < 0)
413 return ret; 389 return ret;
414 390
415 dai_link->ops = &graph_ops; 391 dai_link->ops = &graph_ops;
416 dai_link->init = graph_dai_init; 392 dai_link->init = asoc_simple_dai_init;
417 393
418 asoc_simple_card_canonicalize_platform(dai_link); 394 asoc_simple_canonicalize_cpu(dai_link, single_cpu);
419 asoc_simple_card_canonicalize_cpu(dai_link, 395 asoc_simple_canonicalize_platform(dai_link);
420 of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1);
421 396
422 return 0; 397 return 0;
423} 398}
424 399
425static int graph_for_each_link(struct graph_priv *priv, 400static int graph_for_each_link(struct asoc_simple_priv *priv,
426 struct link_info *li, 401 struct link_info *li,
427 int (*func_noml)(struct graph_priv *priv, 402 int (*func_noml)(struct asoc_simple_priv *priv,
428 struct device_node *cpu_ep, 403 struct device_node *cpu_ep,
429 struct device_node *codec_ep, 404 struct device_node *codec_ep,
430 struct link_info *li), 405 struct link_info *li),
431 int (*func_dpcm)(struct graph_priv *priv, 406 int (*func_dpcm)(struct asoc_simple_priv *priv,
432 struct device_node *cpu_ep, 407 struct device_node *cpu_ep,
433 struct device_node *codec_ep, 408 struct device_node *codec_ep,
434 struct link_info *li, int dup_codec)) 409 struct link_info *li, int dup_codec))
435{ 410{
436 struct of_phandle_iterator it; 411 struct of_phandle_iterator it;
437 struct device *dev = graph_priv_to_dev(priv); 412 struct device *dev = simple_priv_to_dev(priv);
438 struct device_node *node = dev->of_node; 413 struct device_node *node = dev->of_node;
439 struct device_node *cpu_port; 414 struct device_node *cpu_port;
440 struct device_node *cpu_ep; 415 struct device_node *cpu_ep;
441 struct device_node *codec_ep; 416 struct device_node *codec_ep;
442 struct device_node *codec_port; 417 struct device_node *codec_port;
443 struct device_node *codec_port_old = NULL; 418 struct device_node *codec_port_old = NULL;
444 struct asoc_simple_card_data adata; 419 struct asoc_simple_data adata;
445 uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); 420 uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
446 int rc, ret; 421 int rc, ret;
447 422
@@ -465,8 +440,8 @@ static int graph_for_each_link(struct graph_priv *priv,
465 440
466 /* get convert-xxx property */ 441 /* get convert-xxx property */
467 memset(&adata, 0, sizeof(adata)); 442 memset(&adata, 0, sizeof(adata));
468 graph_get_conversion(dev, codec_ep, &adata); 443 graph_parse_convert(dev, codec_ep, &adata);
469 graph_get_conversion(dev, cpu_ep, &adata); 444 graph_parse_convert(dev, cpu_ep, &adata);
470 445
471 /* 446 /*
472 * It is DPCM 447 * It is DPCM
@@ -492,17 +467,17 @@ static int graph_for_each_link(struct graph_priv *priv,
492 return 0; 467 return 0;
493} 468}
494 469
495static int graph_parse_of(struct graph_priv *priv) 470static int graph_parse_of(struct asoc_simple_priv *priv)
496{ 471{
497 struct snd_soc_card *card = graph_priv_to_card(priv); 472 struct snd_soc_card *card = simple_priv_to_card(priv);
498 struct link_info li; 473 struct link_info li;
499 int ret; 474 int ret;
500 475
501 ret = asoc_simple_card_of_parse_widgets(card, NULL); 476 ret = asoc_simple_parse_widgets(card, NULL);
502 if (ret < 0) 477 if (ret < 0)
503 return ret; 478 return ret;
504 479
505 ret = asoc_simple_card_of_parse_routing(card, NULL); 480 ret = asoc_simple_parse_routing(card, NULL);
506 if (ret < 0) 481 if (ret < 0)
507 return ret; 482 return ret;
508 483
@@ -527,15 +502,15 @@ static int graph_parse_of(struct graph_priv *priv)
527 return ret; 502 return ret;
528 } 503 }
529 504
530 return asoc_simple_card_parse_card_name(card, NULL); 505 return asoc_simple_parse_card_name(card, NULL);
531} 506}
532 507
533static int graph_count_noml(struct graph_priv *priv, 508static int graph_count_noml(struct asoc_simple_priv *priv,
534 struct device_node *cpu_ep, 509 struct device_node *cpu_ep,
535 struct device_node *codec_ep, 510 struct device_node *codec_ep,
536 struct link_info *li) 511 struct link_info *li)
537{ 512{
538 struct device *dev = graph_priv_to_dev(priv); 513 struct device *dev = simple_priv_to_dev(priv);
539 514
540 li->link += 1; /* 1xCPU-Codec */ 515 li->link += 1; /* 1xCPU-Codec */
541 li->dais += 2; /* 1xCPU + 1xCodec */ 516 li->dais += 2; /* 1xCPU + 1xCodec */
@@ -545,13 +520,13 @@ static int graph_count_noml(struct graph_priv *priv,
545 return 0; 520 return 0;
546} 521}
547 522
548static int graph_count_dpcm(struct graph_priv *priv, 523static int graph_count_dpcm(struct asoc_simple_priv *priv,
549 struct device_node *cpu_ep, 524 struct device_node *cpu_ep,
550 struct device_node *codec_ep, 525 struct device_node *codec_ep,
551 struct link_info *li, 526 struct link_info *li,
552 int dup_codec) 527 int dup_codec)
553{ 528{
554 struct device *dev = graph_priv_to_dev(priv); 529 struct device *dev = simple_priv_to_dev(priv);
555 530
556 li->link++; /* 1xCPU-dummy */ 531 li->link++; /* 1xCPU-dummy */
557 li->dais++; /* 1xCPU */ 532 li->dais++; /* 1xCPU */
@@ -567,10 +542,10 @@ static int graph_count_dpcm(struct graph_priv *priv,
567 return 0; 542 return 0;
568} 543}
569 544
570static void graph_get_dais_count(struct graph_priv *priv, 545static void graph_get_dais_count(struct asoc_simple_priv *priv,
571 struct link_info *li) 546 struct link_info *li)
572{ 547{
573 struct device *dev = graph_priv_to_dev(priv); 548 struct device *dev = simple_priv_to_dev(priv);
574 549
575 /* 550 /*
576 * link_num : number of links. 551 * link_num : number of links.
@@ -627,14 +602,14 @@ static void graph_get_dais_count(struct graph_priv *priv,
627 602
628static int graph_card_probe(struct snd_soc_card *card) 603static int graph_card_probe(struct snd_soc_card *card)
629{ 604{
630 struct graph_priv *priv = snd_soc_card_get_drvdata(card); 605 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
631 int ret; 606 int ret;
632 607
633 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL); 608 ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
634 if (ret < 0) 609 if (ret < 0)
635 return ret; 610 return ret;
636 611
637 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, NULL); 612 ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL);
638 if (ret < 0) 613 if (ret < 0)
639 return ret; 614 return ret;
640 615
@@ -643,22 +618,18 @@ static int graph_card_probe(struct snd_soc_card *card)
643 618
644static int graph_probe(struct platform_device *pdev) 619static int graph_probe(struct platform_device *pdev)
645{ 620{
646 struct graph_priv *priv; 621 struct asoc_simple_priv *priv;
647 struct snd_soc_dai_link *dai_link;
648 struct graph_dai_props *dai_props;
649 struct asoc_simple_dai *dais;
650 struct device *dev = &pdev->dev; 622 struct device *dev = &pdev->dev;
651 struct snd_soc_card *card; 623 struct snd_soc_card *card;
652 struct snd_soc_codec_conf *cconf;
653 struct link_info li; 624 struct link_info li;
654 int ret, i; 625 int ret;
655 626
656 /* Allocate the private data and the DAI link array */ 627 /* Allocate the private data and the DAI link array */
657 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 628 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
658 if (!priv) 629 if (!priv)
659 return -ENOMEM; 630 return -ENOMEM;
660 631
661 card = graph_priv_to_card(priv); 632 card = simple_priv_to_card(priv);
662 card->owner = THIS_MODULE; 633 card->owner = THIS_MODULE;
663 card->dev = dev; 634 card->dev = dev;
664 card->dapm_widgets = graph_dapm_widgets; 635 card->dapm_widgets = graph_dapm_widgets;
@@ -670,25 +641,9 @@ static int graph_probe(struct platform_device *pdev)
670 if (!li.link || !li.dais) 641 if (!li.link || !li.dais)
671 return -EINVAL; 642 return -EINVAL;
672 643
673 dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); 644 ret = asoc_simple_init_priv(priv, &li);
674 dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); 645 if (ret < 0)
675 dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); 646 return ret;
676 cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL);
677 if (!dai_props || !dai_link || !dais)
678 return -ENOMEM;
679
680 /*
681 * Use snd_soc_dai_link_component instead of legacy style
682 * It is codec only. but cpu/platform will be supported in the future.
683 * see
684 * soc-core.c :: snd_soc_init_multicodec()
685 */
686 for (i = 0; i < li.link; i++) {
687 dai_link[i].codecs = &dai_props[i].codecs;
688 dai_link[i].num_codecs = 1;
689 dai_link[i].platforms = &dai_props[i].platforms;
690 dai_link[i].num_platforms = 1;
691 }
692 647
693 priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); 648 priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
694 if (IS_ERR(priv->pa_gpio)) { 649 if (IS_ERR(priv->pa_gpio)) {
@@ -697,16 +652,6 @@ static int graph_probe(struct platform_device *pdev)
697 return ret; 652 return ret;
698 } 653 }
699 654
700 priv->dai_props = dai_props;
701 priv->dai_link = dai_link;
702 priv->dais = dais;
703 priv->codec_conf = cconf;
704
705 card->dai_link = dai_link;
706 card->num_links = li.link;
707 card->codec_conf = cconf;
708 card->num_configs = li.conf;
709
710 ret = graph_parse_of(priv); 655 ret = graph_parse_of(priv);
711 if (ret < 0) { 656 if (ret < 0) {
712 if (ret != -EPROBE_DEFER) 657 if (ret != -EPROBE_DEFER)
@@ -716,13 +661,15 @@ static int graph_probe(struct platform_device *pdev)
716 661
717 snd_soc_card_set_drvdata(card, priv); 662 snd_soc_card_set_drvdata(card, priv);
718 663
664 asoc_simple_debug_info(priv);
665
719 ret = devm_snd_soc_register_card(dev, card); 666 ret = devm_snd_soc_register_card(dev, card);
720 if (ret < 0) 667 if (ret < 0)
721 goto err; 668 goto err;
722 669
723 return 0; 670 return 0;
724err: 671err:
725 asoc_simple_card_clean_reference(card); 672 asoc_simple_clean_reference(card);
726 673
727 return ret; 674 return ret;
728} 675}
@@ -731,7 +678,7 @@ static int graph_remove(struct platform_device *pdev)
731{ 678{
732 struct snd_soc_card *card = platform_get_drvdata(pdev); 679 struct snd_soc_card *card = platform_get_drvdata(pdev);
733 680
734 return asoc_simple_card_clean_reference(card); 681 return asoc_simple_clean_reference(card);
735} 682}
736 683
737static const struct of_device_id graph_of_match[] = { 684static const struct of_device_id graph_of_match[] = {
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 5c1424f03620..f4c6375d11c7 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -14,8 +14,8 @@
14#include <sound/jack.h> 14#include <sound/jack.h>
15#include <sound/simple_card_utils.h> 15#include <sound/simple_card_utils.h>
16 16
17void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, 17void asoc_simple_convert_fixup(struct asoc_simple_data *data,
18 struct snd_pcm_hw_params *params) 18 struct snd_pcm_hw_params *params)
19{ 19{
20 struct snd_interval *rate = hw_param_interval(params, 20 struct snd_interval *rate = hw_param_interval(params,
21 SNDRV_PCM_HW_PARAM_RATE); 21 SNDRV_PCM_HW_PARAM_RATE);
@@ -30,12 +30,12 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
30 channels->min = 30 channels->min =
31 channels->max = data->convert_channels; 31 channels->max = data->convert_channels;
32} 32}
33EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup); 33EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup);
34 34
35void asoc_simple_card_parse_convert(struct device *dev, 35void asoc_simple_parse_convert(struct device *dev,
36 struct device_node *np, 36 struct device_node *np,
37 char *prefix, 37 char *prefix,
38 struct asoc_simple_card_data *data) 38 struct asoc_simple_data *data)
39{ 39{
40 char prop[128]; 40 char prop[128];
41 41
@@ -49,17 +49,14 @@ void asoc_simple_card_parse_convert(struct device *dev,
49 /* channels transfer */ 49 /* channels transfer */
50 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels"); 50 snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
51 of_property_read_u32(np, prop, &data->convert_channels); 51 of_property_read_u32(np, prop, &data->convert_channels);
52
53 dev_dbg(dev, "convert_rate %d\n", data->convert_rate);
54 dev_dbg(dev, "convert_channels %d\n", data->convert_channels);
55} 52}
56EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert); 53EXPORT_SYMBOL_GPL(asoc_simple_parse_convert);
57 54
58int asoc_simple_card_parse_daifmt(struct device *dev, 55int asoc_simple_parse_daifmt(struct device *dev,
59 struct device_node *node, 56 struct device_node *node,
60 struct device_node *codec, 57 struct device_node *codec,
61 char *prefix, 58 char *prefix,
62 unsigned int *retfmt) 59 unsigned int *retfmt)
63{ 60{
64 struct device_node *bitclkmaster = NULL; 61 struct device_node *bitclkmaster = NULL;
65 struct device_node *framemaster = NULL; 62 struct device_node *framemaster = NULL;
@@ -93,15 +90,13 @@ int asoc_simple_card_parse_daifmt(struct device *dev,
93 90
94 *retfmt = daifmt; 91 *retfmt = daifmt;
95 92
96 dev_dbg(dev, "format : %04x\n", daifmt);
97
98 return 0; 93 return 0;
99} 94}
100EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt); 95EXPORT_SYMBOL_GPL(asoc_simple_parse_daifmt);
101 96
102int asoc_simple_card_set_dailink_name(struct device *dev, 97int asoc_simple_set_dailink_name(struct device *dev,
103 struct snd_soc_dai_link *dai_link, 98 struct snd_soc_dai_link *dai_link,
104 const char *fmt, ...) 99 const char *fmt, ...)
105{ 100{
106 va_list ap; 101 va_list ap;
107 char *name = NULL; 102 char *name = NULL;
@@ -116,16 +111,14 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
116 111
117 dai_link->name = name; 112 dai_link->name = name;
118 dai_link->stream_name = name; 113 dai_link->stream_name = name;
119
120 dev_dbg(dev, "name : %s\n", name);
121 } 114 }
122 115
123 return ret; 116 return ret;
124} 117}
125EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name); 118EXPORT_SYMBOL_GPL(asoc_simple_set_dailink_name);
126 119
127int asoc_simple_card_parse_card_name(struct snd_soc_card *card, 120int asoc_simple_parse_card_name(struct snd_soc_card *card,
128 char *prefix) 121 char *prefix)
129{ 122{
130 int ret; 123 int ret;
131 124
@@ -146,34 +139,30 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
146 if (!card->name && card->dai_link) 139 if (!card->name && card->dai_link)
147 card->name = card->dai_link->name; 140 card->name = card->dai_link->name;
148 141
149 dev_dbg(card->dev, "Card Name: %s\n", card->name ? card->name : "");
150
151 return 0; 142 return 0;
152} 143}
153EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); 144EXPORT_SYMBOL_GPL(asoc_simple_parse_card_name);
154 145
155int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai) 146static int asoc_simple_clk_enable(struct asoc_simple_dai *dai)
156{ 147{
157 if (dai) 148 if (dai)
158 return clk_prepare_enable(dai->clk); 149 return clk_prepare_enable(dai->clk);
159 150
160 return 0; 151 return 0;
161} 152}
162EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
163 153
164void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai) 154static void asoc_simple_clk_disable(struct asoc_simple_dai *dai)
165{ 155{
166 if (dai) 156 if (dai)
167 clk_disable_unprepare(dai->clk); 157 clk_disable_unprepare(dai->clk);
168} 158}
169EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable); 159
170 160int asoc_simple_parse_clk(struct device *dev,
171int asoc_simple_card_parse_clk(struct device *dev, 161 struct device_node *node,
172 struct device_node *node, 162 struct device_node *dai_of_node,
173 struct device_node *dai_of_node, 163 struct asoc_simple_dai *simple_dai,
174 struct asoc_simple_dai *simple_dai, 164 const char *dai_name,
175 const char *dai_name, 165 struct snd_soc_dai_link_component *dlc)
176 struct snd_soc_dai_link_component *dlc)
177{ 166{
178 struct clk *clk; 167 struct clk *clk;
179 u32 val; 168 u32 val;
@@ -184,10 +173,8 @@ int asoc_simple_card_parse_clk(struct device *dev,
184 * see 173 * see
185 * soc-core.c :: snd_soc_init_multicodec() 174 * soc-core.c :: snd_soc_init_multicodec()
186 */ 175 */
187 if (dlc) { 176 if (dlc)
188 dai_of_node = dlc->of_node; 177 dai_of_node = dlc->of_node;
189 dai_name = dlc->dai_name;
190 }
191 178
192 /* 179 /*
193 * Parse dai->sysclk come from "clocks = <&xxx>" 180 * Parse dai->sysclk come from "clocks = <&xxx>"
@@ -211,158 +198,113 @@ int asoc_simple_card_parse_clk(struct device *dev,
211 if (of_property_read_bool(node, "system-clock-direction-out")) 198 if (of_property_read_bool(node, "system-clock-direction-out"))
212 simple_dai->clk_direction = SND_SOC_CLOCK_OUT; 199 simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
213 200
214 dev_dbg(dev, "%s : sysclk = %d, direction %d\n", dai_name,
215 simple_dai->sysclk, simple_dai->clk_direction);
216
217 return 0; 201 return 0;
218} 202}
219EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk); 203EXPORT_SYMBOL_GPL(asoc_simple_parse_clk);
220 204
221int asoc_simple_card_parse_dai(struct device_node *node, 205int asoc_simple_startup(struct snd_pcm_substream *substream)
222 struct snd_soc_dai_link_component *dlc,
223 struct device_node **dai_of_node,
224 const char **dai_name,
225 const char *list_name,
226 const char *cells_name,
227 int *is_single_link)
228{ 206{
229 struct of_phandle_args args; 207 struct snd_soc_pcm_runtime *rtd = substream->private_data;
208 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
209 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
230 int ret; 210 int ret;
231 211
232 if (!node) 212 ret = asoc_simple_clk_enable(dai_props->cpu_dai);
233 return 0;
234
235 /*
236 * Use snd_soc_dai_link_component instead of legacy style.
237 * It is only for codec, but cpu will be supported in the future.
238 * see
239 * soc-core.c :: snd_soc_init_multicodec()
240 */
241 if (dlc) {
242 dai_name = &dlc->dai_name;
243 dai_of_node = &dlc->of_node;
244 }
245
246 /*
247 * Get node via "sound-dai = <&phandle port>"
248 * it will be used as xxx_of_node on soc_bind_dai_link()
249 */
250 ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args);
251 if (ret) 213 if (ret)
252 return ret; 214 return ret;
253 215
254 /* Get dai->name */ 216 ret = asoc_simple_clk_enable(dai_props->codec_dai);
255 if (dai_name) { 217 if (ret)
256 ret = snd_soc_of_get_dai_name(node, dai_name); 218 asoc_simple_clk_disable(dai_props->cpu_dai);
257 if (ret < 0)
258 return ret;
259 }
260
261 *dai_of_node = args.np;
262
263 if (is_single_link)
264 *is_single_link = !args.args_count;
265 219
266 return 0; 220 return ret;
267} 221}
268EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai); 222EXPORT_SYMBOL_GPL(asoc_simple_startup);
269 223
270static int asoc_simple_card_get_dai_id(struct device_node *ep) 224void asoc_simple_shutdown(struct snd_pcm_substream *substream)
271{ 225{
272 struct device_node *node; 226 struct snd_soc_pcm_runtime *rtd = substream->private_data;
273 struct device_node *endpoint; 227 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
274 struct of_endpoint info; 228 struct simple_dai_props *dai_props =
275 int i, id; 229 simple_priv_to_props(priv, rtd->num);
276 int ret;
277 230
278 /* use driver specified DAI ID if exist */ 231 asoc_simple_clk_disable(dai_props->cpu_dai);
279 ret = snd_soc_get_dai_id(ep);
280 if (ret != -ENOTSUPP)
281 return ret;
282 232
283 /* use endpoint/port reg if exist */ 233 asoc_simple_clk_disable(dai_props->codec_dai);
284 ret = of_graph_parse_endpoint(ep, &info); 234}
285 if (ret == 0) { 235EXPORT_SYMBOL_GPL(asoc_simple_shutdown);
286 /*
287 * Because it will count port/endpoint if it doesn't have "reg".
288 * But, we can't judge whether it has "no reg", or "reg = <0>"
289 * only of_graph_parse_endpoint().
290 * We need to check "reg" property
291 */
292 if (of_get_property(ep, "reg", NULL))
293 return info.id;
294
295 node = of_get_parent(ep);
296 of_node_put(node);
297 if (of_get_property(node, "reg", NULL))
298 return info.port;
299 }
300 node = of_graph_get_port_parent(ep);
301 236
302 /* 237static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
303 * Non HDMI sound case, counting port/endpoint on its DT 238 unsigned long rate)
304 * is enough. Let's count it. 239{
305 */ 240 if (!simple_dai)
306 i = 0; 241 return 0;
307 id = -1;
308 for_each_endpoint_of_node(node, endpoint) {
309 if (endpoint == ep)
310 id = i;
311 i++;
312 }
313 242
314 of_node_put(node); 243 if (!simple_dai->clk)
244 return 0;
315 245
316 if (id < 0) 246 if (clk_get_rate(simple_dai->clk) == rate)
317 return -ENODEV; 247 return 0;
318 248
319 return id; 249 return clk_set_rate(simple_dai->clk, rate);
320} 250}
321 251
322int asoc_simple_card_parse_graph_dai(struct device_node *ep, 252int asoc_simple_hw_params(struct snd_pcm_substream *substream,
323 struct snd_soc_dai_link_component *dlc, 253 struct snd_pcm_hw_params *params)
324 struct device_node **dai_of_node,
325 const char **dai_name)
326{ 254{
327 struct device_node *node; 255 struct snd_soc_pcm_runtime *rtd = substream->private_data;
328 struct of_phandle_args args; 256 struct snd_soc_dai *codec_dai = rtd->codec_dai;
329 int ret; 257 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
330 258 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
331 /* 259 struct simple_dai_props *dai_props =
332 * Use snd_soc_dai_link_component instead of legacy style. 260 simple_priv_to_props(priv, rtd->num);
333 * It is only for codec, but cpu will be supported in the future. 261 unsigned int mclk, mclk_fs = 0;
334 * see 262 int ret = 0;
335 * soc-core.c :: snd_soc_init_multicodec() 263
336 */ 264 if (dai_props->mclk_fs)
337 if (dlc) { 265 mclk_fs = dai_props->mclk_fs;
338 dai_name = &dlc->dai_name; 266
339 dai_of_node = &dlc->of_node; 267 if (mclk_fs) {
340 } 268 mclk = params_rate(params) * mclk_fs;
269
270 ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk);
271 if (ret < 0)
272 return ret;
341 273
342 if (!ep) 274 ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk);
343 return 0; 275 if (ret < 0)
344 if (!dai_name) 276 return ret;
345 return 0;
346 277
347 node = of_graph_get_port_parent(ep); 278 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
279 SND_SOC_CLOCK_IN);
280 if (ret && ret != -ENOTSUPP)
281 goto err;
348 282
349 /* Get dai->name */ 283 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
350 args.np = node; 284 SND_SOC_CLOCK_OUT);
351 args.args[0] = asoc_simple_card_get_dai_id(ep); 285 if (ret && ret != -ENOTSUPP)
352 args.args_count = (of_graph_get_endpoint_count(node) > 1); 286 goto err;
287 }
288 return 0;
289err:
290 return ret;
291}
292EXPORT_SYMBOL_GPL(asoc_simple_hw_params);
353 293
354 ret = snd_soc_get_dai_name(&args, dai_name); 294int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
355 if (ret < 0) 295 struct snd_pcm_hw_params *params)
356 return ret; 296{
297 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
298 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
357 299
358 *dai_of_node = node; 300 asoc_simple_convert_fixup(&dai_props->adata, params);
359 301
360 return 0; 302 return 0;
361} 303}
362EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai); 304EXPORT_SYMBOL_GPL(asoc_simple_be_hw_params_fixup);
363 305
364int asoc_simple_card_init_dai(struct snd_soc_dai *dai, 306static int asoc_simple_init_dai(struct snd_soc_dai *dai,
365 struct asoc_simple_dai *simple_dai) 307 struct asoc_simple_dai *simple_dai)
366{ 308{
367 int ret; 309 int ret;
368 310
@@ -392,18 +334,37 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
392 334
393 return 0; 335 return 0;
394} 336}
395EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);
396 337
397void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link) 338int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
339{
340 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
341 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
342 int ret;
343
344 ret = asoc_simple_init_dai(rtd->codec_dai,
345 dai_props->codec_dai);
346 if (ret < 0)
347 return ret;
348
349 ret = asoc_simple_init_dai(rtd->cpu_dai,
350 dai_props->cpu_dai);
351 if (ret < 0)
352 return ret;
353
354 return 0;
355}
356EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
357
358void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link)
398{ 359{
399 /* Assumes platform == cpu */ 360 /* Assumes platform == cpu */
400 if (!dai_link->platforms->of_node) 361 if (!dai_link->platforms->of_node)
401 dai_link->platforms->of_node = dai_link->cpu_of_node; 362 dai_link->platforms->of_node = dai_link->cpu_of_node;
402} 363}
403EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_platform); 364EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
404 365
405void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, 366void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
406 int is_single_links) 367 int is_single_links)
407{ 368{
408 /* 369 /*
409 * In soc_bind_dai_link() will check cpu name after 370 * In soc_bind_dai_link() will check cpu name after
@@ -417,9 +378,9 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
417 if (is_single_links) 378 if (is_single_links)
418 dai_link->cpu_dai_name = NULL; 379 dai_link->cpu_dai_name = NULL;
419} 380}
420EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu); 381EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
421 382
422int asoc_simple_card_clean_reference(struct snd_soc_card *card) 383int asoc_simple_clean_reference(struct snd_soc_card *card)
423{ 384{
424 struct snd_soc_dai_link *dai_link; 385 struct snd_soc_dai_link *dai_link;
425 int i; 386 int i;
@@ -430,10 +391,10 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card)
430 } 391 }
431 return 0; 392 return 0;
432} 393}
433EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); 394EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
434 395
435int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, 396int asoc_simple_parse_routing(struct snd_soc_card *card,
436 char *prefix) 397 char *prefix)
437{ 398{
438 struct device_node *node = card->dev->of_node; 399 struct device_node *node = card->dev->of_node;
439 char prop[128]; 400 char prop[128];
@@ -448,10 +409,10 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
448 409
449 return snd_soc_of_parse_audio_routing(card, prop); 410 return snd_soc_of_parse_audio_routing(card, prop);
450} 411}
451EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing); 412EXPORT_SYMBOL_GPL(asoc_simple_parse_routing);
452 413
453int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card, 414int asoc_simple_parse_widgets(struct snd_soc_card *card,
454 char *prefix) 415 char *prefix)
455{ 416{
456 struct device_node *node = card->dev->of_node; 417 struct device_node *node = card->dev->of_node;
457 char prop[128]; 418 char prop[128];
@@ -467,11 +428,68 @@ int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
467 /* no widgets is not error */ 428 /* no widgets is not error */
468 return 0; 429 return 0;
469} 430}
470EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets); 431EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets);
432
433int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
434 char *prefix)
435{
436 const unsigned int nb_controls_max = 16;
437 const char **strings, *control_name;
438 struct snd_kcontrol_new *controls;
439 struct device *dev = card->dev;
440 unsigned int i, nb_controls;
441 char prop[128];
442 int ret;
443
444 if (!prefix)
445 prefix = "";
446
447 snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
448
449 if (!of_property_read_bool(dev->of_node, prop))
450 return 0;
451
452 strings = devm_kcalloc(dev, nb_controls_max,
453 sizeof(*strings), GFP_KERNEL);
454 if (!strings)
455 return -ENOMEM;
456
457 ret = of_property_read_string_array(dev->of_node, prop,
458 strings, nb_controls_max);
459 if (ret < 0)
460 return ret;
461
462 nb_controls = (unsigned int)ret;
463
464 controls = devm_kcalloc(dev, nb_controls,
465 sizeof(*controls), GFP_KERNEL);
466 if (!controls)
467 return -ENOMEM;
468
469 for (i = 0; i < nb_controls; i++) {
470 control_name = devm_kasprintf(dev, GFP_KERNEL,
471 "%s Switch", strings[i]);
472 if (!control_name)
473 return -ENOMEM;
474
475 controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
476 controls[i].name = control_name;
477 controls[i].info = snd_soc_dapm_info_pin_switch;
478 controls[i].get = snd_soc_dapm_get_pin_switch;
479 controls[i].put = snd_soc_dapm_put_pin_switch;
480 controls[i].private_value = (unsigned long)strings[i];
481 }
482
483 card->controls = controls;
484 card->num_controls = nb_controls;
485
486 return 0;
487}
488EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
471 489
472int asoc_simple_card_init_jack(struct snd_soc_card *card, 490int asoc_simple_init_jack(struct snd_soc_card *card,
473 struct asoc_simple_jack *sjack, 491 struct asoc_simple_jack *sjack,
474 int is_hp, char *prefix) 492 int is_hp, char *prefix)
475{ 493{
476 struct device *dev = card->dev; 494 struct device *dev = card->dev;
477 enum of_gpio_flags flags; 495 enum of_gpio_flags flags;
@@ -522,7 +540,61 @@ int asoc_simple_card_init_jack(struct snd_soc_card *card,
522 540
523 return 0; 541 return 0;
524} 542}
525EXPORT_SYMBOL_GPL(asoc_simple_card_init_jack); 543EXPORT_SYMBOL_GPL(asoc_simple_init_jack);
544
545int asoc_simple_init_priv(struct asoc_simple_priv *priv,
546 struct link_info *li)
547{
548 struct snd_soc_card *card = simple_priv_to_card(priv);
549 struct device *dev = simple_priv_to_dev(priv);
550 struct snd_soc_dai_link *dai_link;
551 struct simple_dai_props *dai_props;
552 struct asoc_simple_dai *dais;
553 struct snd_soc_codec_conf *cconf = NULL;
554 int i;
555
556 dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
557 dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL);
558 dais = devm_kcalloc(dev, li->dais, sizeof(*dais), GFP_KERNEL);
559 if (!dai_props || !dai_link || !dais)
560 return -ENOMEM;
561
562 if (li->conf) {
563 cconf = devm_kcalloc(dev, li->conf, sizeof(*cconf), GFP_KERNEL);
564 if (!cconf)
565 return -ENOMEM;
566 }
567
568 /*
569 * Use snd_soc_dai_link_component instead of legacy style
570 * It is codec only. but cpu/platform will be supported in the future.
571 * see
572 * soc-core.c :: snd_soc_init_multicodec()
573 *
574 * "platform" might be removed
575 * see
576 * simple-card-utils.c :: asoc_simple_canonicalize_platform()
577 */
578 for (i = 0; i < li->link; i++) {
579 dai_link[i].codecs = &dai_props[i].codecs;
580 dai_link[i].num_codecs = 1;
581 dai_link[i].platforms = &dai_props[i].platforms;
582 dai_link[i].num_platforms = 1;
583 }
584
585 priv->dai_props = dai_props;
586 priv->dai_link = dai_link;
587 priv->dais = dais;
588 priv->codec_conf = cconf;
589
590 card->dai_link = priv->dai_link;
591 card->num_links = li->link;
592 card->codec_conf = cconf;
593 card->num_configs = li->conf;
594
595 return 0;
596}
597EXPORT_SYMBOL_GPL(asoc_simple_init_priv);
526 598
527/* Module information */ 599/* Module information */
528MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 600MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 34de32efc4c4..9b568f578bcd 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -18,179 +18,98 @@
18 18
19#define DPCM_SELECTABLE 1 19#define DPCM_SELECTABLE 1
20 20
21struct simple_priv {
22 struct snd_soc_card snd_card;
23 struct simple_dai_props {
24 struct asoc_simple_dai *cpu_dai;
25 struct asoc_simple_dai *codec_dai;
26 struct snd_soc_dai_link_component codecs; /* single codec */
27 struct snd_soc_dai_link_component platforms;
28 struct asoc_simple_card_data adata;
29 struct snd_soc_codec_conf *codec_conf;
30 unsigned int mclk_fs;
31 } *dai_props;
32 struct asoc_simple_jack hp_jack;
33 struct asoc_simple_jack mic_jack;
34 struct snd_soc_dai_link *dai_link;
35 struct asoc_simple_dai *dais;
36 struct snd_soc_codec_conf *codec_conf;
37};
38
39struct link_info {
40 int dais; /* number of dai */
41 int link; /* number of link */
42 int conf; /* number of codec_conf */
43 int cpu; /* turn for CPU / Codec */
44};
45
46#define simple_priv_to_card(priv) (&(priv)->snd_card)
47#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
48#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
49#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
50
51#define DAI "sound-dai" 21#define DAI "sound-dai"
52#define CELL "#sound-dai-cells" 22#define CELL "#sound-dai-cells"
53#define PREFIX "simple-audio-card," 23#define PREFIX "simple-audio-card,"
54 24
55static int simple_startup(struct snd_pcm_substream *substream) 25static const struct snd_soc_ops simple_ops = {
56{ 26 .startup = asoc_simple_startup,
57 struct snd_soc_pcm_runtime *rtd = substream->private_data; 27 .shutdown = asoc_simple_shutdown,
58 struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 28 .hw_params = asoc_simple_hw_params,
59 struct simple_dai_props *dai_props = 29};
60 simple_priv_to_props(priv, rtd->num);
61 int ret;
62
63 ret = asoc_simple_card_clk_enable(dai_props->cpu_dai);
64 if (ret)
65 return ret;
66
67 ret = asoc_simple_card_clk_enable(dai_props->codec_dai);
68 if (ret)
69 asoc_simple_card_clk_disable(dai_props->cpu_dai);
70
71 return ret;
72}
73
74static void simple_shutdown(struct snd_pcm_substream *substream)
75{
76 struct snd_soc_pcm_runtime *rtd = substream->private_data;
77 struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
78 struct simple_dai_props *dai_props =
79 simple_priv_to_props(priv, rtd->num);
80
81 asoc_simple_card_clk_disable(dai_props->cpu_dai);
82
83 asoc_simple_card_clk_disable(dai_props->codec_dai);
84}
85 30
86static int simple_set_clk_rate(struct asoc_simple_dai *simple_dai, 31static int asoc_simple_parse_dai(struct device_node *node,
87 unsigned long rate) 32 struct snd_soc_dai_link_component *dlc,
33 struct device_node **dai_of_node,
34 const char **dai_name,
35 int *is_single_link)
88{ 36{
89 if (!simple_dai) 37 struct of_phandle_args args;
90 return 0; 38 int ret;
91
92 if (!simple_dai->clk)
93 return 0;
94 39
95 if (clk_get_rate(simple_dai->clk) == rate) 40 if (!node)
96 return 0; 41 return 0;
97 42
98 return clk_set_rate(simple_dai->clk, rate); 43 /*
99} 44 * Use snd_soc_dai_link_component instead of legacy style.
100 45 * It is only for codec, but cpu will be supported in the future.
101static int simple_hw_params(struct snd_pcm_substream *substream, 46 * see
102 struct snd_pcm_hw_params *params) 47 * soc-core.c :: snd_soc_init_multicodec()
103{ 48 */
104 struct snd_soc_pcm_runtime *rtd = substream->private_data; 49 if (dlc) {
105 struct snd_soc_dai *codec_dai = rtd->codec_dai; 50 dai_name = &dlc->dai_name;
106 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 51 dai_of_node = &dlc->of_node;
107 struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 52 }
108 struct simple_dai_props *dai_props =
109 simple_priv_to_props(priv, rtd->num);
110 unsigned int mclk, mclk_fs = 0;
111 int ret = 0;
112
113 if (dai_props->mclk_fs)
114 mclk_fs = dai_props->mclk_fs;
115
116 if (mclk_fs) {
117 mclk = params_rate(params) * mclk_fs;
118 53
119 ret = simple_set_clk_rate(dai_props->codec_dai, mclk); 54 /*
120 if (ret < 0) 55 * Get node via "sound-dai = <&phandle port>"
121 return ret; 56 * it will be used as xxx_of_node on soc_bind_dai_link()
57 */
58 ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
59 if (ret)
60 return ret;
122 61
123 ret = simple_set_clk_rate(dai_props->cpu_dai, mclk); 62 /* Get dai->name */
63 if (dai_name) {
64 ret = snd_soc_of_get_dai_name(node, dai_name);
124 if (ret < 0) 65 if (ret < 0)
125 return ret; 66 return ret;
126
127 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
128 SND_SOC_CLOCK_IN);
129 if (ret && ret != -ENOTSUPP)
130 goto err;
131
132 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
133 SND_SOC_CLOCK_OUT);
134 if (ret && ret != -ENOTSUPP)
135 goto err;
136 } 67 }
137 return 0;
138err:
139 return ret;
140}
141
142static const struct snd_soc_ops simple_ops = {
143 .startup = simple_startup,
144 .shutdown = simple_shutdown,
145 .hw_params = simple_hw_params,
146};
147 68
148static int simple_dai_init(struct snd_soc_pcm_runtime *rtd) 69 *dai_of_node = args.np;
149{
150 struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
151 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
152 int ret;
153 70
154 ret = asoc_simple_card_init_dai(rtd->codec_dai, 71 if (is_single_link)
155 dai_props->codec_dai); 72 *is_single_link = !args.args_count;
156 if (ret < 0)
157 return ret;
158
159 ret = asoc_simple_card_init_dai(rtd->cpu_dai,
160 dai_props->cpu_dai);
161 if (ret < 0)
162 return ret;
163 73
164 return 0; 74 return 0;
165} 75}
166 76
167static int simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 77static void simple_parse_convert(struct device *dev,
168 struct snd_pcm_hw_params *params) 78 struct device_node *np,
79 struct asoc_simple_data *adata)
169{ 80{
170 struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); 81 struct device_node *top = dev->of_node;
171 struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); 82 struct device_node *node = of_get_parent(np);
172 83
173 asoc_simple_card_convert_fixup(&dai_props->adata, params); 84 asoc_simple_parse_convert(dev, top, PREFIX, adata);
85 asoc_simple_parse_convert(dev, node, PREFIX, adata);
86 asoc_simple_parse_convert(dev, node, NULL, adata);
87 asoc_simple_parse_convert(dev, np, NULL, adata);
174 88
175 return 0; 89 of_node_put(node);
176} 90}
177 91
178static void simple_get_conversion(struct device *dev, 92static void simple_parse_mclk_fs(struct device_node *top,
179 struct device_node *np, 93 struct device_node *cpu,
180 struct asoc_simple_card_data *adata) 94 struct device_node *codec,
95 struct simple_dai_props *props,
96 char *prefix)
181{ 97{
182 struct device_node *top = dev->of_node; 98 struct device_node *node = of_get_parent(cpu);
183 struct device_node *node = of_get_parent(np); 99 char prop[128];
184 100
185 asoc_simple_card_parse_convert(dev, top, PREFIX, adata); 101 snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX);
186 asoc_simple_card_parse_convert(dev, node, PREFIX, adata); 102 of_property_read_u32(top, prop, &props->mclk_fs);
187 asoc_simple_card_parse_convert(dev, node, NULL, adata); 103
188 asoc_simple_card_parse_convert(dev, np, NULL, adata); 104 snprintf(prop, sizeof(prop), "%smclk-fs", prefix);
105 of_property_read_u32(node, prop, &props->mclk_fs);
106 of_property_read_u32(cpu, prop, &props->mclk_fs);
107 of_property_read_u32(codec, prop, &props->mclk_fs);
189 108
190 of_node_put(node); 109 of_node_put(node);
191} 110}
192 111
193static int simple_dai_link_of_dpcm(struct simple_priv *priv, 112static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv,
194 struct device_node *np, 113 struct device_node *np,
195 struct device_node *codec, 114 struct device_node *codec,
196 struct link_info *li, 115 struct link_info *li,
@@ -203,7 +122,6 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv,
203 struct snd_soc_dai_link_component *codecs = dai_link->codecs; 122 struct snd_soc_dai_link_component *codecs = dai_link->codecs;
204 struct device_node *top = dev->of_node; 123 struct device_node *top = dev->of_node;
205 struct device_node *node = of_get_parent(np); 124 struct device_node *node = of_get_parent(np);
206 char prop[128];
207 char *prefix = ""; 125 char *prefix = "";
208 int ret; 126 int ret;
209 127
@@ -241,22 +159,21 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv,
241 dai = 159 dai =
242 dai_props->cpu_dai = &priv->dais[li->dais++]; 160 dai_props->cpu_dai = &priv->dais[li->dais++];
243 161
244 ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, 162 ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links);
245 &is_single_links);
246 if (ret) 163 if (ret)
247 return ret; 164 return ret;
248 165
249 ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); 166 ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai);
250 if (ret < 0) 167 if (ret < 0)
251 return ret; 168 return ret;
252 169
253 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 170 ret = asoc_simple_set_dailink_name(dev, dai_link,
254 "fe.%s", 171 "fe.%s",
255 dai_link->cpu_dai_name); 172 dai_link->cpu_dai_name);
256 if (ret < 0) 173 if (ret < 0)
257 return ret; 174 return ret;
258 175
259 asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); 176 asoc_simple_canonicalize_cpu(dai_link, is_single_links);
260 } else { 177 } else {
261 struct snd_soc_codec_conf *cconf; 178 struct snd_soc_codec_conf *cconf;
262 179
@@ -267,7 +184,7 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv,
267 184
268 /* BE settings */ 185 /* BE settings */
269 dai_link->no_pcm = 1; 186 dai_link->no_pcm = 1;
270 dai_link->be_hw_params_fixup = simple_be_hw_params_fixup; 187 dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup;
271 188
272 dai = 189 dai =
273 dai_props->codec_dai = &priv->dais[li->dais++]; 190 dai_props->codec_dai = &priv->dais[li->dais++];
@@ -275,17 +192,17 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv,
275 cconf = 192 cconf =
276 dai_props->codec_conf = &priv->codec_conf[li->conf++]; 193 dai_props->codec_conf = &priv->codec_conf[li->conf++];
277 194
278 ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); 195 ret = asoc_simple_parse_codec(np, dai_link);
279 if (ret < 0) 196 if (ret < 0)
280 return ret; 197 return ret;
281 198
282 ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); 199 ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai);
283 if (ret < 0) 200 if (ret < 0)
284 return ret; 201 return ret;
285 202
286 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 203 ret = asoc_simple_set_dailink_name(dev, dai_link,
287 "be.%s", 204 "be.%s",
288 codecs->dai_name); 205 codecs->dai_name);
289 if (ret < 0) 206 if (ret < 0)
290 return ret; 207 return ret;
291 208
@@ -298,33 +215,29 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv,
298 "prefix"); 215 "prefix");
299 } 216 }
300 217
301 simple_get_conversion(dev, np, &dai_props->adata); 218 simple_parse_convert(dev, np, &dai_props->adata);
219 simple_parse_mclk_fs(top, np, codec, dai_props, prefix);
302 220
303 asoc_simple_card_canonicalize_platform(dai_link); 221 asoc_simple_canonicalize_platform(dai_link);
304 222
305 ret = asoc_simple_card_of_parse_tdm(np, dai); 223 ret = asoc_simple_parse_tdm(np, dai);
306 if (ret) 224 if (ret)
307 return ret; 225 return ret;
308 226
309 snprintf(prop, sizeof(prop), "%smclk-fs", prefix); 227 ret = asoc_simple_parse_daifmt(dev, node, codec,
310 of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); 228 prefix, &dai_link->dai_fmt);
311 of_property_read_u32(node, prop, &dai_props->mclk_fs);
312 of_property_read_u32(np, prop, &dai_props->mclk_fs);
313
314 ret = asoc_simple_card_parse_daifmt(dev, node, codec,
315 prefix, &dai_link->dai_fmt);
316 if (ret < 0) 229 if (ret < 0)
317 return ret; 230 return ret;
318 231
319 dai_link->dpcm_playback = 1; 232 dai_link->dpcm_playback = 1;
320 dai_link->dpcm_capture = 1; 233 dai_link->dpcm_capture = 1;
321 dai_link->ops = &simple_ops; 234 dai_link->ops = &simple_ops;
322 dai_link->init = simple_dai_init; 235 dai_link->init = asoc_simple_dai_init;
323 236
324 return 0; 237 return 0;
325} 238}
326 239
327static int simple_dai_link_of(struct simple_priv *priv, 240static int simple_dai_link_of(struct asoc_simple_priv *priv,
328 struct device_node *np, 241 struct device_node *np,
329 struct device_node *codec, 242 struct device_node *codec,
330 struct link_info *li, 243 struct link_info *li,
@@ -370,58 +283,53 @@ static int simple_dai_link_of(struct simple_priv *priv,
370 codec_dai = 283 codec_dai =
371 dai_props->codec_dai = &priv->dais[li->dais++]; 284 dai_props->codec_dai = &priv->dais[li->dais++];
372 285
373 ret = asoc_simple_card_parse_daifmt(dev, node, codec, 286 ret = asoc_simple_parse_daifmt(dev, node, codec,
374 prefix, &dai_link->dai_fmt); 287 prefix, &dai_link->dai_fmt);
375 if (ret < 0) 288 if (ret < 0)
376 goto dai_link_of_err; 289 goto dai_link_of_err;
377 290
378 snprintf(prop, sizeof(prop), "%smclk-fs", prefix); 291 simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix);
379 of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs);
380 of_property_read_u32(node, prop, &dai_props->mclk_fs);
381 of_property_read_u32(cpu, prop, &dai_props->mclk_fs);
382 of_property_read_u32(codec, prop, &dai_props->mclk_fs);
383 292
384 ret = asoc_simple_card_parse_cpu(cpu, dai_link, 293 ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu);
385 DAI, CELL, &single_cpu);
386 if (ret < 0) 294 if (ret < 0)
387 goto dai_link_of_err; 295 goto dai_link_of_err;
388 296
389 ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL); 297 ret = asoc_simple_parse_codec(codec, dai_link);
390 if (ret < 0) 298 if (ret < 0)
391 goto dai_link_of_err; 299 goto dai_link_of_err;
392 300
393 ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL); 301 ret = asoc_simple_parse_platform(plat, dai_link);
394 if (ret < 0) 302 if (ret < 0)
395 goto dai_link_of_err; 303 goto dai_link_of_err;
396 304
397 ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai); 305 ret = asoc_simple_parse_tdm(cpu, cpu_dai);
398 if (ret < 0) 306 if (ret < 0)
399 goto dai_link_of_err; 307 goto dai_link_of_err;
400 308
401 ret = asoc_simple_card_of_parse_tdm(codec, codec_dai); 309 ret = asoc_simple_parse_tdm(codec, codec_dai);
402 if (ret < 0) 310 if (ret < 0)
403 goto dai_link_of_err; 311 goto dai_link_of_err;
404 312
405 ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); 313 ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
406 if (ret < 0) 314 if (ret < 0)
407 goto dai_link_of_err; 315 goto dai_link_of_err;
408 316
409 ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai); 317 ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
410 if (ret < 0) 318 if (ret < 0)
411 goto dai_link_of_err; 319 goto dai_link_of_err;
412 320
413 ret = asoc_simple_card_set_dailink_name(dev, dai_link, 321 ret = asoc_simple_set_dailink_name(dev, dai_link,
414 "%s-%s", 322 "%s-%s",
415 dai_link->cpu_dai_name, 323 dai_link->cpu_dai_name,
416 dai_link->codecs->dai_name); 324 dai_link->codecs->dai_name);
417 if (ret < 0) 325 if (ret < 0)
418 goto dai_link_of_err; 326 goto dai_link_of_err;
419 327
420 dai_link->ops = &simple_ops; 328 dai_link->ops = &simple_ops;
421 dai_link->init = simple_dai_init; 329 dai_link->init = asoc_simple_dai_init;
422 330
423 asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); 331 asoc_simple_canonicalize_cpu(dai_link, single_cpu);
424 asoc_simple_card_canonicalize_platform(dai_link); 332 asoc_simple_canonicalize_platform(dai_link);
425 333
426dai_link_of_err: 334dai_link_of_err:
427 of_node_put(plat); 335 of_node_put(plat);
@@ -430,13 +338,13 @@ dai_link_of_err:
430 return ret; 338 return ret;
431} 339}
432 340
433static int simple_for_each_link(struct simple_priv *priv, 341static int simple_for_each_link(struct asoc_simple_priv *priv,
434 struct link_info *li, 342 struct link_info *li,
435 int (*func_noml)(struct simple_priv *priv, 343 int (*func_noml)(struct asoc_simple_priv *priv,
436 struct device_node *np, 344 struct device_node *np,
437 struct device_node *codec, 345 struct device_node *codec,
438 struct link_info *li, bool is_top), 346 struct link_info *li, bool is_top),
439 int (*func_dpcm)(struct simple_priv *priv, 347 int (*func_dpcm)(struct asoc_simple_priv *priv,
440 struct device_node *np, 348 struct device_node *np,
441 struct device_node *codec, 349 struct device_node *codec,
442 struct link_info *li, bool is_top)) 350 struct link_info *li, bool is_top))
@@ -457,7 +365,7 @@ static int simple_for_each_link(struct simple_priv *priv,
457 365
458 /* loop for all dai-link */ 366 /* loop for all dai-link */
459 do { 367 do {
460 struct asoc_simple_card_data adata; 368 struct asoc_simple_data adata;
461 struct device_node *codec; 369 struct device_node *codec;
462 struct device_node *np; 370 struct device_node *np;
463 int num = of_get_child_count(node); 371 int num = of_get_child_count(node);
@@ -475,7 +383,7 @@ static int simple_for_each_link(struct simple_priv *priv,
475 /* get convert-xxx property */ 383 /* get convert-xxx property */
476 memset(&adata, 0, sizeof(adata)); 384 memset(&adata, 0, sizeof(adata));
477 for_each_child_of_node(node, np) 385 for_each_child_of_node(node, np)
478 simple_get_conversion(dev, np, &adata); 386 simple_parse_convert(dev, np, &adata);
479 387
480 /* loop for all CPU/Codec node */ 388 /* loop for all CPU/Codec node */
481 for_each_child_of_node(node, np) { 389 for_each_child_of_node(node, np) {
@@ -507,7 +415,7 @@ static int simple_for_each_link(struct simple_priv *priv,
507} 415}
508 416
509static int simple_parse_aux_devs(struct device_node *node, 417static int simple_parse_aux_devs(struct device_node *node,
510 struct simple_priv *priv) 418 struct asoc_simple_priv *priv)
511{ 419{
512 struct device *dev = simple_priv_to_dev(priv); 420 struct device *dev = simple_priv_to_dev(priv);
513 struct device_node *aux_node; 421 struct device_node *aux_node;
@@ -537,7 +445,7 @@ static int simple_parse_aux_devs(struct device_node *node,
537 return 0; 445 return 0;
538} 446}
539 447
540static int simple_parse_of(struct simple_priv *priv) 448static int simple_parse_of(struct asoc_simple_priv *priv)
541{ 449{
542 struct device *dev = simple_priv_to_dev(priv); 450 struct device *dev = simple_priv_to_dev(priv);
543 struct device_node *top = dev->of_node; 451 struct device_node *top = dev->of_node;
@@ -548,11 +456,15 @@ static int simple_parse_of(struct simple_priv *priv)
548 if (!top) 456 if (!top)
549 return -EINVAL; 457 return -EINVAL;
550 458
551 ret = asoc_simple_card_of_parse_widgets(card, PREFIX); 459 ret = asoc_simple_parse_widgets(card, PREFIX);
552 if (ret < 0) 460 if (ret < 0)
553 return ret; 461 return ret;
554 462
555 ret = asoc_simple_card_of_parse_routing(card, PREFIX); 463 ret = asoc_simple_parse_routing(card, PREFIX);
464 if (ret < 0)
465 return ret;
466
467 ret = asoc_simple_parse_pin_switches(card, PREFIX);
556 if (ret < 0) 468 if (ret < 0)
557 return ret; 469 return ret;
558 470
@@ -578,7 +490,7 @@ static int simple_parse_of(struct simple_priv *priv)
578 return ret; 490 return ret;
579 } 491 }
580 492
581 ret = asoc_simple_card_parse_card_name(card, PREFIX); 493 ret = asoc_simple_parse_card_name(card, PREFIX);
582 if (ret < 0) 494 if (ret < 0)
583 return ret; 495 return ret;
584 496
@@ -587,7 +499,7 @@ static int simple_parse_of(struct simple_priv *priv)
587 return ret; 499 return ret;
588} 500}
589 501
590static int simple_count_noml(struct simple_priv *priv, 502static int simple_count_noml(struct asoc_simple_priv *priv,
591 struct device_node *np, 503 struct device_node *np,
592 struct device_node *codec, 504 struct device_node *codec,
593 struct link_info *li, bool is_top) 505 struct link_info *li, bool is_top)
@@ -599,7 +511,7 @@ static int simple_count_noml(struct simple_priv *priv,
599 return 0; 511 return 0;
600} 512}
601 513
602static int simple_count_dpcm(struct simple_priv *priv, 514static int simple_count_dpcm(struct asoc_simple_priv *priv,
603 struct device_node *np, 515 struct device_node *np,
604 struct device_node *codec, 516 struct device_node *codec,
605 struct link_info *li, bool is_top) 517 struct link_info *li, bool is_top)
@@ -612,7 +524,7 @@ static int simple_count_dpcm(struct simple_priv *priv,
612 return 0; 524 return 0;
613} 525}
614 526
615static void simple_get_dais_count(struct simple_priv *priv, 527static void simple_get_dais_count(struct asoc_simple_priv *priv,
616 struct link_info *li) 528 struct link_info *li)
617{ 529{
618 struct device *dev = simple_priv_to_dev(priv); 530 struct device *dev = simple_priv_to_dev(priv);
@@ -681,14 +593,14 @@ static void simple_get_dais_count(struct simple_priv *priv,
681 593
682static int simple_soc_probe(struct snd_soc_card *card) 594static int simple_soc_probe(struct snd_soc_card *card)
683{ 595{
684 struct simple_priv *priv = snd_soc_card_get_drvdata(card); 596 struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
685 int ret; 597 int ret;
686 598
687 ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); 599 ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
688 if (ret < 0) 600 if (ret < 0)
689 return ret; 601 return ret;
690 602
691 ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX); 603 ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
692 if (ret < 0) 604 if (ret < 0)
693 return ret; 605 return ret;
694 606
@@ -697,16 +609,12 @@ static int simple_soc_probe(struct snd_soc_card *card)
697 609
698static int simple_probe(struct platform_device *pdev) 610static int simple_probe(struct platform_device *pdev)
699{ 611{
700 struct simple_priv *priv; 612 struct asoc_simple_priv *priv;
701 struct snd_soc_dai_link *dai_link;
702 struct simple_dai_props *dai_props;
703 struct asoc_simple_dai *dais;
704 struct device *dev = &pdev->dev; 613 struct device *dev = &pdev->dev;
705 struct device_node *np = dev->of_node; 614 struct device_node *np = dev->of_node;
706 struct snd_soc_card *card; 615 struct snd_soc_card *card;
707 struct snd_soc_codec_conf *cconf;
708 struct link_info li; 616 struct link_info li;
709 int ret, i; 617 int ret;
710 618
711 /* Allocate the private data and the DAI link array */ 619 /* Allocate the private data and the DAI link array */
712 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 620 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -723,35 +631,9 @@ static int simple_probe(struct platform_device *pdev)
723 if (!li.link || !li.dais) 631 if (!li.link || !li.dais)
724 return -EINVAL; 632 return -EINVAL;
725 633
726 dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); 634 ret = asoc_simple_init_priv(priv, &li);
727 dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); 635 if (ret < 0)
728 dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); 636 return ret;
729 cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL);
730 if (!dai_props || !dai_link || !dais)
731 return -ENOMEM;
732
733 /*
734 * Use snd_soc_dai_link_component instead of legacy style
735 * It is codec only. but cpu/platform will be supported in the future.
736 * see
737 * soc-core.c :: snd_soc_init_multicodec()
738 */
739 for (i = 0; i < li.link; i++) {
740 dai_link[i].codecs = &dai_props[i].codecs;
741 dai_link[i].num_codecs = 1;
742 dai_link[i].platforms = &dai_props[i].platforms;
743 dai_link[i].num_platforms = 1;
744 }
745
746 priv->dai_props = dai_props;
747 priv->dai_link = dai_link;
748 priv->dais = dais;
749 priv->codec_conf = cconf;
750
751 card->dai_link = priv->dai_link;
752 card->num_links = li.link;
753 card->codec_conf = cconf;
754 card->num_configs = li.conf;
755 637
756 if (np && of_device_is_available(np)) { 638 if (np && of_device_is_available(np)) {
757 639
@@ -766,6 +648,9 @@ static int simple_probe(struct platform_device *pdev)
766 struct asoc_simple_card_info *cinfo; 648 struct asoc_simple_card_info *cinfo;
767 struct snd_soc_dai_link_component *codecs; 649 struct snd_soc_dai_link_component *codecs;
768 struct snd_soc_dai_link_component *platform; 650 struct snd_soc_dai_link_component *platform;
651 struct snd_soc_dai_link *dai_link = priv->dai_link;
652 struct simple_dai_props *dai_props = priv->dai_props;
653
769 int dai_idx = 0; 654 int dai_idx = 0;
770 655
771 cinfo = dev->platform_data; 656 cinfo = dev->platform_data;
@@ -798,22 +683,24 @@ static int simple_probe(struct platform_device *pdev)
798 dai_link->stream_name = cinfo->name; 683 dai_link->stream_name = cinfo->name;
799 dai_link->cpu_dai_name = cinfo->cpu_dai.name; 684 dai_link->cpu_dai_name = cinfo->cpu_dai.name;
800 dai_link->dai_fmt = cinfo->daifmt; 685 dai_link->dai_fmt = cinfo->daifmt;
801 dai_link->init = simple_dai_init; 686 dai_link->init = asoc_simple_dai_init;
802 memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, 687 memcpy(dai_props->cpu_dai, &cinfo->cpu_dai,
803 sizeof(*priv->dai_props->cpu_dai)); 688 sizeof(*dai_props->cpu_dai));
804 memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, 689 memcpy(dai_props->codec_dai, &cinfo->codec_dai,
805 sizeof(*priv->dai_props->codec_dai)); 690 sizeof(*dai_props->codec_dai));
806 } 691 }
807 692
808 snd_soc_card_set_drvdata(card, priv); 693 snd_soc_card_set_drvdata(card, priv);
809 694
695 asoc_simple_debug_info(priv);
696
810 ret = devm_snd_soc_register_card(dev, card); 697 ret = devm_snd_soc_register_card(dev, card);
811 if (ret < 0) 698 if (ret < 0)
812 goto err; 699 goto err;
813 700
814 return 0; 701 return 0;
815err: 702err:
816 asoc_simple_card_clean_reference(card); 703 asoc_simple_clean_reference(card);
817 704
818 return ret; 705 return ret;
819} 706}
@@ -822,7 +709,7 @@ static int simple_remove(struct platform_device *pdev)
822{ 709{
823 struct snd_soc_card *card = platform_get_drvdata(pdev); 710 struct snd_soc_card *card = platform_get_drvdata(pdev);
824 711
825 return asoc_simple_card_clean_reference(card); 712 return asoc_simple_clean_reference(card);
826} 713}
827 714
828static const struct of_device_id simple_of_match[] = { 715static const struct of_device_id simple_of_match[] = {
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index bd9fd2035c55..fc1396adde71 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -196,13 +196,18 @@ config SND_SOC_INTEL_SKYLAKE_COMMON
196 196
197endif ## SND_SOC_INTEL_SKYLAKE_FAMILY 197endif ## SND_SOC_INTEL_SKYLAKE_FAMILY
198 198
199endif ## SND_SOC_INTEL_SST_TOPLEVEL
200
201if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
202
199config SND_SOC_ACPI_INTEL_MATCH 203config SND_SOC_ACPI_INTEL_MATCH
200 tristate 204 tristate
201 select SND_SOC_ACPI if ACPI 205 select SND_SOC_ACPI if ACPI
202 # this option controls the compilation of ACPI matching tables and 206 # this option controls the compilation of ACPI matching tables and
203 # helpers and is not meant to be selected by the user. 207 # helpers and is not meant to be selected by the user.
204 208
205endif ## SND_SOC_INTEL_SST_TOPLEVEL 209endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
210
206 211
207# ASoC codec drivers 212# ASoC codec drivers
208source "sound/soc/intel/boards/Kconfig" 213source "sound/soc/intel/boards/Kconfig"
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 12d6b73e9531..e39473a6a5d9 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -1,6 +1,6 @@
1menuconfig SND_SOC_INTEL_MACH 1menuconfig SND_SOC_INTEL_MACH
2 bool "Intel Machine drivers" 2 bool "Intel Machine drivers"
3 depends on SND_SOC_INTEL_SST_TOPLEVEL 3 depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL
4 help 4 help
5 Intel ASoC Machine Drivers. If you have a Intel machine that 5 Intel ASoC Machine Drivers. If you have a Intel machine that
6 has an audio controller with a DSP and I2S or DMIC port, then 6 has an audio controller with a DSP and I2S or DMIC port, then
@@ -16,7 +16,9 @@ if SND_SOC_INTEL_HASWELL
16 16
17config SND_SOC_INTEL_HASWELL_MACH 17config SND_SOC_INTEL_HASWELL_MACH
18 tristate "Haswell Lynxpoint" 18 tristate "Haswell Lynxpoint"
19 depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM 19 depends on I2C
20 depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
21 depends on X86_INTEL_LPSS || COMPILE_TEST
20 select SND_SOC_RT5640 22 select SND_SOC_RT5640
21 help 23 help
22 This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell 24 This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
@@ -24,9 +26,16 @@ config SND_SOC_INTEL_HASWELL_MACH
24 Say Y or m if you have such a device. 26 Say Y or m if you have such a device.
25 If unsure select "N". 27 If unsure select "N".
26 28
29endif ## SND_SOC_INTEL_HASWELL
30
31if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL
32
27config SND_SOC_INTEL_BDW_RT5677_MACH 33config SND_SOC_INTEL_BDW_RT5677_MACH
28 tristate "Broadwell with RT5677 codec" 34 tristate "Broadwell with RT5677 codec"
29 depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB 35 depends on I2C
36 depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
37 depends on GPIOLIB || COMPILE_TEST
38 depends on X86_INTEL_LPSS || COMPILE_TEST
30 select SND_SOC_RT5677 39 select SND_SOC_RT5677
31 help 40 help
32 This adds support for Intel Broadwell platform based boards with 41 This adds support for Intel Broadwell platform based boards with
@@ -36,20 +45,23 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
36 45
37config SND_SOC_INTEL_BROADWELL_MACH 46config SND_SOC_INTEL_BROADWELL_MACH
38 tristate "Broadwell Wildcatpoint" 47 tristate "Broadwell Wildcatpoint"
39 depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM 48 depends on I2C
49 depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
50 depends on X86_INTEL_LPSS || COMPILE_TEST
40 select SND_SOC_RT286 51 select SND_SOC_RT286
41 help 52 help
42 This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell 53 This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
43 Ultrabook platforms. 54 Ultrabook platforms.
44 Say Y or m if you have such a device. This is a recommended option. 55 Say Y or m if you have such a device. This is a recommended option.
45 If unsure select "N". 56 If unsure select "N".
46endif ## SND_SOC_INTEL_HASWELL 57endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL
47 58
48if SND_SOC_INTEL_BAYTRAIL 59if SND_SOC_INTEL_BAYTRAIL
49 60
50config SND_SOC_INTEL_BYT_MAX98090_MACH 61config SND_SOC_INTEL_BYT_MAX98090_MACH
51 tristate "Baytrail with MAX98090 codec" 62 tristate "Baytrail with MAX98090 codec"
52 depends on X86_INTEL_LPSS && I2C 63 depends on I2C
64 depends on X86_INTEL_LPSS || COMPILE_TEST
53 select SND_SOC_MAX98090 65 select SND_SOC_MAX98090
54 help 66 help
55 This adds audio driver for Intel Baytrail platform based boards 67 This adds audio driver for Intel Baytrail platform based boards
@@ -59,7 +71,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
59 71
60config SND_SOC_INTEL_BYT_RT5640_MACH 72config SND_SOC_INTEL_BYT_RT5640_MACH
61 tristate "Baytrail with RT5640 codec" 73 tristate "Baytrail with RT5640 codec"
62 depends on X86_INTEL_LPSS && I2C 74 depends on I2C
75 depends on X86_INTEL_LPSS || COMPILE_TEST
63 select SND_SOC_RT5640 76 select SND_SOC_RT5640
64 help 77 help
65 This adds audio driver for Intel Baytrail platform based boards 78 This adds audio driver for Intel Baytrail platform based boards
@@ -68,11 +81,12 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
68 81
69endif ## SND_SOC_INTEL_BAYTRAIL 82endif ## SND_SOC_INTEL_BAYTRAIL
70 83
71if SND_SST_ATOM_HIFI2_PLATFORM 84if SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL
72 85
73config SND_SOC_INTEL_BYTCR_RT5640_MACH 86config SND_SOC_INTEL_BYTCR_RT5640_MACH
74 tristate "Baytrail and Baytrail-CR with RT5640 codec" 87 tristate "Baytrail and Baytrail-CR with RT5640 codec"
75 depends on X86_INTEL_LPSS && I2C && ACPI 88 depends on I2C && ACPI
89 depends on X86_INTEL_LPSS || COMPILE_TEST
76 select SND_SOC_ACPI 90 select SND_SOC_ACPI
77 select SND_SOC_RT5640 91 select SND_SOC_RT5640
78 help 92 help
@@ -83,7 +97,8 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
83 97
84config SND_SOC_INTEL_BYTCR_RT5651_MACH 98config SND_SOC_INTEL_BYTCR_RT5651_MACH
85 tristate "Baytrail and Baytrail-CR with RT5651 codec" 99 tristate "Baytrail and Baytrail-CR with RT5651 codec"
86 depends on X86_INTEL_LPSS && I2C && ACPI 100 depends on I2C && ACPI
101 depends on X86_INTEL_LPSS || COMPILE_TEST
87 select SND_SOC_ACPI 102 select SND_SOC_ACPI
88 select SND_SOC_RT5651 103 select SND_SOC_RT5651
89 help 104 help
@@ -94,7 +109,8 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
94 109
95config SND_SOC_INTEL_CHT_BSW_RT5672_MACH 110config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
96 tristate "Cherrytrail & Braswell with RT5672 codec" 111 tristate "Cherrytrail & Braswell with RT5672 codec"
97 depends on X86_INTEL_LPSS && I2C && ACPI 112 depends on I2C && ACPI
113 depends on X86_INTEL_LPSS || COMPILE_TEST
98 select SND_SOC_ACPI 114 select SND_SOC_ACPI
99 select SND_SOC_RT5670 115 select SND_SOC_RT5670
100 help 116 help
@@ -105,7 +121,8 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
105 121
106config SND_SOC_INTEL_CHT_BSW_RT5645_MACH 122config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
107 tristate "Cherrytrail & Braswell with RT5645/5650 codec" 123 tristate "Cherrytrail & Braswell with RT5645/5650 codec"
108 depends on X86_INTEL_LPSS && I2C && ACPI 124 depends on I2C && ACPI
125 depends on X86_INTEL_LPSS || COMPILE_TEST
109 select SND_SOC_ACPI 126 select SND_SOC_ACPI
110 select SND_SOC_RT5645 127 select SND_SOC_RT5645
111 help 128 help
@@ -116,7 +133,8 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
116 133
117config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH 134config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
118 tristate "Cherrytrail & Braswell with MAX98090 & TI codec" 135 tristate "Cherrytrail & Braswell with MAX98090 & TI codec"
119 depends on X86_INTEL_LPSS && I2C && ACPI 136 depends on I2C && ACPI
137 depends on X86_INTEL_LPSS || COMPILE_TEST
120 select SND_SOC_MAX98090 138 select SND_SOC_MAX98090
121 select SND_SOC_TS3A227E 139 select SND_SOC_TS3A227E
122 help 140 help
@@ -127,7 +145,8 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
127 145
128config SND_SOC_INTEL_CHT_BSW_NAU8824_MACH 146config SND_SOC_INTEL_CHT_BSW_NAU8824_MACH
129 tristate "Cherrytrail & Braswell with NAU88L24 codec" 147 tristate "Cherrytrail & Braswell with NAU88L24 codec"
130 depends on X86_INTEL_LPSS && I2C && ACPI 148 depends on I2C && ACPI
149 depends on X86_INTEL_LPSS || COMPILE_TEST
131 select SND_SOC_ACPI 150 select SND_SOC_ACPI
132 select SND_SOC_NAU8824 151 select SND_SOC_NAU8824
133 help 152 help
@@ -138,7 +157,8 @@ config SND_SOC_INTEL_CHT_BSW_NAU8824_MACH
138 157
139config SND_SOC_INTEL_BYT_CHT_DA7213_MACH 158config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
140 tristate "Baytrail & Cherrytrail with DA7212/7213 codec" 159 tristate "Baytrail & Cherrytrail with DA7212/7213 codec"
141 depends on X86_INTEL_LPSS && I2C && ACPI 160 depends on I2C && ACPI
161 depends on X86_INTEL_LPSS || COMPILE_TEST
142 select SND_SOC_ACPI 162 select SND_SOC_ACPI
143 select SND_SOC_DA7213 163 select SND_SOC_DA7213
144 help 164 help
@@ -149,7 +169,8 @@ config SND_SOC_INTEL_BYT_CHT_DA7213_MACH
149 169
150config SND_SOC_INTEL_BYT_CHT_ES8316_MACH 170config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
151 tristate "Baytrail & Cherrytrail with ES8316 codec" 171 tristate "Baytrail & Cherrytrail with ES8316 codec"
152 depends on X86_INTEL_LPSS && I2C && ACPI 172 depends on I2C && ACPI
173 depends on X86_INTEL_LPSS || COMPILE_TEST
153 select SND_SOC_ACPI 174 select SND_SOC_ACPI
154 select SND_SOC_ES8316 175 select SND_SOC_ES8316
155 help 176 help
@@ -158,9 +179,14 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH
158 Say Y or m if you have such a device. This is a recommended option. 179 Say Y or m if you have such a device. This is a recommended option.
159 If unsure select "N". 180 If unsure select "N".
160 181
182endif ## SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL
183
184if SND_SST_ATOM_HIFI2_PLATFORM
185
161config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH 186config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH
162 tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" 187 tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)"
163 depends on X86_INTEL_LPSS && I2C && ACPI 188 depends on I2C && ACPI
189 depends on X86_INTEL_LPSS || COMPILE_TEST
164 help 190 help
165 This adds support for ASoC machine driver for the MinnowBoard Max or 191 This adds support for ASoC machine driver for the MinnowBoard Max or
166 Up boards and provides access to I2S signals on the Low-Speed 192 Up boards and provides access to I2S signals on the Low-Speed
@@ -176,7 +202,8 @@ if SND_SOC_INTEL_SKL
176 202
177config SND_SOC_INTEL_SKL_RT286_MACH 203config SND_SOC_INTEL_SKL_RT286_MACH
178 tristate "SKL with RT286 I2S mode" 204 tristate "SKL with RT286 I2S mode"
179 depends on MFD_INTEL_LPSS && I2C && ACPI 205 depends on I2C && ACPI
206 depends on MFD_INTEL_LPSS || COMPILE_TEST
180 select SND_SOC_RT286 207 select SND_SOC_RT286
181 select SND_SOC_DMIC 208 select SND_SOC_DMIC
182 select SND_SOC_HDAC_HDMI 209 select SND_SOC_HDAC_HDMI
@@ -188,7 +215,8 @@ config SND_SOC_INTEL_SKL_RT286_MACH
188 215
189config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH 216config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
190 tristate "SKL with NAU88L25 and SSM4567 in I2S Mode" 217 tristate "SKL with NAU88L25 and SSM4567 in I2S Mode"
191 depends on MFD_INTEL_LPSS && I2C && ACPI 218 depends on I2C && ACPI
219 depends on MFD_INTEL_LPSS || COMPILE_TEST
192 select SND_SOC_NAU8825 220 select SND_SOC_NAU8825
193 select SND_SOC_SSM4567 221 select SND_SOC_SSM4567
194 select SND_SOC_DMIC 222 select SND_SOC_DMIC
@@ -201,7 +229,8 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
201 229
202config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH 230config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
203 tristate "SKL with NAU88L25 and MAX98357A in I2S Mode" 231 tristate "SKL with NAU88L25 and MAX98357A in I2S Mode"
204 depends on MFD_INTEL_LPSS && I2C && ACPI 232 depends on I2C && ACPI
233 depends on MFD_INTEL_LPSS || COMPILE_TEST
205 select SND_SOC_NAU8825 234 select SND_SOC_NAU8825
206 select SND_SOC_MAX98357A 235 select SND_SOC_MAX98357A
207 select SND_SOC_DMIC 236 select SND_SOC_DMIC
@@ -218,7 +247,8 @@ if SND_SOC_INTEL_APL
218 247
219config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH 248config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
220 tristate "Broxton with DA7219 and MAX98357A in I2S Mode" 249 tristate "Broxton with DA7219 and MAX98357A in I2S Mode"
221 depends on MFD_INTEL_LPSS && I2C && ACPI 250 depends on I2C && ACPI
251 depends on MFD_INTEL_LPSS || COMPILE_TEST
222 select SND_SOC_DA7219 252 select SND_SOC_DA7219
223 select SND_SOC_MAX98357A 253 select SND_SOC_MAX98357A
224 select SND_SOC_DMIC 254 select SND_SOC_DMIC
@@ -232,7 +262,8 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH
232 262
233config SND_SOC_INTEL_BXT_RT298_MACH 263config SND_SOC_INTEL_BXT_RT298_MACH
234 tristate "Broxton with RT298 I2S mode" 264 tristate "Broxton with RT298 I2S mode"
235 depends on MFD_INTEL_LPSS && I2C && ACPI 265 depends on I2C && ACPI
266 depends on MFD_INTEL_LPSS || COMPILE_TEST
236 select SND_SOC_RT298 267 select SND_SOC_RT298
237 select SND_SOC_DMIC 268 select SND_SOC_DMIC
238 select SND_SOC_HDAC_HDMI 269 select SND_SOC_HDAC_HDMI
@@ -249,7 +280,8 @@ if SND_SOC_INTEL_KBL
249 280
250config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH 281config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
251 tristate "KBL with RT5663 and MAX98927 in I2S Mode" 282 tristate "KBL with RT5663 and MAX98927 in I2S Mode"
252 depends on MFD_INTEL_LPSS && I2C && ACPI 283 depends on I2C && ACPI
284 depends on MFD_INTEL_LPSS || COMPILE_TEST
253 select SND_SOC_RT5663 285 select SND_SOC_RT5663
254 select SND_SOC_MAX98927 286 select SND_SOC_MAX98927
255 select SND_SOC_DMIC 287 select SND_SOC_DMIC
@@ -263,7 +295,8 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
263 295
264config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH 296config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
265 tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" 297 tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
266 depends on MFD_INTEL_LPSS && I2C && ACPI 298 depends on I2C && ACPI
299 depends on MFD_INTEL_LPSS || COMPILE_TEST
267 depends on SPI 300 depends on SPI
268 select SND_SOC_RT5663 301 select SND_SOC_RT5663
269 select SND_SOC_RT5514 302 select SND_SOC_RT5514
@@ -278,7 +311,8 @@ config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
278 311
279config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH 312config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
280 tristate "KBL with DA7219 and MAX98357A in I2S Mode" 313 tristate "KBL with DA7219 and MAX98357A in I2S Mode"
281 depends on MFD_INTEL_LPSS && I2C && ACPI 314 depends on I2C && ACPI
315 depends on MFD_INTEL_LPSS || COMPILE_TEST
282 select SND_SOC_DA7219 316 select SND_SOC_DA7219
283 select SND_SOC_MAX98357A 317 select SND_SOC_MAX98357A
284 select SND_SOC_DMIC 318 select SND_SOC_DMIC
@@ -290,7 +324,8 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
290 324
291config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH 325config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
292 tristate "KBL with DA7219 and MAX98927 in I2S Mode" 326 tristate "KBL with DA7219 and MAX98927 in I2S Mode"
293 depends on MFD_INTEL_LPSS && I2C && ACPI 327 depends on I2C && ACPI
328 depends on MFD_INTEL_LPSS || COMPILE_TEST
294 select SND_SOC_DA7219 329 select SND_SOC_DA7219
295 select SND_SOC_MAX98927 330 select SND_SOC_MAX98927
296 select SND_SOC_MAX98373 331 select SND_SOC_MAX98373
@@ -304,7 +339,8 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH
304 339
305config SND_SOC_INTEL_KBL_RT5660_MACH 340config SND_SOC_INTEL_KBL_RT5660_MACH
306 tristate "KBL with RT5660 in I2S Mode" 341 tristate "KBL with RT5660 in I2S Mode"
307 depends on MFD_INTEL_LPSS && I2C && ACPI 342 depends on I2C && ACPI
343 depends on MFD_INTEL_LPSS || COMPILE_TEST
308 select SND_SOC_RT5660 344 select SND_SOC_RT5660
309 select SND_SOC_HDAC_HDMI 345 select SND_SOC_HDAC_HDMI
310 help 346 help
@@ -314,11 +350,12 @@ config SND_SOC_INTEL_KBL_RT5660_MACH
314 350
315endif ## SND_SOC_INTEL_KBL 351endif ## SND_SOC_INTEL_KBL
316 352
317if SND_SOC_INTEL_GLK 353if SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK)
318 354
319config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH 355config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
320 tristate "GLK with RT5682 and MAX98357A in I2S Mode" 356 tristate "GLK with RT5682 and MAX98357A in I2S Mode"
321 depends on MFD_INTEL_LPSS && I2C && ACPI 357 depends on I2C && ACPI
358 depends on MFD_INTEL_LPSS || COMPILE_TEST
322 select SND_SOC_RT5682 359 select SND_SOC_RT5682
323 select SND_SOC_MAX98357A 360 select SND_SOC_MAX98357A
324 select SND_SOC_DMIC 361 select SND_SOC_DMIC
@@ -330,9 +367,9 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
330 Say Y if you have such a device. 367 Say Y if you have such a device.
331 If unsure select "N". 368 If unsure select "N".
332 369
333endif ## SND_SOC_INTEL_GLK 370endif ## SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK)
334 371
335if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC 372if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
336 373
337config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH 374config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
338 tristate "SKL/KBL/BXT/APL with HDA Codecs" 375 tristate "SKL/KBL/BXT/APL with HDA Codecs"
@@ -344,6 +381,22 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
344 Say Y or m if you have such a device. This is a recommended option. 381 Say Y or m if you have such a device. This is a recommended option.
345 If unsure select "N". 382 If unsure select "N".
346 383
347endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC 384endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
385
386if SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL
387config SND_SOC_INTEL_SOF_RT5682_MACH
388 tristate "SOF with rt5682 codec in I2S Mode"
389 depends on I2C && ACPI
390 depends on (SND_SOC_SOF_HDA_COMMON && MFD_INTEL_LPSS) ||\
391 (SND_SOC_SOF_BAYTRAIL && X86_INTEL_LPSS)
392 select SND_SOC_RT5682
393 select SND_SOC_DMIC
394 select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_COMMON
395 help
396 This adds support for ASoC machine driver for SOF platforms
397 with rt5682 codec.
398 Say Y if you have such a device.
399 If unsure select "N".
400endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL
348 401
349endif ## SND_SOC_INTEL_MACH 402endif ## SND_SOC_INTEL_MACH
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index bf072ea299b7..451b3bd7d9c5 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -16,6 +16,7 @@ snd-soc-sst-cht-bsw-nau8824-objs := cht_bsw_nau8824.o
16snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o 16snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o
17snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o 17snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o
18snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o 18snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o
19snd-soc-sof_rt5682-objs := sof_rt5682.o
19snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o 20snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
20snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o 21snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o
21snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o 22snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
@@ -26,6 +27,7 @@ snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
26snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o 27snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
27snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o 28snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
28 29
30obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o
29obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o 31obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
30obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o 32obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
31obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o 33obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 1844c88ea4e2..6520a8ea5537 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -180,6 +180,7 @@ static const struct snd_soc_ops bdw_rt5677_ops = {
180 .hw_params = bdw_rt5677_hw_params, 180 .hw_params = bdw_rt5677_hw_params,
181}; 181};
182 182
183#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
183static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) 184static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
184{ 185{
185 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); 186 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
@@ -198,6 +199,7 @@ static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd)
198 199
199 return 0; 200 return 0;
200} 201}
202#endif
201 203
202static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) 204static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd)
203{ 205{
@@ -265,7 +267,9 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
265 .dynamic = 1, 267 .dynamic = 1,
266 .codec_name = "snd-soc-dummy", 268 .codec_name = "snd-soc-dummy",
267 .codec_dai_name = "snd-soc-dummy-dai", 269 .codec_dai_name = "snd-soc-dummy-dai",
270#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
268 .init = bdw_rt5677_rtd_init, 271 .init = bdw_rt5677_rtd_init,
272#endif
269 .trigger = { 273 .trigger = {
270 SND_SOC_DPCM_TRIGGER_POST, 274 SND_SOC_DPCM_TRIGGER_POST,
271 SND_SOC_DPCM_TRIGGER_POST 275 SND_SOC_DPCM_TRIGGER_POST
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
index b86c746d9b7a..0f18f8964f51 100644
--- a/sound/soc/intel/boards/broadwell.c
+++ b/sound/soc/intel/boards/broadwell.c
@@ -131,6 +131,7 @@ static const struct snd_soc_ops broadwell_rt286_ops = {
131 .hw_params = broadwell_rt286_hw_params, 131 .hw_params = broadwell_rt286_hw_params,
132}; 132};
133 133
134#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
134static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) 135static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
135{ 136{
136 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); 137 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
@@ -149,6 +150,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
149 150
150 return 0; 151 return 0;
151} 152}
153#endif
152 154
153/* broadwell digital audio interface glue - connects codec <--> CPU */ 155/* broadwell digital audio interface glue - connects codec <--> CPU */
154static struct snd_soc_dai_link broadwell_rt286_dais[] = { 156static struct snd_soc_dai_link broadwell_rt286_dais[] = {
@@ -161,7 +163,9 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
161 .dynamic = 1, 163 .dynamic = 1,
162 .codec_name = "snd-soc-dummy", 164 .codec_name = "snd-soc-dummy",
163 .codec_dai_name = "snd-soc-dummy-dai", 165 .codec_dai_name = "snd-soc-dummy-dai",
166#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
164 .init = broadwell_rtd_init, 167 .init = broadwell_rtd_init,
168#endif
165 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 169 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
166 .dpcm_playback = 1, 170 .dpcm_playback = 1,
167 .dpcm_capture = 1, 171 .dpcm_capture = 1,
diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c
index 6937c00cf63d..e8c585ffd04d 100644
--- a/sound/soc/intel/boards/bytcht_es8316.c
+++ b/sound/soc/intel/boards/bytcht_es8316.c
@@ -22,6 +22,7 @@
22#include <linux/acpi.h> 22#include <linux/acpi.h>
23#include <linux/clk.h> 23#include <linux/clk.h>
24#include <linux/device.h> 24#include <linux/device.h>
25#include <linux/dmi.h>
25#include <linux/gpio/consumer.h> 26#include <linux/gpio/consumer.h>
26#include <linux/i2c.h> 27#include <linux/i2c.h>
27#include <linux/init.h> 28#include <linux/init.h>
@@ -40,6 +41,9 @@
40#include "../atom/sst-atom-controls.h" 41#include "../atom/sst-atom-controls.h"
41#include "../common/sst-dsp.h" 42#include "../common/sst-dsp.h"
42 43
44/* jd-inv + terminating entry */
45#define MAX_NO_PROPS 2
46
43struct byt_cht_es8316_private { 47struct byt_cht_es8316_private {
44 struct clk *mclk; 48 struct clk *mclk;
45 struct snd_soc_jack jack; 49 struct snd_soc_jack jack;
@@ -55,8 +59,9 @@ enum {
55#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) 59#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0))
56#define BYT_CHT_ES8316_SSP0 BIT(16) 60#define BYT_CHT_ES8316_SSP0 BIT(16)
57#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) 61#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17)
62#define BYT_CHT_ES8316_JD_INVERTED BIT(18)
58 63
59static int quirk; 64static unsigned long quirk;
60 65
61static int quirk_override = -1; 66static int quirk_override = -1;
62module_param_named(quirk, quirk_override, int, 0444); 67module_param_named(quirk, quirk_override, int, 0444);
@@ -72,6 +77,8 @@ static void log_quirks(struct device *dev)
72 dev_info(dev, "quirk SSP0 enabled"); 77 dev_info(dev, "quirk SSP0 enabled");
73 if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) 78 if (quirk & BYT_CHT_ES8316_MONO_SPEAKER)
74 dev_info(dev, "quirk MONO_SPEAKER enabled\n"); 79 dev_info(dev, "quirk MONO_SPEAKER enabled\n");
80 if (quirk & BYT_CHT_ES8316_JD_INVERTED)
81 dev_info(dev, "quirk JD_INVERTED enabled\n");
75} 82}
76 83
77static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, 84static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
@@ -435,15 +442,31 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = {
435 { }, 442 { },
436}; 443};
437 444
445/* Please keep this list alphabetically sorted */
446static const struct dmi_system_id byt_cht_es8316_quirk_table[] = {
447 { /* Teclast X98 Plus II */
448 .matches = {
449 DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"),
450 DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"),
451 },
452 .driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN1_MAP
453 | BYT_CHT_ES8316_JD_INVERTED),
454 },
455 {}
456};
457
438static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) 458static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
439{ 459{
440 static const char * const mic_name[] = { "in1", "in2" }; 460 static const char * const mic_name[] = { "in1", "in2" };
461 struct property_entry props[MAX_NO_PROPS] = {};
441 struct byt_cht_es8316_private *priv; 462 struct byt_cht_es8316_private *priv;
463 const struct dmi_system_id *dmi_id;
442 struct device *dev = &pdev->dev; 464 struct device *dev = &pdev->dev;
443 struct snd_soc_acpi_mach *mach; 465 struct snd_soc_acpi_mach *mach;
444 const char *platform_name; 466 const char *platform_name;
445 struct acpi_device *adev; 467 struct acpi_device *adev;
446 struct device *codec_dev; 468 struct device *codec_dev;
469 unsigned int cnt = 0;
447 int dai_index = 0; 470 int dai_index = 0;
448 int i; 471 int i;
449 int ret = 0; 472 int ret = 0;
@@ -480,7 +503,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
480 return ret; 503 return ret;
481 504
482 /* Check for BYTCR or other platform and setup quirks */ 505 /* Check for BYTCR or other platform and setup quirks */
483 if (x86_match_cpu(baytrail_cpu_ids) && 506 dmi_id = dmi_first_match(byt_cht_es8316_quirk_table);
507 if (dmi_id) {
508 quirk = (unsigned long)dmi_id->driver_data;
509 } else if (x86_match_cpu(baytrail_cpu_ids) &&
484 mach->mach_params.acpi_ipc_irq_index == 0) { 510 mach->mach_params.acpi_ipc_irq_index == 0) {
485 /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ 511 /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */
486 quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | 512 quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP |
@@ -491,7 +517,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
491 BYT_CHT_ES8316_MONO_SPEAKER; 517 BYT_CHT_ES8316_MONO_SPEAKER;
492 } 518 }
493 if (quirk_override != -1) { 519 if (quirk_override != -1) {
494 dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, 520 dev_info(dev, "Overriding quirk 0x%x => 0x%x\n",
521 (unsigned int)quirk,
495 quirk_override); 522 quirk_override);
496 quirk = quirk_override; 523 quirk = quirk_override;
497 } 524 }
@@ -513,6 +540,15 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
513 if (!codec_dev) 540 if (!codec_dev)
514 return -EPROBE_DEFER; 541 return -EPROBE_DEFER;
515 542
543 if (quirk & BYT_CHT_ES8316_JD_INVERTED)
544 props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted");
545
546 if (cnt) {
547 ret = device_add_properties(codec_dev, props);
548 if (ret)
549 return ret;
550 }
551
516 devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); 552 devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios);
517 priv->speaker_en_gpio = 553 priv->speaker_en_gpio =
518 gpiod_get_index(codec_dev, "speaker-enable", 0, 554 gpiod_get_index(codec_dev, "speaker-enable", 0,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index f9175cf6747e..dc22df9a99fb 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -98,8 +98,8 @@ struct byt_rt5640_private {
98static bool is_bytcr; 98static bool is_bytcr;
99 99
100static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; 100static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN;
101static unsigned int quirk_override; 101static int quirk_override = -1;
102module_param_named(quirk, quirk_override, uint, 0444); 102module_param_named(quirk, quirk_override, int, 0444);
103MODULE_PARM_DESC(quirk, "Board-specific quirk override"); 103MODULE_PARM_DESC(quirk, "Board-specific quirk override");
104 104
105static void log_quirks(struct device *dev) 105static void log_quirks(struct device *dev)
@@ -1254,7 +1254,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
1254 dmi_id = dmi_first_match(byt_rt5640_quirk_table); 1254 dmi_id = dmi_first_match(byt_rt5640_quirk_table);
1255 if (dmi_id) 1255 if (dmi_id)
1256 byt_rt5640_quirk = (unsigned long)dmi_id->driver_data; 1256 byt_rt5640_quirk = (unsigned long)dmi_id->driver_data;
1257 if (quirk_override) { 1257 if (quirk_override != -1) {
1258 dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", 1258 dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n",
1259 (unsigned int)byt_rt5640_quirk, quirk_override); 1259 (unsigned int)byt_rt5640_quirk, quirk_override);
1260 byt_rt5640_quirk = quirk_override; 1260 byt_rt5640_quirk = quirk_override;
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index b744add01d12..ca657c3e5726 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -79,14 +79,15 @@ enum {
79#define BYT_RT5651_SSP0_AIF2 BIT(21) 79#define BYT_RT5651_SSP0_AIF2 BIT(21)
80#define BYT_RT5651_HP_LR_SWAPPED BIT(22) 80#define BYT_RT5651_HP_LR_SWAPPED BIT(22)
81#define BYT_RT5651_MONO_SPEAKER BIT(23) 81#define BYT_RT5651_MONO_SPEAKER BIT(23)
82#define BYT_RT5651_JD_NOT_INV BIT(24)
82 83
83#define BYT_RT5651_DEFAULT_QUIRKS (BYT_RT5651_MCLK_EN | \ 84#define BYT_RT5651_DEFAULT_QUIRKS (BYT_RT5651_MCLK_EN | \
84 BYT_RT5651_JD1_1 | \ 85 BYT_RT5651_JD1_1 | \
85 BYT_RT5651_OVCD_TH_2000UA | \ 86 BYT_RT5651_OVCD_TH_2000UA | \
86 BYT_RT5651_OVCD_SF_0P75) 87 BYT_RT5651_OVCD_SF_0P75)
87 88
88/* jack-detect-source + dmic-en + ovcd-th + -sf + terminating empty entry */ 89/* jack-detect-source + inv + dmic-en + ovcd-th + -sf + terminating entry */
89#define MAX_NO_PROPS 5 90#define MAX_NO_PROPS 6
90 91
91struct byt_rt5651_private { 92struct byt_rt5651_private {
92 struct clk *mclk; 93 struct clk *mclk;
@@ -101,8 +102,8 @@ static const struct acpi_gpio_mapping *byt_rt5651_gpios;
101static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | 102static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS |
102 BYT_RT5651_IN2_MAP; 103 BYT_RT5651_IN2_MAP;
103 104
104static unsigned int quirk_override; 105static int quirk_override = -1;
105module_param_named(quirk, quirk_override, uint, 0444); 106module_param_named(quirk, quirk_override, int, 0444);
106MODULE_PARM_DESC(quirk, "Board-specific quirk override"); 107MODULE_PARM_DESC(quirk, "Board-specific quirk override");
107 108
108static void log_quirks(struct device *dev) 109static void log_quirks(struct device *dev)
@@ -137,6 +138,8 @@ static void log_quirks(struct device *dev)
137 dev_info(dev, "quirk SSP0_AIF2 enabled\n"); 138 dev_info(dev, "quirk SSP0_AIF2 enabled\n");
138 if (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) 139 if (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER)
139 dev_info(dev, "quirk MONO_SPEAKER enabled\n"); 140 dev_info(dev, "quirk MONO_SPEAKER enabled\n");
141 if (byt_rt5651_quirk & BYT_RT5651_JD_NOT_INV)
142 dev_info(dev, "quirk JD_NOT_INV enabled\n");
140} 143}
141 144
142#define BYT_CODEC_DAI1 "rt5651-aif1" 145#define BYT_CODEC_DAI1 "rt5651-aif1"
@@ -415,6 +418,18 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
415 BYT_RT5651_MONO_SPEAKER), 418 BYT_RT5651_MONO_SPEAKER),
416 }, 419 },
417 { 420 {
421 /* Complet Electro Serv MY8307 */
422 .callback = byt_rt5651_quirk_cb,
423 .matches = {
424 DMI_MATCH(DMI_SYS_VENDOR, "Complet Electro Serv"),
425 DMI_MATCH(DMI_PRODUCT_NAME, "MY8307"),
426 },
427 .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
428 BYT_RT5651_IN2_MAP |
429 BYT_RT5651_MONO_SPEAKER |
430 BYT_RT5651_JD_NOT_INV),
431 },
432 {
418 /* I.T.Works TW701, Ployer Momo7w and Trekstor ST70416-6 433 /* I.T.Works TW701, Ployer Momo7w and Trekstor ST70416-6
419 * (these all use the same mainboard) */ 434 * (these all use the same mainboard) */
420 .callback = byt_rt5651_quirk_cb, 435 .callback = byt_rt5651_quirk_cb,
@@ -525,6 +540,9 @@ static int byt_rt5651_add_codec_device_props(struct device *i2c_dev)
525 if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN) 540 if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN)
526 props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,dmic-en"); 541 props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,dmic-en");
527 542
543 if (byt_rt5651_quirk & BYT_RT5651_JD_NOT_INV)
544 props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted");
545
528 return device_add_properties(i2c_dev, props); 546 return device_add_properties(i2c_dev, props);
529} 547}
530 548
@@ -969,7 +987,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
969 /* check quirks before creating card */ 987 /* check quirks before creating card */
970 dmi_check_system(byt_rt5651_quirk_table); 988 dmi_check_system(byt_rt5651_quirk_table);
971 989
972 if (quirk_override) { 990 if (quirk_override != -1) {
973 dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", 991 dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n",
974 (unsigned int)byt_rt5651_quirk, quirk_override); 992 (unsigned int)byt_rt5651_quirk, quirk_override);
975 byt_rt5651_quirk = quirk_override; 993 byt_rt5651_quirk = quirk_override;
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 38f6ab74709d..07491a0f8fb8 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -188,7 +188,7 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
188 188
189 jack = &ctx->kabylake_headset; 189 jack = &ctx->kabylake_headset;
190 190
191 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); 191 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
192 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 192 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
193 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 193 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
194 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 194 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c
index 2768a572d065..f72a7bf028d7 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98927.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98927.c
@@ -52,7 +52,6 @@ struct kbl_codec_private {
52 52
53enum { 53enum {
54 KBL_DPCM_AUDIO_PB = 0, 54 KBL_DPCM_AUDIO_PB = 0,
55 KBL_DPCM_AUDIO_CP,
56 KBL_DPCM_AUDIO_ECHO_REF_CP, 55 KBL_DPCM_AUDIO_ECHO_REF_CP,
57 KBL_DPCM_AUDIO_REF_CP, 56 KBL_DPCM_AUDIO_REF_CP,
58 KBL_DPCM_AUDIO_DMIC_CP, 57 KBL_DPCM_AUDIO_DMIC_CP,
@@ -60,6 +59,7 @@ enum {
60 KBL_DPCM_AUDIO_HDMI2_PB, 59 KBL_DPCM_AUDIO_HDMI2_PB,
61 KBL_DPCM_AUDIO_HDMI3_PB, 60 KBL_DPCM_AUDIO_HDMI3_PB,
62 KBL_DPCM_AUDIO_HS_PB, 61 KBL_DPCM_AUDIO_HS_PB,
62 KBL_DPCM_AUDIO_CP,
63}; 63};
64 64
65static int platform_clock_control(struct snd_soc_dapm_widget *w, 65static int platform_clock_control(struct snd_soc_dapm_widget *w,
@@ -311,6 +311,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
311 311
312 da7219_aad_jack_det(component, &ctx->kabylake_headset); 312 da7219_aad_jack_det(component, &ctx->kabylake_headset);
313 313
314 return 0;
315}
316
317static int kabylake_dmic_init(struct snd_soc_pcm_runtime *rtd)
318{
319 int ret;
314 ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); 320 ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
315 if (ret) 321 if (ret)
316 dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); 322 dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret);
@@ -581,20 +587,6 @@ static struct snd_soc_dai_link kabylake_dais[] = {
581 .dpcm_playback = 1, 587 .dpcm_playback = 1,
582 .ops = &kabylake_da7219_fe_ops, 588 .ops = &kabylake_da7219_fe_ops,
583 }, 589 },
584 [KBL_DPCM_AUDIO_CP] = {
585 .name = "Kbl Audio Capture Port",
586 .stream_name = "Audio Record",
587 .cpu_dai_name = "System Pin",
588 .platform_name = "0000:00:1f.3",
589 .dynamic = 1,
590 .codec_name = "snd-soc-dummy",
591 .codec_dai_name = "snd-soc-dummy-dai",
592 .nonatomic = 1,
593 .trigger = {
594 SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
595 .dpcm_capture = 1,
596 .ops = &kabylake_da7219_fe_ops,
597 },
598 [KBL_DPCM_AUDIO_ECHO_REF_CP] = { 590 [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
599 .name = "Kbl Audio Echo Reference cap", 591 .name = "Kbl Audio Echo Reference cap",
600 .stream_name = "Echoreference Capture", 592 .stream_name = "Echoreference Capture",
@@ -690,6 +682,20 @@ static struct snd_soc_dai_link kabylake_dais[] = {
690 .ops = &kabylake_da7219_fe_ops, 682 .ops = &kabylake_da7219_fe_ops,
691 683
692 }, 684 },
685 [KBL_DPCM_AUDIO_CP] = {
686 .name = "Kbl Audio Capture Port",
687 .stream_name = "Audio Record",
688 .cpu_dai_name = "System Pin",
689 .platform_name = "0000:00:1f.3",
690 .dynamic = 1,
691 .codec_name = "snd-soc-dummy",
692 .codec_dai_name = "snd-soc-dummy-dai",
693 .nonatomic = 1,
694 .trigger = {
695 SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
696 .dpcm_capture = 1,
697 .ops = &kabylake_da7219_fe_ops,
698 },
693 699
694 /* Back End DAI links */ 700 /* Back End DAI links */
695 { 701 {
@@ -733,6 +739,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
733 .cpu_dai_name = "DMIC01 Pin", 739 .cpu_dai_name = "DMIC01 Pin",
734 .codec_name = "dmic-codec", 740 .codec_name = "dmic-codec",
735 .codec_dai_name = "dmic-hifi", 741 .codec_dai_name = "dmic-hifi",
742 .init = kabylake_dmic_init,
736 .platform_name = "0000:00:1f.3", 743 .platform_name = "0000:00:1f.3",
737 .be_hw_params_fixup = kabylake_dmic_fixup, 744 .be_hw_params_fixup = kabylake_dmic_fixup,
738 .ignore_suspend = 1, 745 .ignore_suspend = 1,
@@ -792,20 +799,6 @@ static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = {
792 .dpcm_playback = 1, 799 .dpcm_playback = 1,
793 .ops = &kabylake_da7219_fe_ops, 800 .ops = &kabylake_da7219_fe_ops,
794 }, 801 },
795 [KBL_DPCM_AUDIO_CP] = {
796 .name = "Kbl Audio Capture Port",
797 .stream_name = "Audio Record",
798 .cpu_dai_name = "System Pin",
799 .platform_name = "0000:00:1f.3",
800 .dynamic = 1,
801 .codec_name = "snd-soc-dummy",
802 .codec_dai_name = "snd-soc-dummy-dai",
803 .nonatomic = 1,
804 .trigger = {
805 SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
806 .dpcm_capture = 1,
807 .ops = &kabylake_da7219_fe_ops,
808 },
809 [KBL_DPCM_AUDIO_ECHO_REF_CP] = { 802 [KBL_DPCM_AUDIO_ECHO_REF_CP] = {
810 .name = "Kbl Audio Echo Reference cap", 803 .name = "Kbl Audio Echo Reference cap",
811 .stream_name = "Echoreference Capture", 804 .stream_name = "Echoreference Capture",
@@ -911,6 +904,7 @@ static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = {
911 .cpu_dai_name = "DMIC01 Pin", 904 .cpu_dai_name = "DMIC01 Pin",
912 .codec_name = "dmic-codec", 905 .codec_name = "dmic-codec",
913 .codec_dai_name = "dmic-hifi", 906 .codec_dai_name = "dmic-hifi",
907 .init = kabylake_dmic_init,
914 .platform_name = "0000:00:1f.3", 908 .platform_name = "0000:00:1f.3",
915 .be_hw_params_fixup = kabylake_dmic_fixup, 909 .be_hw_params_fixup = kabylake_dmic_fixup,
916 .ignore_suspend = 1, 910 .ignore_suspend = 1,
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c
index 3fdbf239da74..8b68f41a5b88 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_common.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.c
@@ -78,7 +78,6 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = {
78 .platform_name = "0000:00:1f.3", 78 .platform_name = "0000:00:1f.3",
79 .dpcm_playback = 1, 79 .dpcm_playback = 1,
80 .dpcm_capture = 1, 80 .dpcm_capture = 1,
81 .init = NULL,
82 .no_pcm = 1, 81 .no_pcm = 1,
83 }, 82 },
84 { 83 {
@@ -90,7 +89,26 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = {
90 .platform_name = "0000:00:1f.3", 89 .platform_name = "0000:00:1f.3",
91 .dpcm_playback = 1, 90 .dpcm_playback = 1,
92 .dpcm_capture = 1, 91 .dpcm_capture = 1,
93 .init = NULL, 92 .no_pcm = 1,
93 },
94 {
95 .name = "dmic01",
96 .id = 6,
97 .cpu_dai_name = "DMIC01 Pin",
98 .codec_name = "dmic-codec",
99 .codec_dai_name = "dmic-hifi",
100 .platform_name = "0000:00:1f.3",
101 .dpcm_capture = 1,
102 .no_pcm = 1,
103 },
104 {
105 .name = "dmic16k",
106 .id = 7,
107 .cpu_dai_name = "DMIC16k Pin",
108 .codec_name = "dmic-codec",
109 .codec_dai_name = "dmic-hifi",
110 .platform_name = "0000:00:1f.3",
111 .dpcm_capture = 1,
94 .no_pcm = 1, 112 .no_pcm = 1,
95 }, 113 },
96}; 114};
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h
index 87c50aff56cd..daa582e513b2 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_common.h
+++ b/sound/soc/intel/boards/skl_hda_dsp_common.h
@@ -15,7 +15,7 @@
15#include <sound/core.h> 15#include <sound/core.h>
16#include <sound/jack.h> 16#include <sound/jack.h>
17 17
18#define HDA_DSP_MAX_BE_DAI_LINKS 5 18#define HDA_DSP_MAX_BE_DAI_LINKS 7
19 19
20struct skl_hda_hdmi_pcm { 20struct skl_hda_hdmi_pcm {
21 struct list_head head; 21 struct list_head head;
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index b9a21e64ead2..fc52d3a32354 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -97,6 +97,9 @@ static struct snd_soc_card hda_soc_card = {
97}; 97};
98 98
99#define IDISP_DAI_COUNT 3 99#define IDISP_DAI_COUNT 3
100#define HDAC_DAI_COUNT 2
101#define DMIC_DAI_COUNT 2
102
100/* there are two routes per iDisp output */ 103/* there are two routes per iDisp output */
101#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) 104#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2)
102#define IDISP_CODEC_MASK 0x4 105#define IDISP_CODEC_MASK 0x4
@@ -112,11 +115,23 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
112 codec_count = hweight_long(codec_mask); 115 codec_count = hweight_long(codec_mask);
113 116
114 if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { 117 if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) {
115 num_links = IDISP_DAI_COUNT; 118 num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT;
116 num_route = IDISP_ROUTE_COUNT; 119 num_route = IDISP_ROUTE_COUNT;
120
121 /*
122 * rearrange the dai link array and make the
123 * dmic dai links follow idsp dai links for only
124 * num_links of dai links need to be registered
125 * to ASoC.
126 */
127 for (i = 0; i < DMIC_DAI_COUNT; i++) {
128 skl_hda_be_dai_links[IDISP_DAI_COUNT + i] =
129 skl_hda_be_dai_links[IDISP_DAI_COUNT +
130 HDAC_DAI_COUNT + i];
131 }
117 } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { 132 } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
118 num_links = ARRAY_SIZE(skl_hda_be_dai_links); 133 num_links = ARRAY_SIZE(skl_hda_be_dai_links);
119 num_route = ARRAY_SIZE(skl_hda_map), 134 num_route = ARRAY_SIZE(skl_hda_map);
120 card->dapm_widgets = skl_hda_widgets; 135 card->dapm_widgets = skl_hda_widgets;
121 card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); 136 card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets);
122 } else { 137 } else {
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c
new file mode 100644
index 000000000000..f28fb98cc306
--- /dev/null
+++ b/sound/soc/intel/boards/sof_rt5682.c
@@ -0,0 +1,563 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright(c) 2019 Intel Corporation.
3
4/*
5 * Intel SOF Machine Driver with Realtek rt5682 Codec
6 * and speaker codec MAX98357A
7 */
8#include <linux/i2c.h>
9#include <linux/input.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/dmi.h>
13#include <asm/cpu_device_id.h>
14#include <asm/intel-family.h>
15#include <sound/core.h>
16#include <sound/jack.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/soc.h>
20#include <sound/rt5682.h>
21#include <sound/soc-acpi.h>
22#include "../../codecs/rt5682.h"
23#include "../../codecs/hdac_hdmi.h"
24
25#define NAME_SIZE 32
26
27#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
28#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
29#define SOF_RT5682_MCLK_EN BIT(3)
30#define SOF_RT5682_MCLK_24MHZ BIT(4)
31#define SOF_SPEAKER_AMP_PRESENT BIT(5)
32#define SOF_RT5682_SSP_AMP(quirk) ((quirk) & GENMASK(8, 6))
33#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
34#define SOF_RT5682_SSP_AMP_SHIFT 6
35
36/* Default: MCLK on, MCLK 19.2M, SSP0 */
37static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
38 SOF_RT5682_SSP_CODEC(0);
39
40static int is_legacy_cpu;
41
42static struct snd_soc_jack sof_hdmi[3];
43
44struct sof_hdmi_pcm {
45 struct list_head head;
46 struct snd_soc_dai *codec_dai;
47 int device;
48};
49
50struct sof_card_private {
51 struct snd_soc_jack sof_headset;
52 struct list_head hdmi_pcm_list;
53};
54
55static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
56{
57 sof_rt5682_quirk = (unsigned long)id->driver_data;
58 return 1;
59}
60
61static const struct dmi_system_id sof_rt5682_quirk_table[] = {
62 {
63 .callback = sof_rt5682_quirk_cb,
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
67 },
68 .driver_data = (void *)(SOF_RT5682_MCLK_EN |
69 SOF_RT5682_MCLK_24MHZ |
70 SOF_RT5682_SSP_CODEC(1)),
71 },
72 {
73 .callback = sof_rt5682_quirk_cb,
74 .matches = {
75 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
76 DMI_MATCH(DMI_PRODUCT_NAME, "Hatch"),
77 },
78 .driver_data = (void *)(SOF_RT5682_MCLK_EN |
79 SOF_RT5682_MCLK_24MHZ |
80 SOF_RT5682_SSP_CODEC(0) |
81 SOF_SPEAKER_AMP_PRESENT |
82 SOF_RT5682_SSP_AMP(1)),
83 },
84 {
85 .callback = sof_rt5682_quirk_cb,
86 .matches = {
87 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
88 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
89 },
90 .driver_data = (void *)(SOF_RT5682_MCLK_EN |
91 SOF_RT5682_SSP_CODEC(0)),
92 },
93 {}
94};
95
96static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
97{
98 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
99 struct snd_soc_dai *dai = rtd->codec_dai;
100 struct sof_hdmi_pcm *pcm;
101
102 pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
103 if (!pcm)
104 return -ENOMEM;
105
106 /* dai_link id is 1:1 mapped to the PCM device */
107 pcm->device = rtd->dai_link->id;
108 pcm->codec_dai = dai;
109
110 list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
111
112 return 0;
113}
114
115static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
116{
117 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
118 struct snd_soc_component *component = rtd->codec_dai->component;
119 struct snd_soc_jack *jack;
120 int ret;
121
122 /* need to enable ASRC function for 24MHz mclk rate */
123 if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) &&
124 (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) {
125 rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
126 RT5682_AD_STEREO1_FILTER,
127 RT5682_CLK_SEL_I2S1_ASRC);
128 }
129
130 /*
131 * Headset buttons map to the google Reference headset.
132 * These can be configured by userspace.
133 */
134 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
135 SND_JACK_HEADSET | SND_JACK_BTN_0 |
136 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
137 SND_JACK_BTN_3,
138 &ctx->sof_headset, NULL, 0);
139 if (ret) {
140 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
141 return ret;
142 }
143
144 jack = &ctx->sof_headset;
145
146 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
147 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
148 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
149 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
150 ret = snd_soc_component_set_jack(component, jack, NULL);
151
152 if (ret) {
153 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
154 return ret;
155 }
156
157 return ret;
158};
159
160static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
161 struct snd_pcm_hw_params *params)
162{
163 struct snd_soc_pcm_runtime *rtd = substream->private_data;
164 struct snd_soc_dai *codec_dai = rtd->codec_dai;
165 int clk_id, clk_freq, pll_out, ret;
166
167 if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
168 clk_id = RT5682_PLL1_S_MCLK;
169 if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)
170 clk_freq = 24000000;
171 else
172 clk_freq = 19200000;
173 } else {
174 clk_id = RT5682_PLL1_S_BCLK1;
175 clk_freq = params_rate(params) * 50;
176 }
177
178 pll_out = params_rate(params) * 512;
179
180 ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
181 if (ret < 0)
182 dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
183
184 /* Configure sysclk for codec */
185 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
186 pll_out, SND_SOC_CLOCK_IN);
187 if (ret < 0)
188 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
189
190 /*
191 * slot_width should equal or large than data length, set them
192 * be the same
193 */
194 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
195 params_width(params));
196 if (ret < 0) {
197 dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
198 return ret;
199 }
200
201 return ret;
202}
203
204static struct snd_soc_ops sof_rt5682_ops = {
205 .hw_params = sof_rt5682_hw_params,
206};
207
208static struct snd_soc_dai_link_component platform_component[] = {
209 {
210 /* name might be overridden during probe */
211 .name = "0000:00:1f.3"
212 }
213};
214
215static int sof_card_late_probe(struct snd_soc_card *card)
216{
217 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
218 struct snd_soc_component *component = NULL;
219 char jack_name[NAME_SIZE];
220 struct sof_hdmi_pcm *pcm;
221 int err = 0;
222 int i = 0;
223
224 /* HDMI is not supported by SOF on Baytrail/CherryTrail */
225 if (is_legacy_cpu)
226 return 0;
227
228 list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
229 component = pcm->codec_dai->component;
230 snprintf(jack_name, sizeof(jack_name),
231 "HDMI/DP, pcm=%d Jack", pcm->device);
232 err = snd_soc_card_jack_new(card, jack_name,
233 SND_JACK_AVOUT, &sof_hdmi[i],
234 NULL, 0);
235
236 if (err)
237 return err;
238
239 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
240 &sof_hdmi[i]);
241 if (err < 0)
242 return err;
243
244 i++;
245 }
246 if (!component)
247 return -EINVAL;
248
249 return hdac_hdmi_jack_port_init(component, &card->dapm);
250}
251
252static const struct snd_kcontrol_new sof_controls[] = {
253 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
254 SOC_DAPM_PIN_SWITCH("Headset Mic"),
255 SOC_DAPM_PIN_SWITCH("Spk"),
256};
257
258static const struct snd_soc_dapm_widget sof_widgets[] = {
259 SND_SOC_DAPM_HP("Headphone Jack", NULL),
260 SND_SOC_DAPM_MIC("Headset Mic", NULL),
261 SND_SOC_DAPM_SPK("Spk", NULL),
262};
263
264static const struct snd_soc_dapm_route sof_map[] = {
265 /* HP jack connectors - unknown if we have jack detection */
266 { "Headphone Jack", NULL, "HPOL" },
267 { "Headphone Jack", NULL, "HPOR" },
268
269 /* other jacks */
270 { "IN1P", NULL, "Headset Mic" },
271
272};
273
274static const struct snd_soc_dapm_route speaker_map[] = {
275 /* speaker */
276 { "Spk", NULL, "Speaker" },
277};
278
279static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
280{
281 struct snd_soc_card *card = rtd->card;
282 int ret;
283
284 ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map,
285 ARRAY_SIZE(speaker_map));
286
287 if (ret)
288 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
289 return ret;
290}
291
292/* sof audio machine driver for rt5682 codec */
293static struct snd_soc_card sof_audio_card_rt5682 = {
294 .name = "sof_rt5682",
295 .owner = THIS_MODULE,
296 .controls = sof_controls,
297 .num_controls = ARRAY_SIZE(sof_controls),
298 .dapm_widgets = sof_widgets,
299 .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
300 .dapm_routes = sof_map,
301 .num_dapm_routes = ARRAY_SIZE(sof_map),
302 .fully_routed = true,
303 .late_probe = sof_card_late_probe,
304};
305
306static const struct x86_cpu_id legacy_cpi_ids[] = {
307 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Baytrail */
308 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, /* Cherrytrail */
309 {}
310};
311
312static struct snd_soc_dai_link_component rt5682_component[] = {
313 {
314 .name = "i2c-10EC5682:00",
315 .dai_name = "rt5682-aif1",
316 }
317};
318
319static struct snd_soc_dai_link_component dmic_component[] = {
320 {
321 .name = "dmic-codec",
322 .dai_name = "dmic-hifi",
323 }
324};
325
326static struct snd_soc_dai_link_component max98357a_component[] = {
327 {
328 .name = "MX98357A:00",
329 .dai_name = "HiFi",
330 }
331};
332
333static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
334 int ssp_codec,
335 int ssp_amp,
336 int dmic_num,
337 int hdmi_num)
338{
339 struct snd_soc_dai_link_component *idisp_components;
340 struct snd_soc_dai_link *links;
341 int i, id = 0;
342
343 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
344 sof_audio_card_rt5682.num_links, GFP_KERNEL);
345 if (!links)
346 goto devm_err;
347
348 /* codec SSP */
349 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
350 "SSP%d-Codec", ssp_codec);
351 if (!links[id].name)
352 goto devm_err;
353
354 links[id].id = id;
355 links[id].codecs = rt5682_component;
356 links[id].num_codecs = ARRAY_SIZE(rt5682_component);
357 links[id].platforms = platform_component;
358 links[id].num_platforms = ARRAY_SIZE(platform_component);
359 links[id].init = sof_rt5682_codec_init;
360 links[id].ops = &sof_rt5682_ops;
361 links[id].nonatomic = true;
362 links[id].dpcm_playback = 1;
363 links[id].dpcm_capture = 1;
364 links[id].no_pcm = 1;
365 if (is_legacy_cpu) {
366 links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL,
367 "ssp%d-port",
368 ssp_codec);
369 if (!links[id].cpu_dai_name)
370 goto devm_err;
371 } else {
372 /*
373 * Currently, On SKL+ platforms MCLK will be turned off in sof
374 * runtime suspended, and it will go into runtime suspended
375 * right after playback is stop. However, rt5682 will output
376 * static noise if sysclk turns off during playback. Set
377 * ignore_pmdown_time to power down rt5682 immediately and
378 * avoid the noise.
379 * It can be removed once we can control MCLK by driver.
380 */
381 links[id].ignore_pmdown_time = 1;
382 links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL,
383 "SSP%d Pin",
384 ssp_codec);
385 if (!links[id].cpu_dai_name)
386 goto devm_err;
387 }
388 id++;
389
390 /* dmic */
391 for (i = 1; i <= dmic_num; i++) {
392 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
393 "dmic%02d", i);
394 if (!links[id].name)
395 goto devm_err;
396
397 links[id].id = id;
398 links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL,
399 "DMIC%02d Pin", i);
400 if (!links[id].cpu_dai_name)
401 goto devm_err;
402
403 links[id].codecs = dmic_component;
404 links[id].num_codecs = ARRAY_SIZE(dmic_component);
405 links[id].platforms = platform_component;
406 links[id].num_platforms = ARRAY_SIZE(platform_component);
407 links[id].ignore_suspend = 1;
408 links[id].dpcm_capture = 1;
409 links[id].no_pcm = 1;
410 id++;
411 }
412
413 /* HDMI */
414 if (hdmi_num > 0) {
415 idisp_components = devm_kzalloc(dev,
416 sizeof(struct snd_soc_dai_link_component) *
417 hdmi_num, GFP_KERNEL);
418 if (!idisp_components)
419 goto devm_err;
420 }
421 for (i = 1; i <= hdmi_num; i++) {
422 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
423 "iDisp%d", i);
424 if (!links[id].name)
425 goto devm_err;
426
427 links[id].id = id;
428 links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL,
429 "iDisp%d Pin", i);
430 if (!links[id].cpu_dai_name)
431 goto devm_err;
432
433 idisp_components[i - 1].name = "ehdaudio0D2";
434 idisp_components[i - 1].dai_name = devm_kasprintf(dev,
435 GFP_KERNEL,
436 "intel-hdmi-hifi%d",
437 i);
438 if (!idisp_components[i - 1].dai_name)
439 goto devm_err;
440
441 links[id].codecs = &idisp_components[i - 1];
442 links[id].num_codecs = 1;
443 links[id].platforms = platform_component;
444 links[id].num_platforms = ARRAY_SIZE(platform_component);
445 links[id].init = sof_hdmi_init;
446 links[id].dpcm_playback = 1;
447 links[id].no_pcm = 1;
448 id++;
449 }
450
451 /* speaker amp */
452 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) {
453 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
454 "SSP%d-Codec", ssp_amp);
455 if (!links[id].name)
456 goto devm_err;
457
458 links[id].id = id;
459 links[id].codecs = max98357a_component;
460 links[id].num_codecs = ARRAY_SIZE(max98357a_component);
461 links[id].platforms = platform_component;
462 links[id].num_platforms = ARRAY_SIZE(platform_component);
463 links[id].init = speaker_codec_init,
464 links[id].nonatomic = true;
465 links[id].dpcm_playback = 1;
466 links[id].no_pcm = 1;
467 if (is_legacy_cpu) {
468 links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL,
469 "ssp%d-port",
470 ssp_amp);
471 if (!links[id].cpu_dai_name)
472 goto devm_err;
473
474 } else {
475 links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL,
476 "SSP%d Pin",
477 ssp_amp);
478 if (!links[id].cpu_dai_name)
479 goto devm_err;
480 }
481 }
482
483 return links;
484devm_err:
485 return NULL;
486}
487
488static int sof_audio_probe(struct platform_device *pdev)
489{
490 struct snd_soc_dai_link *dai_links;
491 struct snd_soc_acpi_mach *mach;
492 struct sof_card_private *ctx;
493 int dmic_num, hdmi_num;
494 int ret, ssp_amp, ssp_codec;
495
496 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
497 if (!ctx)
498 return -ENOMEM;
499
500 if (x86_match_cpu(legacy_cpi_ids)) {
501 is_legacy_cpu = 1;
502 dmic_num = 0;
503 hdmi_num = 0;
504 /* default quirk for legacy cpu */
505 sof_rt5682_quirk = SOF_RT5682_SSP_CODEC(2);
506 } else {
507 dmic_num = 1;
508 hdmi_num = 3;
509 }
510
511 dmi_check_system(sof_rt5682_quirk_table);
512
513 dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
514
515 ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >>
516 SOF_RT5682_SSP_AMP_SHIFT;
517
518 ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK;
519
520 /* compute number of dai links */
521 sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num;
522 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT)
523 sof_audio_card_rt5682.num_links++;
524
525 dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
526 dmic_num, hdmi_num);
527 if (!dai_links)
528 return -ENOMEM;
529
530 sof_audio_card_rt5682.dai_link = dai_links;
531
532 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
533
534 sof_audio_card_rt5682.dev = &pdev->dev;
535 mach = (&pdev->dev)->platform_data;
536
537 /* set platform name for each dailink */
538 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682,
539 mach->mach_params.platform);
540 if (ret)
541 return ret;
542
543 snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx);
544
545 return devm_snd_soc_register_card(&pdev->dev,
546 &sof_audio_card_rt5682);
547}
548
549static struct platform_driver sof_audio = {
550 .probe = sof_audio_probe,
551 .driver = {
552 .name = "sof_rt5682",
553 .pm = &snd_soc_pm_ops,
554 },
555};
556module_platform_driver(sof_audio)
557
558/* Module information */
559MODULE_DESCRIPTION("SOF Audio Machine driver");
560MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>");
561MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
562MODULE_LICENSE("GPL v2");
563MODULE_ALIAS("platform:sof_rt5682");
diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
index fe812a909db4..0cfab247876a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
@@ -185,6 +185,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
185 .sof_fw_filename = "sof-byt.ri", 185 .sof_fw_filename = "sof-byt.ri",
186 .sof_tplg_filename = "sof-byt-es8316.tplg", 186 .sof_tplg_filename = "sof-byt-es8316.tplg",
187 }, 187 },
188 {
189 .id = "10EC5682",
190 .drv_name = "sof_rt5682",
191 .sof_fw_filename = "sof-byt.ri",
192 .sof_tplg_filename = "sof-byt-rt5682.tplg",
193 },
188 /* some Baytrail platforms rely on RT5645, use CHT machine driver */ 194 /* some Baytrail platforms rely on RT5645, use CHT machine driver */
189 { 195 {
190 .id = "10EC5645", 196 .id = "10EC5645",
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
index deafd87cc764..ff9c31a39ad4 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -160,6 +160,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
160 .sof_fw_filename = "sof-cht.ri", 160 .sof_fw_filename = "sof-cht.ri",
161 .sof_tplg_filename = "sof-cht-rt5640.tplg", 161 .sof_tplg_filename = "sof-cht-rt5640.tplg",
162 }, 162 },
163 {
164 .id = "10EC5682",
165 .drv_name = "sof_rt5682",
166 .sof_fw_filename = "sof-cht.ri",
167 .sof_tplg_filename = "sof-cht-rt5682.tplg",
168 },
163 /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ 169 /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
164 { 170 {
165 .id = "10EC5651", 171 .id = "10EC5651",
diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
index a914dd238d0a..df7c52cad5c3 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
@@ -14,6 +14,11 @@ static struct skl_machine_pdata cnl_pdata = {
14 .use_tplg_pcm = true, 14 .use_tplg_pcm = true,
15}; 15};
16 16
17static struct snd_soc_acpi_codecs cml_codecs = {
18 .num_codecs = 1,
19 .codecs = {"10EC5682"}
20};
21
17struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { 22struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
18 { 23 {
19 .id = "INT34C2", 24 .id = "INT34C2",
@@ -23,6 +28,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
23 .sof_fw_filename = "sof-cnl.ri", 28 .sof_fw_filename = "sof-cnl.ri",
24 .sof_tplg_filename = "sof-cnl-rt274.tplg", 29 .sof_tplg_filename = "sof-cnl-rt274.tplg",
25 }, 30 },
31 {
32 .id = "10EC5682",
33 .drv_name = "sof_rt5682",
34 .sof_fw_filename = "sof-cnl.ri",
35 .sof_tplg_filename = "sof-cml-rt5682.tplg",
36 },
37 {
38 .id = "MX98357A",
39 .drv_name = "sof_rt5682",
40 .quirk_data = &cml_codecs,
41 .sof_fw_filename = "sof-cnl.ri",
42 .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg",
43 },
44
26 {}, 45 {},
27}; 46};
28EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); 47EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
index 3f2061475ae4..616eb09e78a0 100644
--- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
@@ -31,6 +31,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
31 .sof_fw_filename = "sof-glk.ri", 31 .sof_fw_filename = "sof-glk.ri",
32 .sof_tplg_filename = "sof-glk-da7219.tplg", 32 .sof_tplg_filename = "sof-glk-da7219.tplg",
33 }, 33 },
34 {
35 .id = "10EC5682",
36 .drv_name = "glk_rt5682_max98357a",
37 .fw_filename = "intel/dsp_fw_glk.bin",
38 .machine_quirk = snd_soc_acpi_codec_list,
39 .quirk_data = &glk_codecs,
40 .sof_fw_filename = "sof-glk.ri",
41 .sof_tplg_filename = "sof-glk-rt5682.tplg",
42 },
34 {}, 43 {},
35}; 44};
36EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines); 45EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
index e5a6be5bc0ee..0b430b9b3673 100644
--- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c
@@ -23,6 +23,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = {
23 .sof_fw_filename = "sof-icl.ri", 23 .sof_fw_filename = "sof-icl.ri",
24 .sof_tplg_filename = "sof-icl-rt274.tplg", 24 .sof_tplg_filename = "sof-icl-rt274.tplg",
25 }, 25 },
26 {
27 .id = "10EC5682",
28 .drv_name = "sof_rt5682",
29 .sof_fw_filename = "sof-icl.ri",
30 .sof_tplg_filename = "sof-icl-rt5682.tplg",
31 },
26 {}, 32 {},
27}; 33};
28EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); 34EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines);
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
index 1e067504b604..f830e59f93ea 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -1251,11 +1251,15 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
1251 goto irq_err; 1251 goto irq_err;
1252 1252
1253 err = sst_dma_new(sst); 1253 err = sst_dma_new(sst);
1254 if (err) 1254 if (err) {
1255 dev_warn(dev, "sst_dma_new failed %d\n", err); 1255 dev_err(dev, "sst_dma_new failed %d\n", err);
1256 goto dma_err;
1257 }
1256 1258
1257 return sst; 1259 return sst;
1258 1260
1261dma_err:
1262 free_irq(sst->irq, sst);
1259irq_err: 1263irq_err:
1260 if (sst->ops->free) 1264 if (sst->ops->free)
1261 sst->ops->free(sst); 1265 sst->ops->free(sst);
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c
index 31fcdf12c67d..74acf9c65161 100644
--- a/sound/soc/intel/haswell/sst-haswell-ipc.c
+++ b/sound/soc/intel/haswell/sst-haswell-ipc.c
@@ -345,11 +345,6 @@ static inline u32 msg_get_stream_type(u32 msg)
345 return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT; 345 return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT;
346} 346}
347 347
348static inline u32 msg_get_stage_type(u32 msg)
349{
350 return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
351}
352
353static inline u32 msg_get_stream_id(u32 msg) 348static inline u32 msg_get_stream_id(u32 msg)
354{ 349{
355 return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; 350 return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT;
@@ -666,13 +661,12 @@ static int hsw_module_message(struct sst_hsw *hsw, u32 header)
666 661
667static int hsw_stream_message(struct sst_hsw *hsw, u32 header) 662static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
668{ 663{
669 u32 stream_msg, stream_id, stage_type; 664 u32 stream_msg, stream_id;
670 struct sst_hsw_stream *stream; 665 struct sst_hsw_stream *stream;
671 int handled = 0; 666 int handled = 0;
672 667
673 stream_msg = msg_get_stream_type(header); 668 stream_msg = msg_get_stream_type(header);
674 stream_id = msg_get_stream_id(header); 669 stream_id = msg_get_stream_id(header);
675 stage_type = msg_get_stage_type(header);
676 670
677 stream = get_stream_by_id(hsw, stream_id); 671 stream = get_stream_by_id(hsw, stream_id);
678 if (stream == NULL) 672 if (stream == NULL)
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
index 1a354a6b6e87..b3f9c41b4319 100644
--- a/sound/soc/jz4740/Kconfig
+++ b/sound/soc/jz4740/Kconfig
@@ -1,6 +1,6 @@
1config SND_JZ4740_SOC 1config SND_JZ4740_SOC
2 tristate "SoC Audio for Ingenic JZ4740 SoC" 2 tristate "SoC Audio for Ingenic JZ4740 SoC"
3 depends on MACH_JZ4740 || COMPILE_TEST 3 depends on MIPS || COMPILE_TEST
4 select SND_SOC_GENERIC_DMAENGINE_PCM 4 select SND_SOC_GENERIC_DMAENGINE_PCM
5 help 5 help
6 Say Y or M if you want to add support for codecs attached to 6 Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index b35410e4020e..f70b7109f2b6 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -116,6 +116,33 @@ config SND_SOC_MT8183
116 Select Y if you have such device. 116 Select Y if you have such device.
117 If unsure select "N". 117 If unsure select "N".
118 118
119config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A
120 tristate "ASoC Audio driver for MT8183 with MT6358 TS3A227E MAX98357A codec"
121 depends on I2C
122 depends on SND_SOC_MT8183
123 select SND_SOC_MT6358
124 select SND_SOC_MAX98357A
125 select SND_SOC_BT_SCO
126 select SND_SOC_TS3A227E
127 help
128 This adds ASoC driver for Mediatek MT8183 boards
129 with the MT6358 TS3A227E MAX98357A audio codec.
130 Select Y if you have such device.
131 If unsure select "N".
132
133config SND_SOC_MT8183_DA7219_MAX98357A
134 tristate "ASoC Audio driver for MT8183 with DA7219 MAX98357A codec"
135 depends on SND_SOC_MT8183
136 select SND_SOC_MT6358
137 select SND_SOC_MAX98357A
138 select SND_SOC_DA7219
139 select SND_SOC_BT_SCO
140 help
141 This adds ASoC driver for Mediatek MT8183 boards
142 with the DA7219 MAX98357A audio codec.
143 Select Y if you have such device.
144 If unsure select "N".
145
119config SND_SOC_MTK_BTCVSD 146config SND_SOC_MTK_BTCVSD
120 tristate "ALSA BT SCO CVSD/MSBC Driver" 147 tristate "ALSA BT SCO CVSD/MSBC Driver"
121 help 148 help
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index cf4978be062f..fded11d14cde 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -18,11 +18,11 @@
18 18
19static int mtk_regmap_update_bits(struct regmap *map, int reg, 19static int mtk_regmap_update_bits(struct regmap *map, int reg,
20 unsigned int mask, 20 unsigned int mask,
21 unsigned int val) 21 unsigned int val, int shift)
22{ 22{
23 if (reg < 0) 23 if (reg < 0 || WARN_ON_ONCE(shift < 0))
24 return 0; 24 return 0;
25 return regmap_update_bits(map, reg, mask, val); 25 return regmap_update_bits(map, reg, mask << shift, val << shift);
26} 26}
27 27
28static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) 28static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
@@ -49,8 +49,7 @@ int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
49 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); 49 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
50 /* enable agent */ 50 /* enable agent */
51 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 51 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
52 1 << memif->data->agent_disable_shift, 52 1, 0, memif->data->agent_disable_shift);
53 0 << memif->data->agent_disable_shift);
54 53
55 snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); 54 snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
56 55
@@ -105,8 +104,7 @@ void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
105 irq_id = memif->irq_usage; 104 irq_id = memif->irq_usage;
106 105
107 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, 106 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
108 1 << memif->data->agent_disable_shift, 107 1, 1, memif->data->agent_disable_shift);
109 1 << memif->data->agent_disable_shift);
110 108
111 if (!memif->const_irq) { 109 if (!memif->const_irq) {
112 mtk_dynamic_irq_release(afe, irq_id); 110 mtk_dynamic_irq_release(afe, irq_id);
@@ -144,16 +142,14 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
144 142
145 /* set MSB to 33-bit */ 143 /* set MSB to 33-bit */
146 mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, 144 mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
147 1 << memif->data->msb_shift, 145 1, msb_at_bit33, memif->data->msb_shift);
148 msb_at_bit33 << memif->data->msb_shift);
149 146
150 /* set channel */ 147 /* set channel */
151 if (memif->data->mono_shift >= 0) { 148 if (memif->data->mono_shift >= 0) {
152 unsigned int mono = (params_channels(params) == 1) ? 1 : 0; 149 unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
153 150
154 mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, 151 mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
155 1 << memif->data->mono_shift, 152 1, mono, memif->data->mono_shift);
156 mono << memif->data->mono_shift);
157 } 153 }
158 154
159 /* set rate */ 155 /* set rate */
@@ -166,8 +162,8 @@ int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
166 return -EINVAL; 162 return -EINVAL;
167 163
168 mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, 164 mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
169 memif->data->fs_maskbit << memif->data->fs_shift, 165 memif->data->fs_maskbit, fs,
170 fs << memif->data->fs_shift); 166 memif->data->fs_shift);
171 167
172 return 0; 168 return 0;
173} 169}
@@ -197,17 +193,14 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
197 switch (cmd) { 193 switch (cmd) {
198 case SNDRV_PCM_TRIGGER_START: 194 case SNDRV_PCM_TRIGGER_START:
199 case SNDRV_PCM_TRIGGER_RESUME: 195 case SNDRV_PCM_TRIGGER_RESUME:
200 if (memif->data->enable_shift >= 0) 196 mtk_regmap_update_bits(afe->regmap,
201 mtk_regmap_update_bits(afe->regmap, 197 memif->data->enable_reg,
202 memif->data->enable_reg, 198 1, 1, memif->data->enable_shift);
203 1 << memif->data->enable_shift,
204 1 << memif->data->enable_shift);
205 199
206 /* set irq counter */ 200 /* set irq counter */
207 mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, 201 mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
208 irq_data->irq_cnt_maskbit 202 irq_data->irq_cnt_maskbit, counter,
209 << irq_data->irq_cnt_shift, 203 irq_data->irq_cnt_shift);
210 counter << irq_data->irq_cnt_shift);
211 204
212 /* set irq fs */ 205 /* set irq fs */
213 fs = afe->irq_fs(substream, runtime->rate); 206 fs = afe->irq_fs(substream, runtime->rate);
@@ -216,24 +209,21 @@ int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
216 return -EINVAL; 209 return -EINVAL;
217 210
218 mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, 211 mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
219 irq_data->irq_fs_maskbit 212 irq_data->irq_fs_maskbit, fs,
220 << irq_data->irq_fs_shift, 213 irq_data->irq_fs_shift);
221 fs << irq_data->irq_fs_shift);
222 214
223 /* enable interrupt */ 215 /* enable interrupt */
224 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 216 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
225 1 << irq_data->irq_en_shift, 217 1, 1, irq_data->irq_en_shift);
226 1 << irq_data->irq_en_shift);
227 218
228 return 0; 219 return 0;
229 case SNDRV_PCM_TRIGGER_STOP: 220 case SNDRV_PCM_TRIGGER_STOP:
230 case SNDRV_PCM_TRIGGER_SUSPEND: 221 case SNDRV_PCM_TRIGGER_SUSPEND:
231 mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, 222 mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
232 1 << memif->data->enable_shift, 0); 223 1, 0, memif->data->enable_shift);
233 /* disable interrupt */ 224 /* disable interrupt */
234 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, 225 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
235 1 << irq_data->irq_en_shift, 226 1, 0, irq_data->irq_en_shift);
236 0 << irq_data->irq_en_shift);
237 /* and clear pending IRQ */ 227 /* and clear pending IRQ */
238 mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, 228 mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
239 1 << irq_data->irq_clr_shift); 229 1 << irq_data->irq_clr_shift);
@@ -270,8 +260,7 @@ int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
270 } 260 }
271 261
272 mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, 262 mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
273 1 << memif->data->hd_shift, 263 1, hd_audio, memif->data->hd_shift);
274 hd_audio << memif->data->hd_shift);
275 264
276 return 0; 265 return 0;
277} 266}
diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c
index 9a163d7064d1..bd55c546e790 100644
--- a/sound/soc/mediatek/common/mtk-btcvsd.c
+++ b/sound/soc/mediatek/common/mtk-btcvsd.c
@@ -193,13 +193,13 @@ static const u8 table_msbc_silence[SCO_PACKET_180] = {
193static void mtk_btcvsd_snd_irq_enable(struct mtk_btcvsd_snd *bt) 193static void mtk_btcvsd_snd_irq_enable(struct mtk_btcvsd_snd *bt)
194{ 194{
195 regmap_update_bits(bt->infra, bt->infra_misc_offset, 195 regmap_update_bits(bt->infra, bt->infra_misc_offset,
196 bt->conn_bt_cvsd_mask, bt->conn_bt_cvsd_mask); 196 bt->conn_bt_cvsd_mask, 0);
197} 197}
198 198
199static void mtk_btcvsd_snd_irq_disable(struct mtk_btcvsd_snd *bt) 199static void mtk_btcvsd_snd_irq_disable(struct mtk_btcvsd_snd *bt)
200{ 200{
201 regmap_update_bits(bt->infra, bt->infra_misc_offset, 201 regmap_update_bits(bt->infra, bt->infra_misc_offset,
202 bt->conn_bt_cvsd_mask, 0); 202 bt->conn_bt_cvsd_mask, bt->conn_bt_cvsd_mask);
203} 203}
204 204
205static void mtk_btcvsd_snd_set_state(struct mtk_btcvsd_snd *bt, 205static void mtk_btcvsd_snd_set_state(struct mtk_btcvsd_snd *bt,
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 968fba4d7533..7064a9fd6f74 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -994,7 +994,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
994 .agent_disable_reg = AUDIO_TOP_CON5, 994 .agent_disable_reg = AUDIO_TOP_CON5,
995 .agent_disable_shift = 6, 995 .agent_disable_shift = 6,
996 .msb_reg = -1, 996 .msb_reg = -1,
997 .msb_shift = -1,
998 }, 997 },
999 { 998 {
1000 .name = "DL2", 999 .name = "DL2",
@@ -1013,7 +1012,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1013 .agent_disable_reg = AUDIO_TOP_CON5, 1012 .agent_disable_reg = AUDIO_TOP_CON5,
1014 .agent_disable_shift = 7, 1013 .agent_disable_shift = 7,
1015 .msb_reg = -1, 1014 .msb_reg = -1,
1016 .msb_shift = -1,
1017 }, 1015 },
1018 { 1016 {
1019 .name = "DL3", 1017 .name = "DL3",
@@ -1032,7 +1030,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1032 .agent_disable_reg = AUDIO_TOP_CON5, 1030 .agent_disable_reg = AUDIO_TOP_CON5,
1033 .agent_disable_shift = 8, 1031 .agent_disable_shift = 8,
1034 .msb_reg = -1, 1032 .msb_reg = -1,
1035 .msb_shift = -1,
1036 }, 1033 },
1037 { 1034 {
1038 .name = "DL4", 1035 .name = "DL4",
@@ -1051,7 +1048,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1051 .agent_disable_reg = AUDIO_TOP_CON5, 1048 .agent_disable_reg = AUDIO_TOP_CON5,
1052 .agent_disable_shift = 9, 1049 .agent_disable_shift = 9,
1053 .msb_reg = -1, 1050 .msb_reg = -1,
1054 .msb_shift = -1,
1055 }, 1051 },
1056 { 1052 {
1057 .name = "DL5", 1053 .name = "DL5",
@@ -1070,7 +1066,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1070 .agent_disable_reg = AUDIO_TOP_CON5, 1066 .agent_disable_reg = AUDIO_TOP_CON5,
1071 .agent_disable_shift = 10, 1067 .agent_disable_shift = 10,
1072 .msb_reg = -1, 1068 .msb_reg = -1,
1073 .msb_shift = -1,
1074 }, 1069 },
1075 { 1070 {
1076 .name = "DLM", 1071 .name = "DLM",
@@ -1089,7 +1084,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1089 .agent_disable_reg = AUDIO_TOP_CON5, 1084 .agent_disable_reg = AUDIO_TOP_CON5,
1090 .agent_disable_shift = 12, 1085 .agent_disable_shift = 12,
1091 .msb_reg = -1, 1086 .msb_reg = -1,
1092 .msb_shift = -1,
1093 }, 1087 },
1094 { 1088 {
1095 .name = "UL1", 1089 .name = "UL1",
@@ -1108,7 +1102,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1108 .agent_disable_reg = AUDIO_TOP_CON5, 1102 .agent_disable_reg = AUDIO_TOP_CON5,
1109 .agent_disable_shift = 0, 1103 .agent_disable_shift = 0,
1110 .msb_reg = -1, 1104 .msb_reg = -1,
1111 .msb_shift = -1,
1112 }, 1105 },
1113 { 1106 {
1114 .name = "UL2", 1107 .name = "UL2",
@@ -1127,7 +1120,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1127 .agent_disable_reg = AUDIO_TOP_CON5, 1120 .agent_disable_reg = AUDIO_TOP_CON5,
1128 .agent_disable_shift = 1, 1121 .agent_disable_shift = 1,
1129 .msb_reg = -1, 1122 .msb_reg = -1,
1130 .msb_shift = -1,
1131 }, 1123 },
1132 { 1124 {
1133 .name = "UL3", 1125 .name = "UL3",
@@ -1146,7 +1138,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1146 .agent_disable_reg = AUDIO_TOP_CON5, 1138 .agent_disable_reg = AUDIO_TOP_CON5,
1147 .agent_disable_shift = 2, 1139 .agent_disable_shift = 2,
1148 .msb_reg = -1, 1140 .msb_reg = -1,
1149 .msb_shift = -1,
1150 }, 1141 },
1151 { 1142 {
1152 .name = "UL4", 1143 .name = "UL4",
@@ -1165,7 +1156,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1165 .agent_disable_reg = AUDIO_TOP_CON5, 1156 .agent_disable_reg = AUDIO_TOP_CON5,
1166 .agent_disable_shift = 3, 1157 .agent_disable_shift = 3,
1167 .msb_reg = -1, 1158 .msb_reg = -1,
1168 .msb_shift = -1,
1169 }, 1159 },
1170 { 1160 {
1171 .name = "UL5", 1161 .name = "UL5",
@@ -1184,7 +1174,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1184 .agent_disable_reg = AUDIO_TOP_CON5, 1174 .agent_disable_reg = AUDIO_TOP_CON5,
1185 .agent_disable_shift = 4, 1175 .agent_disable_shift = 4,
1186 .msb_reg = -1, 1176 .msb_reg = -1,
1187 .msb_shift = -1,
1188 }, 1177 },
1189 { 1178 {
1190 .name = "DLBT", 1179 .name = "DLBT",
@@ -1203,7 +1192,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1203 .agent_disable_reg = AUDIO_TOP_CON5, 1192 .agent_disable_reg = AUDIO_TOP_CON5,
1204 .agent_disable_shift = 13, 1193 .agent_disable_shift = 13,
1205 .msb_reg = -1, 1194 .msb_reg = -1,
1206 .msb_shift = -1,
1207 }, 1195 },
1208 { 1196 {
1209 .name = "ULBT", 1197 .name = "ULBT",
@@ -1222,7 +1210,6 @@ static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = {
1222 .agent_disable_reg = AUDIO_TOP_CON5, 1210 .agent_disable_reg = AUDIO_TOP_CON5,
1223 .agent_disable_shift = 16, 1211 .agent_disable_shift = 16,
1224 .msb_reg = -1, 1212 .msb_reg = -1,
1225 .msb_shift = -1,
1226 }, 1213 },
1227}; 1214};
1228 1215
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index bff7d71d0742..08a6532da322 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -401,9 +401,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
401 .hd_reg = AFE_MEMIF_HD_MODE, 401 .hd_reg = AFE_MEMIF_HD_MODE,
402 .hd_shift = DL1_HD_SFT, 402 .hd_shift = DL1_HD_SFT,
403 .agent_disable_reg = -1, 403 .agent_disable_reg = -1,
404 .agent_disable_shift = -1,
405 .msb_reg = -1, 404 .msb_reg = -1,
406 .msb_shift = -1,
407 }, 405 },
408 [MT6797_MEMIF_DL2] = { 406 [MT6797_MEMIF_DL2] = {
409 .name = "DL2", 407 .name = "DL2",
@@ -420,9 +418,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
420 .hd_reg = AFE_MEMIF_HD_MODE, 418 .hd_reg = AFE_MEMIF_HD_MODE,
421 .hd_shift = DL2_HD_SFT, 419 .hd_shift = DL2_HD_SFT,
422 .agent_disable_reg = -1, 420 .agent_disable_reg = -1,
423 .agent_disable_shift = -1,
424 .msb_reg = -1, 421 .msb_reg = -1,
425 .msb_shift = -1,
426 }, 422 },
427 [MT6797_MEMIF_DL3] = { 423 [MT6797_MEMIF_DL3] = {
428 .name = "DL3", 424 .name = "DL3",
@@ -439,9 +435,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
439 .hd_reg = AFE_MEMIF_HD_MODE, 435 .hd_reg = AFE_MEMIF_HD_MODE,
440 .hd_shift = DL3_HD_SFT, 436 .hd_shift = DL3_HD_SFT,
441 .agent_disable_reg = -1, 437 .agent_disable_reg = -1,
442 .agent_disable_shift = -1,
443 .msb_reg = -1, 438 .msb_reg = -1,
444 .msb_shift = -1,
445 }, 439 },
446 [MT6797_MEMIF_VUL] = { 440 [MT6797_MEMIF_VUL] = {
447 .name = "VUL", 441 .name = "VUL",
@@ -458,9 +452,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
458 .hd_reg = AFE_MEMIF_HD_MODE, 452 .hd_reg = AFE_MEMIF_HD_MODE,
459 .hd_shift = VUL_HD_SFT, 453 .hd_shift = VUL_HD_SFT,
460 .agent_disable_reg = -1, 454 .agent_disable_reg = -1,
461 .agent_disable_shift = -1,
462 .msb_reg = -1, 455 .msb_reg = -1,
463 .msb_shift = -1,
464 }, 456 },
465 [MT6797_MEMIF_AWB] = { 457 [MT6797_MEMIF_AWB] = {
466 .name = "AWB", 458 .name = "AWB",
@@ -477,9 +469,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
477 .hd_reg = AFE_MEMIF_HD_MODE, 469 .hd_reg = AFE_MEMIF_HD_MODE,
478 .hd_shift = AWB_HD_SFT, 470 .hd_shift = AWB_HD_SFT,
479 .agent_disable_reg = -1, 471 .agent_disable_reg = -1,
480 .agent_disable_shift = -1,
481 .msb_reg = -1, 472 .msb_reg = -1,
482 .msb_shift = -1,
483 }, 473 },
484 [MT6797_MEMIF_VUL12] = { 474 [MT6797_MEMIF_VUL12] = {
485 .name = "VUL12", 475 .name = "VUL12",
@@ -496,9 +486,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
496 .hd_reg = AFE_MEMIF_HD_MODE, 486 .hd_reg = AFE_MEMIF_HD_MODE,
497 .hd_shift = VUL_DATA2_HD_SFT, 487 .hd_shift = VUL_DATA2_HD_SFT,
498 .agent_disable_reg = -1, 488 .agent_disable_reg = -1,
499 .agent_disable_shift = -1,
500 .msb_reg = -1, 489 .msb_reg = -1,
501 .msb_shift = -1,
502 }, 490 },
503 [MT6797_MEMIF_DAI] = { 491 [MT6797_MEMIF_DAI] = {
504 .name = "DAI", 492 .name = "DAI",
@@ -515,9 +503,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
515 .hd_reg = AFE_MEMIF_HD_MODE, 503 .hd_reg = AFE_MEMIF_HD_MODE,
516 .hd_shift = DAI_HD_SFT, 504 .hd_shift = DAI_HD_SFT,
517 .agent_disable_reg = -1, 505 .agent_disable_reg = -1,
518 .agent_disable_shift = -1,
519 .msb_reg = -1, 506 .msb_reg = -1,
520 .msb_shift = -1,
521 }, 507 },
522 [MT6797_MEMIF_MOD_DAI] = { 508 [MT6797_MEMIF_MOD_DAI] = {
523 .name = "MOD_DAI", 509 .name = "MOD_DAI",
@@ -534,9 +520,7 @@ static const struct mtk_base_memif_data memif_data[MT6797_MEMIF_NUM] = {
534 .hd_reg = AFE_MEMIF_HD_MODE, 520 .hd_reg = AFE_MEMIF_HD_MODE,
535 .hd_shift = MOD_DAI_HD_SFT, 521 .hd_shift = MOD_DAI_HD_SFT,
536 .agent_disable_reg = -1, 522 .agent_disable_reg = -1,
537 .agent_disable_shift = -1,
538 .msb_reg = -1, 523 .msb_reg = -1,
539 .msb_shift = -1,
540 }, 524 },
541}; 525};
542 526
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 166aed28330d..0382896c162e 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -714,13 +714,11 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
714 .mono_reg = AFE_DAC_CON1, 714 .mono_reg = AFE_DAC_CON1,
715 .mono_shift = 21, 715 .mono_shift = 21,
716 .hd_reg = -1, 716 .hd_reg = -1,
717 .hd_shift = -1,
718 .enable_reg = AFE_DAC_CON0, 717 .enable_reg = AFE_DAC_CON0,
719 .enable_shift = 1, 718 .enable_shift = 1,
720 .msb_reg = AFE_MEMIF_MSB, 719 .msb_reg = AFE_MEMIF_MSB,
721 .msb_shift = 0, 720 .msb_shift = 0,
722 .agent_disable_reg = -1, 721 .agent_disable_reg = -1,
723 .agent_disable_shift = -1,
724 }, { 722 }, {
725 .name = "DL2", 723 .name = "DL2",
726 .id = MT8173_AFE_MEMIF_DL2, 724 .id = MT8173_AFE_MEMIF_DL2,
@@ -732,13 +730,11 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
732 .mono_reg = AFE_DAC_CON1, 730 .mono_reg = AFE_DAC_CON1,
733 .mono_shift = 22, 731 .mono_shift = 22,
734 .hd_reg = -1, 732 .hd_reg = -1,
735 .hd_shift = -1,
736 .enable_reg = AFE_DAC_CON0, 733 .enable_reg = AFE_DAC_CON0,
737 .enable_shift = 2, 734 .enable_shift = 2,
738 .msb_reg = AFE_MEMIF_MSB, 735 .msb_reg = AFE_MEMIF_MSB,
739 .msb_shift = 1, 736 .msb_shift = 1,
740 .agent_disable_reg = -1, 737 .agent_disable_reg = -1,
741 .agent_disable_shift = -1,
742 }, { 738 }, {
743 .name = "VUL", 739 .name = "VUL",
744 .id = MT8173_AFE_MEMIF_VUL, 740 .id = MT8173_AFE_MEMIF_VUL,
@@ -750,13 +746,11 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
750 .mono_reg = AFE_DAC_CON1, 746 .mono_reg = AFE_DAC_CON1,
751 .mono_shift = 27, 747 .mono_shift = 27,
752 .hd_reg = -1, 748 .hd_reg = -1,
753 .hd_shift = -1,
754 .enable_reg = AFE_DAC_CON0, 749 .enable_reg = AFE_DAC_CON0,
755 .enable_shift = 3, 750 .enable_shift = 3,
756 .msb_reg = AFE_MEMIF_MSB, 751 .msb_reg = AFE_MEMIF_MSB,
757 .msb_shift = 6, 752 .msb_shift = 6,
758 .agent_disable_reg = -1, 753 .agent_disable_reg = -1,
759 .agent_disable_shift = -1,
760 }, { 754 }, {
761 .name = "DAI", 755 .name = "DAI",
762 .id = MT8173_AFE_MEMIF_DAI, 756 .id = MT8173_AFE_MEMIF_DAI,
@@ -768,13 +762,11 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
768 .mono_reg = -1, 762 .mono_reg = -1,
769 .mono_shift = -1, 763 .mono_shift = -1,
770 .hd_reg = -1, 764 .hd_reg = -1,
771 .hd_shift = -1,
772 .enable_reg = AFE_DAC_CON0, 765 .enable_reg = AFE_DAC_CON0,
773 .enable_shift = 4, 766 .enable_shift = 4,
774 .msb_reg = AFE_MEMIF_MSB, 767 .msb_reg = AFE_MEMIF_MSB,
775 .msb_shift = 5, 768 .msb_shift = 5,
776 .agent_disable_reg = -1, 769 .agent_disable_reg = -1,
777 .agent_disable_shift = -1,
778 }, { 770 }, {
779 .name = "AWB", 771 .name = "AWB",
780 .id = MT8173_AFE_MEMIF_AWB, 772 .id = MT8173_AFE_MEMIF_AWB,
@@ -786,13 +778,11 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
786 .mono_reg = AFE_DAC_CON1, 778 .mono_reg = AFE_DAC_CON1,
787 .mono_shift = 24, 779 .mono_shift = 24,
788 .hd_reg = -1, 780 .hd_reg = -1,
789 .hd_shift = -1,
790 .enable_reg = AFE_DAC_CON0, 781 .enable_reg = AFE_DAC_CON0,
791 .enable_shift = 6, 782 .enable_shift = 6,
792 .msb_reg = AFE_MEMIF_MSB, 783 .msb_reg = AFE_MEMIF_MSB,
793 .msb_shift = 3, 784 .msb_shift = 3,
794 .agent_disable_reg = -1, 785 .agent_disable_reg = -1,
795 .agent_disable_shift = -1,
796 }, { 786 }, {
797 .name = "MOD_DAI", 787 .name = "MOD_DAI",
798 .id = MT8173_AFE_MEMIF_MOD_DAI, 788 .id = MT8173_AFE_MEMIF_MOD_DAI,
@@ -804,13 +794,11 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
804 .mono_reg = AFE_DAC_CON1, 794 .mono_reg = AFE_DAC_CON1,
805 .mono_shift = 30, 795 .mono_shift = 30,
806 .hd_reg = -1, 796 .hd_reg = -1,
807 .hd_shift = -1,
808 .enable_reg = AFE_DAC_CON0, 797 .enable_reg = AFE_DAC_CON0,
809 .enable_shift = 7, 798 .enable_shift = 7,
810 .msb_reg = AFE_MEMIF_MSB, 799 .msb_reg = AFE_MEMIF_MSB,
811 .msb_shift = 4, 800 .msb_shift = 4,
812 .agent_disable_reg = -1, 801 .agent_disable_reg = -1,
813 .agent_disable_shift = -1,
814 }, { 802 }, {
815 .name = "HDMI", 803 .name = "HDMI",
816 .id = MT8173_AFE_MEMIF_HDMI, 804 .id = MT8173_AFE_MEMIF_HDMI,
@@ -822,13 +810,10 @@ static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
822 .mono_reg = -1, 810 .mono_reg = -1,
823 .mono_shift = -1, 811 .mono_shift = -1,
824 .hd_reg = -1, 812 .hd_reg = -1,
825 .hd_shift = -1,
826 .enable_reg = -1, 813 .enable_reg = -1,
827 .enable_shift = -1,
828 .msb_reg = AFE_MEMIF_MSB, 814 .msb_reg = AFE_MEMIF_MSB,
829 .msb_shift = 8, 815 .msb_shift = 8,
830 .agent_disable_reg = -1, 816 .agent_disable_reg = -1,
831 .agent_disable_shift = -1,
832 }, 817 },
833}; 818};
834 819
@@ -914,7 +899,6 @@ static const struct mtk_base_irq_data irq_data[MT8173_AFE_IRQ_NUM] = {
914 .irq_en_reg = AFE_IRQ_MCU_CON, 899 .irq_en_reg = AFE_IRQ_MCU_CON,
915 .irq_en_shift = 12, 900 .irq_en_shift = 12,
916 .irq_fs_reg = -1, 901 .irq_fs_reg = -1,
917 .irq_fs_shift = -1,
918 .irq_fs_maskbit = -1, 902 .irq_fs_maskbit = -1,
919 .irq_clr_reg = AFE_IRQ_CLR, 903 .irq_clr_reg = AFE_IRQ_CLR,
920 .irq_clr_shift = 4, 904 .irq_clr_shift = 4,
diff --git a/sound/soc/mediatek/mt8183/Makefile b/sound/soc/mediatek/mt8183/Makefile
index f3ee6ac98fe8..c0a3bbc2c1f6 100644
--- a/sound/soc/mediatek/mt8183/Makefile
+++ b/sound/soc/mediatek/mt8183/Makefile
@@ -11,3 +11,5 @@ snd-soc-mt8183-afe-objs := \
11 mt8183-dai-adda.o 11 mt8183-dai-adda.o
12 12
13obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o 13obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o
14obj-$(CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A) += mt8183-mt6358-ts3a227-max98357.o
15obj-$(CONFIG_SND_SOC_MT8183_DA7219_MAX98357A) += mt8183-da7219-max98357.o
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
index 4e045dd305a7..1bc0fafe5e29 100644
--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
@@ -291,11 +291,15 @@ static struct snd_soc_dai_driver mt8183_memif_dai_driver[] = {
291static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = { 291static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
292 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21, 292 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21,
293 I_ADDA_UL_CH1, 1, 0), 293 I_ADDA_UL_CH1, 1, 0),
294 SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN21,
295 I_I2S0_CH1, 1, 0),
294}; 296};
295 297
296static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = { 298static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
297 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22, 299 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22,
298 I_ADDA_UL_CH2, 1, 0), 300 I_ADDA_UL_CH2, 1, 0),
301 SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN21,
302 I_I2S0_CH2, 1, 0),
299}; 303};
300 304
301static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = { 305static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
@@ -307,6 +311,8 @@ static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
307 I_DL2_CH1, 1, 0), 311 I_DL2_CH1, 1, 0),
308 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5, 312 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5,
309 I_DL3_CH1, 1, 0), 313 I_DL3_CH1, 1, 0),
314 SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN5,
315 I_I2S2_CH1, 1, 0),
310}; 316};
311 317
312static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = { 318static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
@@ -318,16 +324,22 @@ static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
318 I_DL2_CH2, 1, 0), 324 I_DL2_CH2, 1, 0),
319 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6, 325 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6,
320 I_DL3_CH2, 1, 0), 326 I_DL3_CH2, 1, 0),
327 SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN6,
328 I_I2S2_CH2, 1, 0),
321}; 329};
322 330
323static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = { 331static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
324 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN32, 332 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN32,
325 I_ADDA_UL_CH1, 1, 0), 333 I_ADDA_UL_CH1, 1, 0),
334 SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN32,
335 I_I2S2_CH1, 1, 0),
326}; 336};
327 337
328static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = { 338static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
329 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN33, 339 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN33,
330 I_ADDA_UL_CH2, 1, 0), 340 I_ADDA_UL_CH2, 1, 0),
341 SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN33,
342 I_I2S2_CH2, 1, 0),
331}; 343};
332 344
333static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = { 345static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = {
@@ -380,16 +392,22 @@ static const struct snd_soc_dapm_route mt8183_memif_routes[] = {
380 {"UL1", NULL, "UL1_CH2"}, 392 {"UL1", NULL, "UL1_CH2"},
381 {"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"}, 393 {"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"},
382 {"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"}, 394 {"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"},
395 {"UL1_CH1", "I2S0_CH1", "I2S0"},
396 {"UL1_CH2", "I2S0_CH2", "I2S0"},
383 397
384 {"UL2", NULL, "UL2_CH1"}, 398 {"UL2", NULL, "UL2_CH1"},
385 {"UL2", NULL, "UL2_CH2"}, 399 {"UL2", NULL, "UL2_CH2"},
386 {"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"}, 400 {"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"},
387 {"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"}, 401 {"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"},
402 {"UL2_CH1", "I2S2_CH1", "I2S2"},
403 {"UL2_CH2", "I2S2_CH2", "I2S2"},
388 404
389 {"UL3", NULL, "UL3_CH1"}, 405 {"UL3", NULL, "UL3_CH1"},
390 {"UL3", NULL, "UL3_CH2"}, 406 {"UL3", NULL, "UL3_CH2"},
391 {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"}, 407 {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"},
392 {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"}, 408 {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"},
409 {"UL3_CH1", "I2S2_CH1", "I2S2"},
410 {"UL3_CH2", "I2S2_CH2", "I2S2"},
393 411
394 {"UL4", NULL, "UL4_CH1"}, 412 {"UL4", NULL, "UL4_CH1"},
395 {"UL4", NULL, "UL4_CH2"}, 413 {"UL4", NULL, "UL4_CH2"},
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
new file mode 100644
index 000000000000..31ea8632c397
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -0,0 +1,471 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// mt8183-da7219-max98357.c
4// -- MT8183-DA7219-MAX98357 ALSA SoC machine driver
5//
6// Copyright (c) 2018 MediaTek Inc.
7// Author: Shunli Wang <shunli.wang@mediatek.com>
8
9#include <linux/module.h>
10#include <sound/pcm_params.h>
11#include <sound/soc.h>
12#include <sound/jack.h>
13#include <linux/pinctrl/consumer.h>
14
15#include "mt8183-afe-common.h"
16#include "../../codecs/da7219-aad.h"
17#include "../../codecs/da7219.h"
18
19static struct snd_soc_jack headset_jack;
20
21/* Headset jack detection DAPM pins */
22static struct snd_soc_jack_pin headset_jack_pins[] = {
23 {
24 .pin = "Headphone",
25 .mask = SND_JACK_HEADPHONE,
26 },
27 {
28 .pin = "Headset Mic",
29 .mask = SND_JACK_MICROPHONE,
30 },
31};
32
33static struct snd_soc_dai_link_component
34mt8183_da7219_max98357_external_codecs[] = {
35 {
36 .name = "max98357a",
37 .dai_name = "HiFi",
38 },
39 {
40 .name = "da7219.5-001a",
41 .dai_name = "da7219-hifi",
42 },
43};
44
45static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
46 struct snd_pcm_hw_params *params)
47{
48 struct snd_soc_pcm_runtime *rtd = substream->private_data;
49 unsigned int rate = params_rate(params);
50 unsigned int mclk_fs_ratio = 128;
51 unsigned int mclk_fs = rate * mclk_fs_ratio;
52
53 return snd_soc_dai_set_sysclk(rtd->cpu_dai,
54 0, mclk_fs, SND_SOC_CLOCK_OUT);
55}
56
57static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
58 .hw_params = mt8183_mt6358_i2s_hw_params,
59};
60
61static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
62 struct snd_pcm_hw_params *params)
63{
64 struct snd_soc_pcm_runtime *rtd = substream->private_data;
65 unsigned int rate = params_rate(params);
66 unsigned int mclk_fs_ratio = 256;
67 unsigned int mclk_fs = rate * mclk_fs_ratio;
68 unsigned int freq;
69 int ret = 0, j;
70
71 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0,
72 mclk_fs, SND_SOC_CLOCK_OUT);
73 if (ret < 0)
74 dev_err(rtd->dev, "failed to set cpu dai sysclk\n");
75
76 for (j = 0; j < rtd->num_codecs; j++) {
77 struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
78
79 if (!strcmp(codec_dai->component->name, "da7219.5-001a")) {
80 ret = snd_soc_dai_set_sysclk(codec_dai,
81 DA7219_CLKSRC_MCLK,
82 mclk_fs,
83 SND_SOC_CLOCK_IN);
84 if (ret < 0)
85 dev_err(rtd->dev, "failed to set sysclk\n");
86
87 if ((rate % 8000) == 0)
88 freq = DA7219_PLL_FREQ_OUT_98304;
89 else
90 freq = DA7219_PLL_FREQ_OUT_90316;
91
92 ret = snd_soc_dai_set_pll(codec_dai, 0,
93 DA7219_SYSCLK_PLL_SRM,
94 0, freq);
95 if (ret)
96 dev_err(rtd->dev, "failed to start PLL: %d\n",
97 ret);
98 }
99 }
100
101 return ret;
102}
103
104static int mt8183_da7219_hw_free(struct snd_pcm_substream *substream)
105{
106 struct snd_soc_pcm_runtime *rtd = substream->private_data;
107 int ret = 0, j;
108
109 for (j = 0; j < rtd->num_codecs; j++) {
110 struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
111
112 if (!strcmp(codec_dai->component->name, "da7219.5-001a")) {
113 ret = snd_soc_dai_set_pll(codec_dai,
114 0, DA7219_SYSCLK_MCLK, 0, 0);
115 if (ret < 0) {
116 dev_err(rtd->dev, "failed to stop PLL: %d\n",
117 ret);
118 break;
119 }
120 }
121 }
122
123 return ret;
124}
125
126static const struct snd_soc_ops mt8183_da7219_i2s_ops = {
127 .hw_params = mt8183_da7219_i2s_hw_params,
128 .hw_free = mt8183_da7219_hw_free,
129};
130
131static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
132 struct snd_pcm_hw_params *params)
133{
134 /* fix BE i2s format to 32bit, clean param mask first */
135 snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
136 0, SNDRV_PCM_FORMAT_LAST);
137
138 params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
139
140 return 0;
141}
142
143static const struct snd_soc_dapm_widget
144mt8183_da7219_max98357_dapm_widgets[] = {
145 SND_SOC_DAPM_OUTPUT("IT6505_8CH"),
146};
147
148static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = {
149 {"IT6505_8CH", NULL, "TDM"},
150};
151
152static struct snd_soc_dai_link mt8183_da7219_max98357_dai_links[] = {
153 /* FE */
154 {
155 .name = "Playback_1",
156 .stream_name = "Playback_1",
157 .cpu_dai_name = "DL1",
158 .codec_name = "snd-soc-dummy",
159 .codec_dai_name = "snd-soc-dummy-dai",
160 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
161 SND_SOC_DPCM_TRIGGER_PRE},
162 .dynamic = 1,
163 .dpcm_playback = 1,
164 },
165 {
166 .name = "Playback_2",
167 .stream_name = "Playback_2",
168 .cpu_dai_name = "DL2",
169 .codec_name = "snd-soc-dummy",
170 .codec_dai_name = "snd-soc-dummy-dai",
171 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
172 SND_SOC_DPCM_TRIGGER_PRE},
173 .dynamic = 1,
174 .dpcm_playback = 1,
175 },
176 {
177 .name = "Playback_3",
178 .stream_name = "Playback_3",
179 .cpu_dai_name = "DL3",
180 .codec_name = "snd-soc-dummy",
181 .codec_dai_name = "snd-soc-dummy-dai",
182 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
183 SND_SOC_DPCM_TRIGGER_PRE},
184 .dynamic = 1,
185 .dpcm_playback = 1,
186 },
187 {
188 .name = "Capture_1",
189 .stream_name = "Capture_1",
190 .cpu_dai_name = "UL1",
191 .codec_name = "snd-soc-dummy",
192 .codec_dai_name = "snd-soc-dummy-dai",
193 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
194 SND_SOC_DPCM_TRIGGER_PRE},
195 .dynamic = 1,
196 .dpcm_capture = 1,
197 },
198 {
199 .name = "Capture_2",
200 .stream_name = "Capture_2",
201 .cpu_dai_name = "UL2",
202 .codec_name = "snd-soc-dummy",
203 .codec_dai_name = "snd-soc-dummy-dai",
204 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
205 SND_SOC_DPCM_TRIGGER_PRE},
206 .dynamic = 1,
207 .dpcm_capture = 1,
208 },
209 {
210 .name = "Capture_3",
211 .stream_name = "Capture_3",
212 .cpu_dai_name = "UL3",
213 .codec_name = "snd-soc-dummy",
214 .codec_dai_name = "snd-soc-dummy-dai",
215 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
216 SND_SOC_DPCM_TRIGGER_PRE},
217 .dynamic = 1,
218 .dpcm_capture = 1,
219 },
220 {
221 .name = "Capture_Mono_1",
222 .stream_name = "Capture_Mono_1",
223 .cpu_dai_name = "UL_MONO_1",
224 .codec_name = "snd-soc-dummy",
225 .codec_dai_name = "snd-soc-dummy-dai",
226 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
227 SND_SOC_DPCM_TRIGGER_PRE},
228 .dynamic = 1,
229 .dpcm_capture = 1,
230 },
231 {
232 .name = "Playback_HDMI",
233 .stream_name = "Playback_HDMI",
234 .cpu_dai_name = "HDMI",
235 .codec_name = "snd-soc-dummy",
236 .codec_dai_name = "snd-soc-dummy-dai",
237 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
238 SND_SOC_DPCM_TRIGGER_PRE},
239 .dynamic = 1,
240 .dpcm_playback = 1,
241 },
242 /* BE */
243 {
244 .name = "Primary Codec",
245 .cpu_dai_name = "ADDA",
246 .codec_dai_name = "mt6358-snd-codec-aif1",
247 .codec_name = "mt6358-sound",
248 .no_pcm = 1,
249 .dpcm_playback = 1,
250 .dpcm_capture = 1,
251 .ignore_suspend = 1,
252 },
253 {
254 .name = "PCM 1",
255 .cpu_dai_name = "PCM 1",
256 .codec_name = "snd-soc-dummy",
257 .codec_dai_name = "snd-soc-dummy-dai",
258 .no_pcm = 1,
259 .dpcm_playback = 1,
260 .dpcm_capture = 1,
261 .ignore_suspend = 1,
262 },
263 {
264 .name = "PCM 2",
265 .cpu_dai_name = "PCM 2",
266 .codec_name = "snd-soc-dummy",
267 .codec_dai_name = "snd-soc-dummy-dai",
268 .no_pcm = 1,
269 .dpcm_playback = 1,
270 .dpcm_capture = 1,
271 .ignore_suspend = 1,
272 },
273 {
274 .name = "I2S0",
275 .cpu_dai_name = "I2S0",
276 .codec_dai_name = "bt-sco-pcm",
277 .codec_name = "bt-sco",
278 .no_pcm = 1,
279 .dpcm_capture = 1,
280 .ignore_suspend = 1,
281 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
282 .ops = &mt8183_mt6358_i2s_ops,
283 },
284 {
285 .name = "I2S1",
286 .cpu_dai_name = "I2S1",
287 .codec_dai_name = "snd-soc-dummy-dai",
288 .codec_name = "snd-soc-dummy",
289 .no_pcm = 1,
290 .dpcm_playback = 1,
291 .ignore_suspend = 1,
292 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
293 .ops = &mt8183_mt6358_i2s_ops,
294 },
295 {
296 .name = "I2S2",
297 .cpu_dai_name = "I2S2",
298 .codec_dai_name = "da7219-hifi",
299 .codec_name = "da7219.5-001a",
300 .no_pcm = 1,
301 .dpcm_capture = 1,
302 .ignore_suspend = 1,
303 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
304 .ops = &mt8183_da7219_i2s_ops,
305 },
306 {
307 .name = "I2S3",
308 .cpu_dai_name = "I2S3",
309 .codecs = mt8183_da7219_max98357_external_codecs,
310 .num_codecs =
311 ARRAY_SIZE(mt8183_da7219_max98357_external_codecs),
312 .no_pcm = 1,
313 .dpcm_playback = 1,
314 .ignore_suspend = 1,
315 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
316 .ops = &mt8183_da7219_i2s_ops,
317 },
318 {
319 .name = "I2S5",
320 .cpu_dai_name = "I2S5",
321 .codec_dai_name = "bt-sco-pcm",
322 .codec_name = "bt-sco",
323 .no_pcm = 1,
324 .dpcm_playback = 1,
325 .ignore_suspend = 1,
326 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
327 .ops = &mt8183_mt6358_i2s_ops,
328 },
329 {
330 .name = "TDM",
331 .cpu_dai_name = "TDM",
332 .codec_name = "snd-soc-dummy",
333 .codec_dai_name = "snd-soc-dummy-dai",
334 .no_pcm = 1,
335 .dpcm_playback = 1,
336 .ignore_suspend = 1,
337 },
338};
339
340static int
341mt8183_da7219_max98357_headset_init(struct snd_soc_component *component);
342
343static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = {
344 .name = "Headset Chip",
345 .init = mt8183_da7219_max98357_headset_init,
346};
347
348static struct snd_soc_codec_conf mt6358_codec_conf[] = {
349 {
350 .dev_name = "mt6358-sound",
351 .name_prefix = "Mt6358",
352 },
353};
354
355static struct snd_soc_card mt8183_da7219_max98357_card = {
356 .name = "mt8183_da7219_max98357",
357 .owner = THIS_MODULE,
358 .dai_link = mt8183_da7219_max98357_dai_links,
359 .num_links = ARRAY_SIZE(mt8183_da7219_max98357_dai_links),
360 .aux_dev = &mt8183_da7219_max98357_headset_dev,
361 .num_aux_devs = 1,
362 .codec_conf = mt6358_codec_conf,
363 .num_configs = ARRAY_SIZE(mt6358_codec_conf),
364};
365
366static int
367mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
368{
369 int ret;
370
371 /* Enable Headset and 4 Buttons Jack detection */
372 ret = snd_soc_card_jack_new(&mt8183_da7219_max98357_card,
373 "Headset Jack",
374 SND_JACK_HEADSET |
375 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
376 SND_JACK_BTN_2 | SND_JACK_BTN_3,
377 &headset_jack,
378 headset_jack_pins,
379 ARRAY_SIZE(headset_jack_pins));
380 if (ret)
381 return ret;
382
383 da7219_aad_jack_det(component, &headset_jack);
384
385 return ret;
386}
387
388static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev)
389{
390 struct snd_soc_card *card = &mt8183_da7219_max98357_card;
391 struct device_node *platform_node;
392 struct snd_soc_dai_link *dai_link;
393 struct pinctrl *default_pins;
394 int ret, i;
395
396 card->dev = &pdev->dev;
397
398 platform_node = of_parse_phandle(pdev->dev.of_node,
399 "mediatek,platform", 0);
400 if (!platform_node) {
401 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
402 return -EINVAL;
403 }
404
405 for_each_card_prelinks(card, i, dai_link) {
406 /* In the alsa soc-core, the "platform" will be
407 * allocated by devm_kzalloc if null.
408 * There is a special case that registerring
409 * sound card is failed at the first time, but
410 * the "platform" will not null when probe is trying
411 * again. It's not expected normally.
412 */
413 dai_link->platforms = NULL;
414
415 if (dai_link->platform_name)
416 continue;
417 dai_link->platform_of_node = platform_node;
418 }
419
420 mt8183_da7219_max98357_headset_dev.codec_of_node =
421 of_parse_phandle(pdev->dev.of_node,
422 "mediatek,headset-codec", 0);
423 if (!mt8183_da7219_max98357_headset_dev.codec_of_node) {
424 dev_err(&pdev->dev,
425 "Property 'mediatek,headset-codec' missing/invalid\n");
426 return -EINVAL;
427 }
428
429 ret = devm_snd_soc_register_card(&pdev->dev, card);
430 if (ret) {
431 dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
432 __func__, ret);
433 return ret;
434 }
435
436 default_pins =
437 devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT);
438 if (IS_ERR(default_pins)) {
439 dev_err(&pdev->dev, "%s set pins failed\n",
440 __func__);
441 return PTR_ERR(default_pins);
442 }
443
444 return ret;
445}
446
447#ifdef CONFIG_OF
448static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
449 {.compatible = "mediatek,mt8183_da7219_max98357",},
450 {}
451};
452#endif
453
454static struct platform_driver mt8183_da7219_max98357_driver = {
455 .driver = {
456 .name = "mt8183_da7219_max98357",
457#ifdef CONFIG_OF
458 .of_match_table = mt8183_da7219_max98357_dt_match,
459#endif
460 },
461 .probe = mt8183_da7219_max98357_dev_probe,
462};
463
464module_platform_driver(mt8183_da7219_max98357_driver);
465
466/* Module information */
467MODULE_DESCRIPTION("MT8183-DA7219-MAX98357 ALSA SoC machine driver");
468MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
469MODULE_LICENSE("GPL v2");
470MODULE_ALIAS("mt8183_da7219_max98357 soc card");
471
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
new file mode 100644
index 000000000000..4e44e5689d6f
--- /dev/null
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -0,0 +1,423 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// mt8183-mt6358.c --
4// MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver
5//
6// Copyright (c) 2018 MediaTek Inc.
7// Author: Shunli Wang <shunli.wang@mediatek.com>
8
9#include <linux/module.h>
10#include <sound/pcm_params.h>
11#include <sound/soc.h>
12#include <sound/jack.h>
13#include <linux/pinctrl/consumer.h>
14
15#include "mt8183-afe-common.h"
16#include "../../codecs/ts3a227e.h"
17
18static struct snd_soc_jack headset_jack;
19
20/* Headset jack detection DAPM pins */
21static struct snd_soc_jack_pin headset_jack_pins[] = {
22 {
23 .pin = "Headphone",
24 .mask = SND_JACK_HEADPHONE,
25 },
26 {
27 .pin = "Headset Mic",
28 .mask = SND_JACK_MICROPHONE,
29 },
30
31};
32
33static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
34 struct snd_pcm_hw_params *params)
35{
36 struct snd_soc_pcm_runtime *rtd = substream->private_data;
37 unsigned int rate = params_rate(params);
38 unsigned int mclk_fs_ratio = 128;
39 unsigned int mclk_fs = rate * mclk_fs_ratio;
40
41 return snd_soc_dai_set_sysclk(rtd->cpu_dai,
42 0, mclk_fs, SND_SOC_CLOCK_OUT);
43}
44
45static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
46 .hw_params = mt8183_mt6358_i2s_hw_params,
47};
48
49static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
50 struct snd_pcm_hw_params *params)
51{
52 dev_dbg(rtd->dev, "%s(), fix format to 32bit\n", __func__);
53
54 /* fix BE i2s format to 32bit, clean param mask first */
55 snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
56 0, SNDRV_PCM_FORMAT_LAST);
57
58 params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
59 return 0;
60}
61
62static const struct snd_soc_dapm_widget
63mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = {
64 SND_SOC_DAPM_OUTPUT("IT6505_8CH"),
65};
66
67static const struct snd_soc_dapm_route
68mt8183_mt6358_ts3a227_max98357_dapm_routes[] = {
69 {"IT6505_8CH", NULL, "TDM"},
70};
71
72static int
73mt8183_mt6358_ts3a227_max98357_bt_sco_startup(
74 struct snd_pcm_substream *substream)
75{
76 static const unsigned int rates[] = {
77 8000, 16000
78 };
79 static const struct snd_pcm_hw_constraint_list constraints_rates = {
80 .count = ARRAY_SIZE(rates),
81 .list = rates,
82 .mask = 0,
83 };
84 static const unsigned int channels[] = {
85 1,
86 };
87 static const struct snd_pcm_hw_constraint_list constraints_channels = {
88 .count = ARRAY_SIZE(channels),
89 .list = channels,
90 .mask = 0,
91 };
92
93 struct snd_pcm_runtime *runtime = substream->runtime;
94
95 snd_pcm_hw_constraint_list(runtime, 0,
96 SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
97 runtime->hw.channels_max = 1;
98 snd_pcm_hw_constraint_list(runtime, 0,
99 SNDRV_PCM_HW_PARAM_CHANNELS,
100 &constraints_channels);
101
102 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
103 snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
104
105 return 0;
106}
107
108static const struct snd_soc_ops mt8183_mt6358_ts3a227_max98357_bt_sco_ops = {
109 .startup = mt8183_mt6358_ts3a227_max98357_bt_sco_startup,
110};
111
112static struct snd_soc_dai_link
113mt8183_mt6358_ts3a227_max98357_dai_links[] = {
114 /* FE */
115 {
116 .name = "Playback_1",
117 .stream_name = "Playback_1",
118 .cpu_dai_name = "DL1",
119 .codec_name = "snd-soc-dummy",
120 .codec_dai_name = "snd-soc-dummy-dai",
121 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
122 SND_SOC_DPCM_TRIGGER_PRE},
123 .dynamic = 1,
124 .dpcm_playback = 1,
125 },
126 {
127 .name = "Playback_2",
128 .stream_name = "Playback_2",
129 .cpu_dai_name = "DL2",
130 .codec_name = "snd-soc-dummy",
131 .codec_dai_name = "snd-soc-dummy-dai",
132 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
133 SND_SOC_DPCM_TRIGGER_PRE},
134 .dynamic = 1,
135 .dpcm_playback = 1,
136 .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops,
137 },
138 {
139 .name = "Playback_3",
140 .stream_name = "Playback_3",
141 .cpu_dai_name = "DL3",
142 .codec_name = "snd-soc-dummy",
143 .codec_dai_name = "snd-soc-dummy-dai",
144 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
145 SND_SOC_DPCM_TRIGGER_PRE},
146 .dynamic = 1,
147 .dpcm_playback = 1,
148 },
149 {
150 .name = "Capture_1",
151 .stream_name = "Capture_1",
152 .cpu_dai_name = "UL1",
153 .codec_name = "snd-soc-dummy",
154 .codec_dai_name = "snd-soc-dummy-dai",
155 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
156 SND_SOC_DPCM_TRIGGER_PRE},
157 .dynamic = 1,
158 .dpcm_capture = 1,
159 .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops,
160 },
161 {
162 .name = "Capture_2",
163 .stream_name = "Capture_2",
164 .cpu_dai_name = "UL2",
165 .codec_name = "snd-soc-dummy",
166 .codec_dai_name = "snd-soc-dummy-dai",
167 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
168 SND_SOC_DPCM_TRIGGER_PRE},
169 .dynamic = 1,
170 .dpcm_capture = 1,
171 },
172 {
173 .name = "Capture_3",
174 .stream_name = "Capture_3",
175 .cpu_dai_name = "UL3",
176 .codec_name = "snd-soc-dummy",
177 .codec_dai_name = "snd-soc-dummy-dai",
178 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
179 SND_SOC_DPCM_TRIGGER_PRE},
180 .dynamic = 1,
181 .dpcm_capture = 1,
182 },
183 {
184 .name = "Capture_Mono_1",
185 .stream_name = "Capture_Mono_1",
186 .cpu_dai_name = "UL_MONO_1",
187 .codec_name = "snd-soc-dummy",
188 .codec_dai_name = "snd-soc-dummy-dai",
189 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
190 SND_SOC_DPCM_TRIGGER_PRE},
191 .dynamic = 1,
192 .dpcm_capture = 1,
193 },
194 {
195 .name = "Playback_HDMI",
196 .stream_name = "Playback_HDMI",
197 .cpu_dai_name = "HDMI",
198 .codec_name = "snd-soc-dummy",
199 .codec_dai_name = "snd-soc-dummy-dai",
200 .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
201 SND_SOC_DPCM_TRIGGER_PRE},
202 .dynamic = 1,
203 .dpcm_playback = 1,
204 },
205 /* BE */
206 {
207 .name = "Primary Codec",
208 .cpu_dai_name = "ADDA",
209 .codec_dai_name = "mt6358-snd-codec-aif1",
210 .codec_name = "mt6358-sound",
211 .no_pcm = 1,
212 .dpcm_playback = 1,
213 .dpcm_capture = 1,
214 .ignore_suspend = 1,
215 },
216 {
217 .name = "PCM 1",
218 .cpu_dai_name = "PCM 1",
219 .codec_name = "snd-soc-dummy",
220 .codec_dai_name = "snd-soc-dummy-dai",
221 .no_pcm = 1,
222 .dpcm_playback = 1,
223 .dpcm_capture = 1,
224 .ignore_suspend = 1,
225 },
226 {
227 .name = "PCM 2",
228 .cpu_dai_name = "PCM 2",
229 .codec_name = "snd-soc-dummy",
230 .codec_dai_name = "snd-soc-dummy-dai",
231 .no_pcm = 1,
232 .dpcm_playback = 1,
233 .dpcm_capture = 1,
234 .ignore_suspend = 1,
235 },
236 {
237 .name = "I2S0",
238 .cpu_dai_name = "I2S0",
239 .codec_dai_name = "bt-sco-pcm",
240 .codec_name = "bt-sco",
241 .no_pcm = 1,
242 .dpcm_capture = 1,
243 .ignore_suspend = 1,
244 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
245 .ops = &mt8183_mt6358_i2s_ops,
246 },
247 {
248 .name = "I2S1",
249 .cpu_dai_name = "I2S1",
250 .codec_dai_name = "snd-soc-dummy-dai",
251 .codec_name = "snd-soc-dummy",
252 .no_pcm = 1,
253 .dpcm_playback = 1,
254 .ignore_suspend = 1,
255 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
256 .ops = &mt8183_mt6358_i2s_ops,
257 },
258 {
259 .name = "I2S2",
260 .cpu_dai_name = "I2S2",
261 .codec_dai_name = "snd-soc-dummy-dai",
262 .codec_name = "snd-soc-dummy",
263 .no_pcm = 1,
264 .dpcm_capture = 1,
265 .ignore_suspend = 1,
266 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
267 .ops = &mt8183_mt6358_i2s_ops,
268 },
269 {
270 .name = "I2S3",
271 .cpu_dai_name = "I2S3",
272 .codec_dai_name = "HiFi",
273 .codec_name = "max98357a",
274 .no_pcm = 1,
275 .dpcm_playback = 1,
276 .ignore_suspend = 1,
277 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
278 .ops = &mt8183_mt6358_i2s_ops,
279 },
280 {
281 .name = "I2S5",
282 .cpu_dai_name = "I2S5",
283 .codec_dai_name = "bt-sco-pcm",
284 .codec_name = "bt-sco",
285 .no_pcm = 1,
286 .dpcm_playback = 1,
287 .ignore_suspend = 1,
288 .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
289 .ops = &mt8183_mt6358_i2s_ops,
290 },
291 {
292 .name = "TDM",
293 .cpu_dai_name = "TDM",
294 .codec_name = "snd-soc-dummy",
295 .codec_dai_name = "snd-soc-dummy-dai",
296 .no_pcm = 1,
297 .dpcm_playback = 1,
298 .ignore_suspend = 1,
299 },
300};
301
302static int
303mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *cpnt);
304
305static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = {
306 .name = "Headset Chip",
307 .init = mt8183_mt6358_ts3a227_max98357_headset_init,
308};
309
310static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = {
311 .name = "mt8183_mt6358_ts3a227_max98357",
312 .owner = THIS_MODULE,
313 .dai_link = mt8183_mt6358_ts3a227_max98357_dai_links,
314 .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dai_links),
315 .aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev,
316 .num_aux_devs = 1,
317};
318
319static int
320mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component)
321{
322 int ret;
323
324 /* Enable Headset and 4 Buttons Jack detection */
325 ret = snd_soc_card_jack_new(&mt8183_mt6358_ts3a227_max98357_card,
326 "Headset Jack",
327 SND_JACK_HEADSET |
328 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
329 SND_JACK_BTN_2 | SND_JACK_BTN_3,
330 &headset_jack,
331 headset_jack_pins,
332 ARRAY_SIZE(headset_jack_pins));
333 if (ret)
334 return ret;
335
336 ret = ts3a227e_enable_jack_detect(component, &headset_jack);
337
338 return ret;
339}
340
341static int
342mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
343{
344 struct snd_soc_card *card = &mt8183_mt6358_ts3a227_max98357_card;
345 struct device_node *platform_node;
346 struct snd_soc_dai_link *dai_link;
347 struct pinctrl *default_pins;
348 int ret, i;
349
350 card->dev = &pdev->dev;
351
352 platform_node = of_parse_phandle(pdev->dev.of_node,
353 "mediatek,platform", 0);
354 if (!platform_node) {
355 dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
356 return -EINVAL;
357 }
358
359 for_each_card_prelinks(card, i, dai_link) {
360 /* In the alsa soc-core, the "platform" will be
361 * allocated by devm_kzalloc if null.
362 * There is a special case that registerring
363 * sound card is failed at the first time, but
364 * the "platform" will not null when probe is trying
365 * again. It's not expected normally.
366 */
367 dai_link->platforms = NULL;
368
369 if (dai_link->platform_name)
370 continue;
371 dai_link->platform_of_node = platform_node;
372 }
373
374 mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node =
375 of_parse_phandle(pdev->dev.of_node,
376 "mediatek,headset-codec", 0);
377 if (!mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node) {
378 dev_err(&pdev->dev,
379 "Property 'mediatek,headset-codec' missing/invalid\n");
380 return -EINVAL;
381 }
382
383 ret = devm_snd_soc_register_card(&pdev->dev, card);
384 if (ret)
385 dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
386 __func__, ret);
387
388 default_pins =
389 devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT);
390 if (IS_ERR(default_pins)) {
391 dev_err(&pdev->dev, "%s set pins failed\n",
392 __func__);
393 return PTR_ERR(default_pins);
394 }
395
396 return ret;
397}
398
399#ifdef CONFIG_OF
400static const struct of_device_id mt8183_mt6358_ts3a227_max98357_dt_match[] = {
401 {.compatible = "mediatek,mt8183_mt6358_ts3a227_max98357",},
402 {}
403};
404#endif
405
406static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = {
407 .driver = {
408 .name = "mt8183_mt6358_ts3a227_max98357",
409#ifdef CONFIG_OF
410 .of_match_table = mt8183_mt6358_ts3a227_max98357_dt_match,
411#endif
412 },
413 .probe = mt8183_mt6358_ts3a227_max98357_dev_probe,
414};
415
416module_platform_driver(mt8183_mt6358_ts3a227_max98357_driver);
417
418/* Module information */
419MODULE_DESCRIPTION("MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver");
420MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
421MODULE_LICENSE("GPL v2");
422MODULE_ALIAS("mt8183_mt6358_ts3a227_max98357 soc card");
423
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
index 75e5e480fda2..01c1c7db2510 100644
--- a/sound/soc/meson/axg-fifo.c
+++ b/sound/soc/meson/axg-fifo.c
@@ -19,7 +19,7 @@
19 * This file implements the platform operations common to the playback and 19 * This file implements the platform operations common to the playback and
20 * capture frontend DAI. The logic behind this two types of fifo is very 20 * capture frontend DAI. The logic behind this two types of fifo is very
21 * similar but some difference exist. 21 * similar but some difference exist.
22 * These differences the respective DAI drivers 22 * These differences are handled in the respective DAI drivers
23 */ 23 */
24 24
25static struct snd_pcm_hardware axg_fifo_hw = { 25static struct snd_pcm_hardware axg_fifo_hw = {
@@ -133,6 +133,23 @@ static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
133 return 0; 133 return 0;
134} 134}
135 135
136static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
137 struct snd_pcm_hw_params *params)
138{
139 struct axg_fifo *fifo = axg_fifo_data(ss);
140 struct snd_pcm_runtime *runtime = ss->runtime;
141 int ret;
142
143 ret = axg_fifo_pcm_hw_params(ss, params);
144 if (ret)
145 return ret;
146
147 /* Set the initial memory address of the DMA */
148 regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr);
149
150 return 0;
151}
152
136static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss) 153static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss)
137{ 154{
138 struct axg_fifo *fifo = axg_fifo_data(ss); 155 struct axg_fifo *fifo = axg_fifo_data(ss);
@@ -262,6 +279,17 @@ const struct snd_pcm_ops axg_fifo_pcm_ops = {
262}; 279};
263EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops); 280EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops);
264 281
282const struct snd_pcm_ops g12a_fifo_pcm_ops = {
283 .open = axg_fifo_pcm_open,
284 .close = axg_fifo_pcm_close,
285 .ioctl = snd_pcm_lib_ioctl,
286 .hw_params = g12a_fifo_pcm_hw_params,
287 .hw_free = axg_fifo_pcm_hw_free,
288 .pointer = axg_fifo_pcm_pointer,
289 .trigger = axg_fifo_pcm_trigger,
290};
291EXPORT_SYMBOL_GPL(g12a_fifo_pcm_ops);
292
265int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) 293int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
266{ 294{
267 struct snd_card *card = rtd->card->snd_card; 295 struct snd_card *card = rtd->card->snd_card;
@@ -278,7 +306,7 @@ static const struct regmap_config axg_fifo_regmap_cfg = {
278 .reg_bits = 32, 306 .reg_bits = 32,
279 .val_bits = 32, 307 .val_bits = 32,
280 .reg_stride = 4, 308 .reg_stride = 4,
281 .max_register = FIFO_STATUS2, 309 .max_register = FIFO_INIT_ADDR,
282}; 310};
283 311
284int axg_fifo_probe(struct platform_device *pdev) 312int axg_fifo_probe(struct platform_device *pdev)
@@ -339,6 +367,6 @@ int axg_fifo_probe(struct platform_device *pdev)
339} 367}
340EXPORT_SYMBOL_GPL(axg_fifo_probe); 368EXPORT_SYMBOL_GPL(axg_fifo_probe);
341 369
342MODULE_DESCRIPTION("Amlogic AXG fifo driver"); 370MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver");
343MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 371MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
344MODULE_LICENSE("GPL v2"); 372MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
index d9f516cfbeda..5caf81241dfe 100644
--- a/sound/soc/meson/axg-fifo.h
+++ b/sound/soc/meson/axg-fifo.h
@@ -60,6 +60,7 @@ struct snd_soc_pcm_runtime;
60#define FIFO_STATUS1 0x14 60#define FIFO_STATUS1 0x14
61#define STATUS1_INT_STS(x) ((x) << 0) 61#define STATUS1_INT_STS(x) ((x) << 0)
62#define FIFO_STATUS2 0x18 62#define FIFO_STATUS2 0x18
63#define FIFO_INIT_ADDR 0x24
63 64
64struct axg_fifo { 65struct axg_fifo {
65 struct regmap *map; 66 struct regmap *map;
@@ -74,6 +75,7 @@ struct axg_fifo_match_data {
74}; 75};
75 76
76extern const struct snd_pcm_ops axg_fifo_pcm_ops; 77extern const struct snd_pcm_ops axg_fifo_pcm_ops;
78extern const struct snd_pcm_ops g12a_fifo_pcm_ops;
77 79
78int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type); 80int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type);
79int axg_fifo_probe(struct platform_device *pdev); 81int axg_fifo_probe(struct platform_device *pdev);
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
index a6f6f6a2eca8..2b8807737b2b 100644
--- a/sound/soc/meson/axg-frddr.c
+++ b/sound/soc/meson/axg-frddr.c
@@ -3,7 +3,9 @@
3// Copyright (c) 2018 BayLibre, SAS. 3// Copyright (c) 2018 BayLibre, SAS.
4// Author: Jerome Brunet <jbrunet@baylibre.com> 4// Author: Jerome Brunet <jbrunet@baylibre.com>
5 5
6/* This driver implements the frontend playback DAI of AXG based SoCs */ 6/*
7 * This driver implements the frontend playback DAI of AXG and G12A based SoCs
8 */
7 9
8#include <linux/clk.h> 10#include <linux/clk.h>
9#include <linux/regmap.h> 11#include <linux/regmap.h>
@@ -14,7 +16,29 @@
14 16
15#include "axg-fifo.h" 17#include "axg-fifo.h"
16 18
17#define CTRL0_FRDDR_PP_MODE BIT(30) 19#define CTRL0_FRDDR_PP_MODE BIT(30)
20#define CTRL0_SEL1_EN_SHIFT 3
21#define CTRL0_SEL2_SHIFT 4
22#define CTRL0_SEL2_EN_SHIFT 7
23#define CTRL0_SEL3_SHIFT 8
24#define CTRL0_SEL3_EN_SHIFT 11
25#define CTRL1_FRDDR_FORCE_FINISH BIT(12)
26
27static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream,
28 struct snd_soc_dai *dai)
29{
30 struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
31
32 /* Reset the read pointer to the FIFO_INIT_ADDR */
33 regmap_update_bits(fifo->map, FIFO_CTRL1,
34 CTRL1_FRDDR_FORCE_FINISH, 0);
35 regmap_update_bits(fifo->map, FIFO_CTRL1,
36 CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH);
37 regmap_update_bits(fifo->map, FIFO_CTRL1,
38 CTRL1_FRDDR_FORCE_FINISH, 0);
39
40 return 0;
41}
18 42
19static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, 43static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
20 struct snd_soc_dai *dai) 44 struct snd_soc_dai *dai)
@@ -119,10 +143,123 @@ static const struct axg_fifo_match_data axg_frddr_match_data = {
119 .dai_drv = &axg_frddr_dai_drv 143 .dai_drv = &axg_frddr_dai_drv
120}; 144};
121 145
146static const struct snd_soc_dai_ops g12a_frddr_ops = {
147 .prepare = g12a_frddr_dai_prepare,
148 .startup = axg_frddr_dai_startup,
149 .shutdown = axg_frddr_dai_shutdown,
150};
151
152static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
153 .name = "FRDDR",
154 .playback = {
155 .stream_name = "Playback",
156 .channels_min = 1,
157 .channels_max = AXG_FIFO_CH_MAX,
158 .rates = AXG_FIFO_RATES,
159 .formats = AXG_FIFO_FORMATS,
160 },
161 .ops = &g12a_frddr_ops,
162 .pcm_new = axg_frddr_pcm_new,
163};
164
165static const char * const g12a_frddr_sel_texts[] = {
166 "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4",
167};
168
169static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
170 g12a_frddr_sel_texts);
171static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT,
172 g12a_frddr_sel_texts);
173static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT,
174 g12a_frddr_sel_texts);
175
176static const struct snd_kcontrol_new g12a_frddr_out1_demux =
177 SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum);
178static const struct snd_kcontrol_new g12a_frddr_out2_demux =
179 SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum);
180static const struct snd_kcontrol_new g12a_frddr_out3_demux =
181 SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum);
182
183static const struct snd_kcontrol_new g12a_frddr_out1_enable =
184 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
185 CTRL0_SEL1_EN_SHIFT, 1, 0);
186static const struct snd_kcontrol_new g12a_frddr_out2_enable =
187 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
188 CTRL0_SEL2_EN_SHIFT, 1, 0);
189static const struct snd_kcontrol_new g12a_frddr_out3_enable =
190 SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
191 CTRL0_SEL3_EN_SHIFT, 1, 0);
192
193static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = {
194 SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
195 SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
196 SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
197 SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
198 &g12a_frddr_out1_enable),
199 SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
200 &g12a_frddr_out2_enable),
201 SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
202 &g12a_frddr_out3_enable),
203 SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
204 &g12a_frddr_out1_demux),
205 SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
206 &g12a_frddr_out2_demux),
207 SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
208 &g12a_frddr_out3_demux),
209 SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
210 SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
211 SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
212 SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
213 SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
214};
215
216static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = {
217 { "SRC 1", NULL, "Playback" },
218 { "SRC 2", NULL, "Playback" },
219 { "SRC 3", NULL, "Playback" },
220 { "SRC 1 EN", "Switch", "SRC 1" },
221 { "SRC 2 EN", "Switch", "SRC 2" },
222 { "SRC 3 EN", "Switch", "SRC 3" },
223 { "SINK 1 SEL", NULL, "SRC 1 EN" },
224 { "SINK 2 SEL", NULL, "SRC 2 EN" },
225 { "SINK 3 SEL", NULL, "SRC 3 EN" },
226 { "OUT 0", "OUT 0", "SINK 1 SEL" },
227 { "OUT 1", "OUT 1", "SINK 1 SEL" },
228 { "OUT 2", "OUT 2", "SINK 1 SEL" },
229 { "OUT 3", "OUT 3", "SINK 1 SEL" },
230 { "OUT 4", "OUT 4", "SINK 1 SEL" },
231 { "OUT 0", "OUT 0", "SINK 2 SEL" },
232 { "OUT 1", "OUT 1", "SINK 2 SEL" },
233 { "OUT 2", "OUT 2", "SINK 2 SEL" },
234 { "OUT 3", "OUT 3", "SINK 2 SEL" },
235 { "OUT 4", "OUT 4", "SINK 2 SEL" },
236 { "OUT 0", "OUT 0", "SINK 3 SEL" },
237 { "OUT 1", "OUT 1", "SINK 3 SEL" },
238 { "OUT 2", "OUT 2", "SINK 3 SEL" },
239 { "OUT 3", "OUT 3", "SINK 3 SEL" },
240 { "OUT 4", "OUT 4", "SINK 3 SEL" },
241};
242
243static const struct snd_soc_component_driver g12a_frddr_component_drv = {
244 .dapm_widgets = g12a_frddr_dapm_widgets,
245 .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets),
246 .dapm_routes = g12a_frddr_dapm_routes,
247 .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
248 .ops = &g12a_fifo_pcm_ops
249};
250
251static const struct axg_fifo_match_data g12a_frddr_match_data = {
252 .component_drv = &g12a_frddr_component_drv,
253 .dai_drv = &g12a_frddr_dai_drv
254};
255
122static const struct of_device_id axg_frddr_of_match[] = { 256static const struct of_device_id axg_frddr_of_match[] = {
123 { 257 {
124 .compatible = "amlogic,axg-frddr", 258 .compatible = "amlogic,axg-frddr",
125 .data = &axg_frddr_match_data, 259 .data = &axg_frddr_match_data,
260 }, {
261 .compatible = "amlogic,g12a-frddr",
262 .data = &g12a_frddr_match_data,
126 }, {} 263 }, {}
127}; 264};
128MODULE_DEVICE_TABLE(of, axg_frddr_of_match); 265MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
@@ -136,6 +273,6 @@ static struct platform_driver axg_frddr_pdrv = {
136}; 273};
137module_platform_driver(axg_frddr_pdrv); 274module_platform_driver(axg_frddr_pdrv);
138 275
139MODULE_DESCRIPTION("Amlogic AXG playback fifo driver"); 276MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver");
140MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 277MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
141MODULE_LICENSE("GPL v2"); 278MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
index 43e390f9358a..0c6cce5c5773 100644
--- a/sound/soc/meson/axg-tdm-formatter.c
+++ b/sound/soc/meson/axg-tdm-formatter.c
@@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
68static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) 68static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter)
69{ 69{
70 struct axg_tdm_stream *ts = formatter->stream; 70 struct axg_tdm_stream *ts = formatter->stream;
71 bool invert = formatter->drv->invert_sclk; 71 bool invert = formatter->drv->quirks->invert_sclk;
72 int ret; 72 int ret;
73 73
74 /* Do nothing if the formatter is already enabled */ 74 /* Do nothing if the formatter is already enabled */
@@ -85,7 +85,9 @@ static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter)
85 return ret; 85 return ret;
86 86
87 /* Setup the stream parameter in the formatter */ 87 /* Setup the stream parameter in the formatter */
88 ret = formatter->drv->ops->prepare(formatter->map, formatter->stream); 88 ret = formatter->drv->ops->prepare(formatter->map,
89 formatter->drv->quirks,
90 formatter->stream);
89 if (ret) 91 if (ret)
90 return ret; 92 return ret;
91 93
diff --git a/sound/soc/meson/axg-tdm-formatter.h b/sound/soc/meson/axg-tdm-formatter.h
index cf947caf3cb1..9ef98e955cb2 100644
--- a/sound/soc/meson/axg-tdm-formatter.h
+++ b/sound/soc/meson/axg-tdm-formatter.h
@@ -14,18 +14,25 @@ struct regmap;
14struct snd_soc_dapm_widget; 14struct snd_soc_dapm_widget;
15struct snd_kcontrol; 15struct snd_kcontrol;
16 16
17struct axg_tdm_formatter_hw {
18 unsigned int skew_offset;
19 bool invert_sclk;
20};
21
17struct axg_tdm_formatter_ops { 22struct axg_tdm_formatter_ops {
18 struct axg_tdm_stream *(*get_stream)(struct snd_soc_dapm_widget *w); 23 struct axg_tdm_stream *(*get_stream)(struct snd_soc_dapm_widget *w);
19 void (*enable)(struct regmap *map); 24 void (*enable)(struct regmap *map);
20 void (*disable)(struct regmap *map); 25 void (*disable)(struct regmap *map);
21 int (*prepare)(struct regmap *map, struct axg_tdm_stream *ts); 26 int (*prepare)(struct regmap *map,
27 const struct axg_tdm_formatter_hw *quirks,
28 struct axg_tdm_stream *ts);
22}; 29};
23 30
24struct axg_tdm_formatter_driver { 31struct axg_tdm_formatter_driver {
25 const struct snd_soc_component_driver *component_drv; 32 const struct snd_soc_component_driver *component_drv;
26 const struct regmap_config *regmap_cfg; 33 const struct regmap_config *regmap_cfg;
27 const struct axg_tdm_formatter_ops *ops; 34 const struct axg_tdm_formatter_ops *ops;
28 bool invert_sclk; 35 const struct axg_tdm_formatter_hw *quirks;
29}; 36};
30 37
31int axg_tdm_formatter_set_channel_masks(struct regmap *map, 38int axg_tdm_formatter_set_channel_masks(struct regmap *map,
diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c
index bbac44c81688..a790f925a4ef 100644
--- a/sound/soc/meson/axg-tdmin.c
+++ b/sound/soc/meson/axg-tdmin.c
@@ -107,21 +107,22 @@ static void axg_tdmin_disable(struct regmap *map)
107 regmap_update_bits(map, TDMIN_CTRL, TDMIN_CTRL_ENABLE, 0); 107 regmap_update_bits(map, TDMIN_CTRL, TDMIN_CTRL_ENABLE, 0);
108} 108}
109 109
110static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts) 110static int axg_tdmin_prepare(struct regmap *map,
111 const struct axg_tdm_formatter_hw *quirks,
112 struct axg_tdm_stream *ts)
111{ 113{
112 unsigned int val = 0; 114 unsigned int val, skew = quirks->skew_offset;
113 115
114 /* Set stream skew */ 116 /* Set stream skew */
115 switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 117 switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
116 case SND_SOC_DAIFMT_I2S: 118 case SND_SOC_DAIFMT_I2S:
117 case SND_SOC_DAIFMT_DSP_A: 119 case SND_SOC_DAIFMT_DSP_A:
118 val |= TDMIN_CTRL_IN_BIT_SKEW(3); 120 skew += 1;
119 break; 121 break;
120 122
121 case SND_SOC_DAIFMT_LEFT_J: 123 case SND_SOC_DAIFMT_LEFT_J:
122 case SND_SOC_DAIFMT_RIGHT_J: 124 case SND_SOC_DAIFMT_RIGHT_J:
123 case SND_SOC_DAIFMT_DSP_B: 125 case SND_SOC_DAIFMT_DSP_B:
124 val = TDMIN_CTRL_IN_BIT_SKEW(2);
125 break; 126 break;
126 127
127 default: 128 default:
@@ -130,6 +131,8 @@ static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts)
130 return -EINVAL; 131 return -EINVAL;
131 } 132 }
132 133
134 val = TDMIN_CTRL_IN_BIT_SKEW(skew);
135
133 /* Set stream format mode */ 136 /* Set stream format mode */
134 switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 137 switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
135 case SND_SOC_DAIFMT_I2S: 138 case SND_SOC_DAIFMT_I2S:
@@ -204,7 +207,10 @@ static const struct axg_tdm_formatter_driver axg_tdmin_drv = {
204 .component_drv = &axg_tdmin_component_drv, 207 .component_drv = &axg_tdmin_component_drv,
205 .regmap_cfg = &axg_tdmin_regmap_cfg, 208 .regmap_cfg = &axg_tdmin_regmap_cfg,
206 .ops = &axg_tdmin_ops, 209 .ops = &axg_tdmin_ops,
207 .invert_sclk = false, 210 .quirks = &(const struct axg_tdm_formatter_hw) {
211 .invert_sclk = false,
212 .skew_offset = 2,
213 },
208}; 214};
209 215
210static const struct of_device_id axg_tdmin_of_match[] = { 216static const struct of_device_id axg_tdmin_of_match[] = {
diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c
index f73368ee1088..527bfc4487e0 100644
--- a/sound/soc/meson/axg-tdmout.c
+++ b/sound/soc/meson/axg-tdmout.c
@@ -124,21 +124,22 @@ static void axg_tdmout_disable(struct regmap *map)
124 regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0); 124 regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0);
125} 125}
126 126
127static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts) 127static int axg_tdmout_prepare(struct regmap *map,
128 const struct axg_tdm_formatter_hw *quirks,
129 struct axg_tdm_stream *ts)
128{ 130{
129 unsigned int val = 0; 131 unsigned int val, skew = quirks->skew_offset;
130 132
131 /* Set the stream skew */ 133 /* Set the stream skew */
132 switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 134 switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
133 case SND_SOC_DAIFMT_I2S: 135 case SND_SOC_DAIFMT_I2S:
134 case SND_SOC_DAIFMT_DSP_A: 136 case SND_SOC_DAIFMT_DSP_A:
135 val |= TDMOUT_CTRL0_INIT_BITNUM(1);
136 break; 137 break;
137 138
138 case SND_SOC_DAIFMT_LEFT_J: 139 case SND_SOC_DAIFMT_LEFT_J:
139 case SND_SOC_DAIFMT_RIGHT_J: 140 case SND_SOC_DAIFMT_RIGHT_J:
140 case SND_SOC_DAIFMT_DSP_B: 141 case SND_SOC_DAIFMT_DSP_B:
141 val |= TDMOUT_CTRL0_INIT_BITNUM(2); 142 skew += 1;
142 break; 143 break;
143 144
144 default: 145 default:
@@ -147,6 +148,8 @@ static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts)
147 return -EINVAL; 148 return -EINVAL;
148 } 149 }
149 150
151 val = TDMOUT_CTRL0_INIT_BITNUM(skew);
152
150 /* Set the slot width */ 153 /* Set the slot width */
151 val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1); 154 val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1);
152 155
@@ -234,13 +237,29 @@ static const struct axg_tdm_formatter_driver axg_tdmout_drv = {
234 .component_drv = &axg_tdmout_component_drv, 237 .component_drv = &axg_tdmout_component_drv,
235 .regmap_cfg = &axg_tdmout_regmap_cfg, 238 .regmap_cfg = &axg_tdmout_regmap_cfg,
236 .ops = &axg_tdmout_ops, 239 .ops = &axg_tdmout_ops,
237 .invert_sclk = true, 240 .quirks = &(const struct axg_tdm_formatter_hw) {
241 .invert_sclk = true,
242 .skew_offset = 1,
243 },
244};
245
246static const struct axg_tdm_formatter_driver g12a_tdmout_drv = {
247 .component_drv = &axg_tdmout_component_drv,
248 .regmap_cfg = &axg_tdmout_regmap_cfg,
249 .ops = &axg_tdmout_ops,
250 .quirks = &(const struct axg_tdm_formatter_hw) {
251 .invert_sclk = true,
252 .skew_offset = 2,
253 },
238}; 254};
239 255
240static const struct of_device_id axg_tdmout_of_match[] = { 256static const struct of_device_id axg_tdmout_of_match[] = {
241 { 257 {
242 .compatible = "amlogic,axg-tdmout", 258 .compatible = "amlogic,axg-tdmout",
243 .data = &axg_tdmout_drv, 259 .data = &axg_tdmout_drv,
260 }, {
261 .compatible = "amlogic,g12a-tdmout",
262 .data = &g12a_tdmout_drv,
244 }, {} 263 }, {}
245}; 264};
246MODULE_DEVICE_TABLE(of, axg_tdmout_of_match); 265MODULE_DEVICE_TABLE(of, axg_tdmout_of_match);
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
index 0e9ca3882ae5..4f63e434fad4 100644
--- a/sound/soc/meson/axg-toddr.c
+++ b/sound/soc/meson/axg-toddr.c
@@ -24,6 +24,7 @@
24#define CTRL0_TODDR_MSB_POS(x) ((x) << 8) 24#define CTRL0_TODDR_MSB_POS(x) ((x) << 8)
25#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) 25#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
26#define CTRL0_TODDR_LSB_POS(x) ((x) << 3) 26#define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
27#define CTRL1_TODDR_FORCE_FINISH BIT(25)
27 28
28#define TODDR_MSB_POS 31 29#define TODDR_MSB_POS 31
29 30
@@ -33,6 +34,22 @@ static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
33 return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE); 34 return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE);
34} 35}
35 36
37static int g12a_toddr_dai_prepare(struct snd_pcm_substream *substream,
38 struct snd_soc_dai *dai)
39{
40 struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
41
42 /* Reset the write pointer to the FIFO_INIT_ADDR */
43 regmap_update_bits(fifo->map, FIFO_CTRL1,
44 CTRL1_TODDR_FORCE_FINISH, 0);
45 regmap_update_bits(fifo->map, FIFO_CTRL1,
46 CTRL1_TODDR_FORCE_FINISH, CTRL1_TODDR_FORCE_FINISH);
47 regmap_update_bits(fifo->map, FIFO_CTRL1,
48 CTRL1_TODDR_FORCE_FINISH, 0);
49
50 return 0;
51}
52
36static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream, 53static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
37 struct snd_pcm_hw_params *params, 54 struct snd_pcm_hw_params *params,
38 struct snd_soc_dai *dai) 55 struct snd_soc_dai *dai)
@@ -172,10 +189,46 @@ static const struct axg_fifo_match_data axg_toddr_match_data = {
172 .dai_drv = &axg_toddr_dai_drv 189 .dai_drv = &axg_toddr_dai_drv
173}; 190};
174 191
192static const struct snd_soc_dai_ops g12a_toddr_ops = {
193 .prepare = g12a_toddr_dai_prepare,
194 .hw_params = axg_toddr_dai_hw_params,
195 .startup = axg_toddr_dai_startup,
196 .shutdown = axg_toddr_dai_shutdown,
197};
198
199static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
200 .name = "TODDR",
201 .capture = {
202 .stream_name = "Capture",
203 .channels_min = 1,
204 .channels_max = AXG_FIFO_CH_MAX,
205 .rates = AXG_FIFO_RATES,
206 .formats = AXG_FIFO_FORMATS,
207 },
208 .ops = &g12a_toddr_ops,
209 .pcm_new = axg_toddr_pcm_new,
210};
211
212static const struct snd_soc_component_driver g12a_toddr_component_drv = {
213 .dapm_widgets = axg_toddr_dapm_widgets,
214 .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets),
215 .dapm_routes = axg_toddr_dapm_routes,
216 .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
217 .ops = &g12a_fifo_pcm_ops
218};
219
220static const struct axg_fifo_match_data g12a_toddr_match_data = {
221 .component_drv = &g12a_toddr_component_drv,
222 .dai_drv = &g12a_toddr_dai_drv
223};
224
175static const struct of_device_id axg_toddr_of_match[] = { 225static const struct of_device_id axg_toddr_of_match[] = {
176 { 226 {
177 .compatible = "amlogic,axg-toddr", 227 .compatible = "amlogic,axg-toddr",
178 .data = &axg_toddr_match_data, 228 .data = &axg_toddr_match_data,
229 }, {
230 .compatible = "amlogic,g12a-toddr",
231 .data = &g12a_toddr_match_data,
179 }, {} 232 }, {}
180}; 233};
181MODULE_DEVICE_TABLE(of, axg_toddr_of_match); 234MODULE_DEVICE_TABLE(of, axg_toddr_of_match);
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 75ceb04d8bf0..b1764af858ba 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -98,7 +98,7 @@ config SND_SOC_MSM8996
98 98
99config SND_SOC_SDM845 99config SND_SOC_SDM845
100 tristate "SoC Machine driver for SDM845 boards" 100 tristate "SoC Machine driver for SDM845 boards"
101 depends on QCOM_APR && MFD_CROS_EC 101 depends on QCOM_APR && MFD_CROS_EC && I2C
102 select SND_SOC_QDSP6 102 select SND_SOC_QDSP6
103 select SND_SOC_QCOM_COMMON 103 select SND_SOC_QCOM_COMMON
104 select SND_SOC_RT5663 104 select SND_SOC_RT5663
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index d0b403a0e27b..b9c1d8ad77c1 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -17,14 +17,23 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/clk.h> 18#include <linux/clk.h>
19#include <linux/of.h> 19#include <linux/of.h>
20#include <linux/of_device.h>
20#include <linux/pm_runtime.h> 21#include <linux/pm_runtime.h>
22#include <linux/rational.h>
21#include <linux/regmap.h> 23#include <linux/regmap.h>
24#include <linux/reset.h>
22#include <sound/dmaengine_pcm.h> 25#include <sound/dmaengine_pcm.h>
23#include <sound/pcm_params.h> 26#include <sound/pcm_params.h>
24 27
25#include "rockchip_pdm.h" 28#include "rockchip_pdm.h"
26 29
27#define PDM_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */ 30#define PDM_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */
31#define PDM_SIGNOFF_CLK_RATE (100000000)
32
33enum rk_pdm_version {
34 RK_PDM_RK3229,
35 RK_PDM_RK3308,
36};
28 37
29struct rk_pdm_dev { 38struct rk_pdm_dev {
30 struct device *dev; 39 struct device *dev;
@@ -32,22 +41,51 @@ struct rk_pdm_dev {
32 struct clk *hclk; 41 struct clk *hclk;
33 struct regmap *regmap; 42 struct regmap *regmap;
34 struct snd_dmaengine_dai_dma_data capture_dma_data; 43 struct snd_dmaengine_dai_dma_data capture_dma_data;
44 struct reset_control *reset;
45 enum rk_pdm_version version;
35}; 46};
36 47
37struct rk_pdm_clkref { 48struct rk_pdm_clkref {
38 unsigned int sr; 49 unsigned int sr;
39 unsigned int clk; 50 unsigned int clk;
51 unsigned int clk_out;
52};
53
54struct rk_pdm_ds_ratio {
55 unsigned int ratio;
56 unsigned int sr;
40}; 57};
41 58
42static struct rk_pdm_clkref clkref[] = { 59static struct rk_pdm_clkref clkref[] = {
43 { 8000, 40960000 }, 60 { 8000, 40960000, 2048000 },
44 { 11025, 56448000 }, 61 { 11025, 56448000, 2822400 },
45 { 12000, 61440000 }, 62 { 12000, 61440000, 3072000 },
63 { 8000, 98304000, 2048000 },
64 { 12000, 98304000, 3072000 },
65};
66
67static struct rk_pdm_ds_ratio ds_ratio[] = {
68 { 0, 192000 },
69 { 0, 176400 },
70 { 0, 128000 },
71 { 1, 96000 },
72 { 1, 88200 },
73 { 1, 64000 },
74 { 2, 48000 },
75 { 2, 44100 },
76 { 2, 32000 },
77 { 3, 24000 },
78 { 3, 22050 },
79 { 3, 16000 },
80 { 4, 12000 },
81 { 4, 11025 },
82 { 4, 8000 },
46}; 83};
47 84
48static unsigned int get_pdm_clk(unsigned int sr) 85static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr,
86 unsigned int *clk_src, unsigned int *clk_out)
49{ 87{
50 unsigned int i, count, clk, div; 88 unsigned int i, count, clk, div, rate;
51 89
52 clk = 0; 90 clk = 0;
53 if (!sr) 91 if (!sr)
@@ -59,14 +97,39 @@ static unsigned int get_pdm_clk(unsigned int sr)
59 continue; 97 continue;
60 div = sr / clkref[i].sr; 98 div = sr / clkref[i].sr;
61 if ((div & (div - 1)) == 0) { 99 if ((div & (div - 1)) == 0) {
100 *clk_out = clkref[i].clk_out;
101 rate = clk_round_rate(pdm->clk, clkref[i].clk);
102 if (rate != clkref[i].clk)
103 continue;
62 clk = clkref[i].clk; 104 clk = clkref[i].clk;
105 *clk_src = clkref[i].clk;
63 break; 106 break;
64 } 107 }
65 } 108 }
66 109
110 if (!clk) {
111 clk = clk_round_rate(pdm->clk, PDM_SIGNOFF_CLK_RATE);
112 *clk_src = clk;
113 }
67 return clk; 114 return clk;
68} 115}
69 116
117static unsigned int get_pdm_ds_ratio(unsigned int sr)
118{
119 unsigned int i, count, ratio;
120
121 ratio = 0;
122 if (!sr)
123 return ratio;
124
125 count = ARRAY_SIZE(ds_ratio);
126 for (i = 0; i < count; i++) {
127 if (sr == ds_ratio[i].sr)
128 ratio = ds_ratio[i].ratio;
129 }
130 return ratio;
131}
132
70static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai) 133static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai)
71{ 134{
72 return snd_soc_dai_get_drvdata(dai); 135 return snd_soc_dai_get_drvdata(dai);
@@ -95,46 +158,61 @@ static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream,
95 struct rk_pdm_dev *pdm = to_info(dai); 158 struct rk_pdm_dev *pdm = to_info(dai);
96 unsigned int val = 0; 159 unsigned int val = 0;
97 unsigned int clk_rate, clk_div, samplerate; 160 unsigned int clk_rate, clk_div, samplerate;
161 unsigned int clk_src, clk_out = 0;
162 unsigned long m, n;
163 bool change;
98 int ret; 164 int ret;
99 165
166 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
167 return 0;
168
100 samplerate = params_rate(params); 169 samplerate = params_rate(params);
101 clk_rate = get_pdm_clk(samplerate); 170 clk_rate = get_pdm_clk(pdm, samplerate, &clk_src, &clk_out);
102 if (!clk_rate) 171 if (!clk_rate)
103 return -EINVAL; 172 return -EINVAL;
104 173
105 ret = clk_set_rate(pdm->clk, clk_rate); 174 ret = clk_set_rate(pdm->clk, clk_src);
106 if (ret) 175 if (ret)
107 return -EINVAL; 176 return -EINVAL;
108 177
109 clk_div = DIV_ROUND_CLOSEST(clk_rate, samplerate); 178 if (pdm->version == RK_PDM_RK3308) {
110 179 rational_best_approximation(clk_out, clk_src,
111 switch (clk_div) { 180 GENMASK(16 - 1, 0),
112 case 320: 181 GENMASK(16 - 1, 0),
113 val = PDM_CLK_320FS; 182 &m, &n);
114 break; 183
115 case 640: 184 val = (m << PDM_FD_NUMERATOR_SFT) |
116 val = PDM_CLK_640FS; 185 (n << PDM_FD_DENOMINATOR_SFT);
117 break; 186 regmap_update_bits_check(pdm->regmap, PDM_CTRL1,
118 case 1280: 187 PDM_FD_NUMERATOR_MSK |
119 val = PDM_CLK_1280FS; 188 PDM_FD_DENOMINATOR_MSK,
120 break; 189 val, &change);
121 case 2560: 190 if (change) {
122 val = PDM_CLK_2560FS; 191 reset_control_assert(pdm->reset);
123 break; 192 reset_control_deassert(pdm->reset);
124 case 5120: 193 rockchip_pdm_rxctrl(pdm, 0);
125 val = PDM_CLK_5120FS; 194 }
126 break; 195 clk_div = n / m;
127 default: 196 if (clk_div >= 40)
128 dev_err(pdm->dev, "unsupported div: %d\n", clk_div); 197 val = PDM_CLK_FD_RATIO_40;
129 return -EINVAL; 198 else if (clk_div <= 35)
199 val = PDM_CLK_FD_RATIO_35;
200 else
201 return -EINVAL;
202 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL,
203 PDM_CLK_FD_RATIO_MSK,
204 val);
130 } 205 }
131 206 val = get_pdm_ds_ratio(samplerate);
132 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val); 207 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val);
133 regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, 208 regmap_update_bits(pdm->regmap, PDM_HPF_CTRL,
134 PDM_HPF_CF_MSK, PDM_HPF_60HZ); 209 PDM_HPF_CF_MSK, PDM_HPF_60HZ);
135 regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, 210 regmap_update_bits(pdm->regmap, PDM_HPF_CTRL,
136 PDM_HPF_LE | PDM_HPF_RE, PDM_HPF_LE | PDM_HPF_RE); 211 PDM_HPF_LE | PDM_HPF_RE, PDM_HPF_LE | PDM_HPF_RE);
137 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_CLK_EN, PDM_CLK_EN); 212 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_CLK_EN, PDM_CLK_EN);
213 if (pdm->version != RK_PDM_RK3229)
214 regmap_update_bits(pdm->regmap, PDM_CTRL0,
215 PDM_MODE_MSK, PDM_MODE_LJ);
138 216
139 val = 0; 217 val = 0;
140 switch (params_format(params)) { 218 switch (params_format(params)) {
@@ -176,16 +254,12 @@ static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream,
176 return -EINVAL; 254 return -EINVAL;
177 } 255 }
178 256
179 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 257 regmap_update_bits(pdm->regmap, PDM_CTRL0,
180 regmap_update_bits(pdm->regmap, PDM_CTRL0, 258 PDM_PATH_MSK | PDM_VDW_MSK,
181 PDM_PATH_MSK | PDM_VDW_MSK, 259 val);
182 val); 260 /* all channels share the single FIFO */
183 regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, PDM_DMA_RDL_MSK, 261 regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, PDM_DMA_RDL_MSK,
184 PDM_DMA_RDL(16)); 262 PDM_DMA_RDL(8 * params_channels(params)));
185 regmap_update_bits(pdm->regmap, PDM_SYSCONFIG,
186 PDM_RX_MASK | PDM_RX_CLR_MASK,
187 PDM_RX_STOP | PDM_RX_CLR_WR);
188 }
189 263
190 return 0; 264 return 0;
191} 265}
@@ -343,6 +417,7 @@ static bool rockchip_pdm_rd_reg(struct device *dev, unsigned int reg)
343 case PDM_INT_CLR: 417 case PDM_INT_CLR:
344 case PDM_INT_ST: 418 case PDM_INT_ST:
345 case PDM_DATA_VALID: 419 case PDM_DATA_VALID:
420 case PDM_RXFIFO_DATA:
346 case PDM_VERSION: 421 case PDM_VERSION:
347 return true; 422 return true;
348 default: 423 default:
@@ -354,27 +429,62 @@ static bool rockchip_pdm_volatile_reg(struct device *dev, unsigned int reg)
354{ 429{
355 switch (reg) { 430 switch (reg) {
356 case PDM_SYSCONFIG: 431 case PDM_SYSCONFIG:
432 case PDM_FIFO_CTRL:
357 case PDM_INT_CLR: 433 case PDM_INT_CLR:
358 case PDM_INT_ST: 434 case PDM_INT_ST:
435 case PDM_RXFIFO_DATA:
436 return true;
437 default:
438 return false;
439 }
440}
441
442static bool rockchip_pdm_precious_reg(struct device *dev, unsigned int reg)
443{
444 switch (reg) {
445 case PDM_RXFIFO_DATA:
359 return true; 446 return true;
360 default: 447 default:
361 return false; 448 return false;
362 } 449 }
363} 450}
364 451
452static const struct reg_default rockchip_pdm_reg_defaults[] = {
453 {0x04, 0x78000017},
454 {0x08, 0x0bb8ea60},
455 {0x18, 0x0000001f},
456};
457
365static const struct regmap_config rockchip_pdm_regmap_config = { 458static const struct regmap_config rockchip_pdm_regmap_config = {
366 .reg_bits = 32, 459 .reg_bits = 32,
367 .reg_stride = 4, 460 .reg_stride = 4,
368 .val_bits = 32, 461 .val_bits = 32,
369 .max_register = PDM_VERSION, 462 .max_register = PDM_VERSION,
463 .reg_defaults = rockchip_pdm_reg_defaults,
464 .num_reg_defaults = ARRAY_SIZE(rockchip_pdm_reg_defaults),
370 .writeable_reg = rockchip_pdm_wr_reg, 465 .writeable_reg = rockchip_pdm_wr_reg,
371 .readable_reg = rockchip_pdm_rd_reg, 466 .readable_reg = rockchip_pdm_rd_reg,
372 .volatile_reg = rockchip_pdm_volatile_reg, 467 .volatile_reg = rockchip_pdm_volatile_reg,
468 .precious_reg = rockchip_pdm_precious_reg,
373 .cache_type = REGCACHE_FLAT, 469 .cache_type = REGCACHE_FLAT,
374}; 470};
375 471
472static const struct of_device_id rockchip_pdm_match[] = {
473 { .compatible = "rockchip,pdm",
474 .data = (void *)RK_PDM_RK3229 },
475 { .compatible = "rockchip,px30-pdm",
476 .data = (void *)RK_PDM_RK3308 },
477 { .compatible = "rockchip,rk1808-pdm",
478 .data = (void *)RK_PDM_RK3308 },
479 { .compatible = "rockchip,rk3308-pdm",
480 .data = (void *)RK_PDM_RK3308 },
481 {},
482};
483MODULE_DEVICE_TABLE(of, rockchip_pdm_match);
484
376static int rockchip_pdm_probe(struct platform_device *pdev) 485static int rockchip_pdm_probe(struct platform_device *pdev)
377{ 486{
487 const struct of_device_id *match;
378 struct rk_pdm_dev *pdm; 488 struct rk_pdm_dev *pdm;
379 struct resource *res; 489 struct resource *res;
380 void __iomem *regs; 490 void __iomem *regs;
@@ -384,6 +494,16 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
384 if (!pdm) 494 if (!pdm)
385 return -ENOMEM; 495 return -ENOMEM;
386 496
497 match = of_match_device(rockchip_pdm_match, &pdev->dev);
498 if (match)
499 pdm->version = (enum rk_pdm_version)match->data;
500
501 if (pdm->version == RK_PDM_RK3308) {
502 pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
503 if (IS_ERR(pdm->reset))
504 return PTR_ERR(pdm->reset);
505 }
506
387 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 507 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
388 regs = devm_ioremap_resource(&pdev->dev, res); 508 regs = devm_ioremap_resource(&pdev->dev, res);
389 if (IS_ERR(regs)) 509 if (IS_ERR(regs))
@@ -429,6 +549,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
429 goto err_suspend; 549 goto err_suspend;
430 } 550 }
431 551
552 rockchip_pdm_rxctrl(pdm, 0);
432 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 553 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
433 if (ret) { 554 if (ret) {
434 dev_err(&pdev->dev, "could not register pcm: %d\n", ret); 555 dev_err(&pdev->dev, "could not register pcm: %d\n", ret);
@@ -495,12 +616,6 @@ static const struct dev_pm_ops rockchip_pdm_pm_ops = {
495 SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) 616 SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume)
496}; 617};
497 618
498static const struct of_device_id rockchip_pdm_match[] = {
499 { .compatible = "rockchip,pdm", },
500 {},
501};
502MODULE_DEVICE_TABLE(of, rockchip_pdm_match);
503
504static struct platform_driver rockchip_pdm_driver = { 619static struct platform_driver rockchip_pdm_driver = {
505 .probe = rockchip_pdm_probe, 620 .probe = rockchip_pdm_probe,
506 .remove = rockchip_pdm_remove, 621 .remove = rockchip_pdm_remove,
diff --git a/sound/soc/rockchip/rockchip_pdm.h b/sound/soc/rockchip/rockchip_pdm.h
index 886b48d128fd..ae88644aa334 100644
--- a/sound/soc/rockchip/rockchip_pdm.h
+++ b/sound/soc/rockchip/rockchip_pdm.h
@@ -42,6 +42,9 @@
42 42
43/* PDM CTRL0 */ 43/* PDM CTRL0 */
44#define PDM_PATH_MSK (0xf << 27) 44#define PDM_PATH_MSK (0xf << 27)
45#define PDM_MODE_MSK BIT(31)
46#define PDM_MODE_RJ 0
47#define PDM_MODE_LJ BIT(31)
45#define PDM_PATH3_EN BIT(30) 48#define PDM_PATH3_EN BIT(30)
46#define PDM_PATH2_EN BIT(29) 49#define PDM_PATH2_EN BIT(29)
47#define PDM_PATH1_EN BIT(28) 50#define PDM_PATH1_EN BIT(28)
@@ -50,7 +53,16 @@
50#define PDM_VDW_MSK (0x1f << 0) 53#define PDM_VDW_MSK (0x1f << 0)
51#define PDM_VDW(X) ((X - 1) << 0) 54#define PDM_VDW(X) ((X - 1) << 0)
52 55
56/* PDM CTRL1 */
57#define PDM_FD_NUMERATOR_SFT 16
58#define PDM_FD_NUMERATOR_MSK GENMASK(31, 16)
59#define PDM_FD_DENOMINATOR_SFT 0
60#define PDM_FD_DENOMINATOR_MSK GENMASK(15, 0)
61
53/* PDM CLK CTRL */ 62/* PDM CLK CTRL */
63#define PDM_CLK_FD_RATIO_MSK BIT(6)
64#define PDM_CLK_FD_RATIO_40 (0X0 << 6)
65#define PDM_CLK_FD_RATIO_35 BIT(6)
54#define PDM_CLK_MSK BIT(5) 66#define PDM_CLK_MSK BIT(5)
55#define PDM_CLK_EN BIT(5) 67#define PDM_CLK_EN BIT(5)
56#define PDM_CLK_DIS (0x0 << 5) 68#define PDM_CLK_DIS (0x0 << 5)
diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
index ee1fda92f2f4..cc334e1866f6 100644
--- a/sound/soc/samsung/arndale_rt5631.c
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -1,15 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * arndale_rt5631.c 2//
3 * 3// Copyright (c) 2014, Insignal Co., Ltd.
4 * Copyright (c) 2014, Insignal Co., Ltd. 4//
5 * 5// Author: Claude <claude@insginal.co.kr>
6 * Author: Claude <claude@insginal.co.kr>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13 6
14#include <linux/module.h> 7#include <linux/module.h>
15#include <linux/platform_device.h> 8#include <linux/platform_device.h>
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 0e66cd8ef2f9..770845e2507a 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -1,13 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Bells audio support 2//
3 * 3// Bells audio support
4 * Copyright 2012 Wolfson Microelectronics 4//
5 * 5// Copyright 2012 Wolfson Microelectronics
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11 6
12#include <sound/soc.h> 7#include <sound/soc.h>
13#include <sound/soc-dapm.h> 8#include <sound/soc-dapm.h>
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index 0ae15d01a3f6..7b5d4556e0fd 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -1,10 +1,6 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
1/* 2/*
2 * This program is free software; you can redistribute it and/or modify it 3 * ALSA PCM interface for the Samsung SoC
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation; either version 2 of the License, or (at your
5 * option) any later version.
6 *
7 * ALSA PCM interface for the Samsung SoC
8 */ 4 */
9 5
10#ifndef _SAMSUNG_DMA_H 6#ifndef _SAMSUNG_DMA_H
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
index 302871974cb3..2802789a323e 100644
--- a/sound/soc/samsung/dmaengine.c
+++ b/sound/soc/samsung/dmaengine.c
@@ -1,19 +1,9 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * dmaengine.c - Samsung dmaengine wrapper 2//
3 * 3// dmaengine.c - Samsung dmaengine wrapper
4 * Author: Mark Brown <broonie@linaro.org> 4//
5 * Copyright 2013 Linaro 5// Author: Mark Brown <broonie@linaro.org>
6 * 6// Copyright 2013 Linaro
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 */
17 7
18#include <linux/module.h> 8#include <linux/module.h>
19#include <sound/core.h> 9#include <sound/core.h>
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 051935162d7b..95925c4a5964 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -1,17 +1,11 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * h1940-uda1380.c -- ALSA Soc Audio Layer 2//
3 * 3// h1940_uda1380.c - ALSA SoC Audio Layer
4 * Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> 4//
5 * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com> 5// Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
6 * 6// Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
7 * Based on version from Arnaud Patard <arnaud.patard@rtp-net.org> 7//
8 * 8// Based on version from Arnaud Patard <arnaud.patard@rtp-net.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15 9
16#include <linux/types.h> 10#include <linux/types.h>
17#include <linux/gpio.h> 11#include <linux/gpio.h>
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h
index 964985ea2e80..b4b5d6053503 100644
--- a/sound/soc/samsung/i2s-regs.h
+++ b/sound/soc/samsung/i2s-regs.h
@@ -1,15 +1,9 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
1/* 2/*
2 * linux/sound/soc/samsung/i2s-regs.h
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com 4 * http://www.samsung.com
6 * 5 *
7 * Samsung I2S driver's register header 6 * Samsung I2S driver's register header
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */ 7 */
14 8
15#ifndef __SND_SOC_SAMSUNG_I2S_REGS_H 9#ifndef __SND_SOC_SAMSUNG_I2S_REGS_H
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index ab471d550d17..9722940da6a4 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -88,12 +88,6 @@ struct samsung_i2s_priv {
88 struct platform_device *pdev; 88 struct platform_device *pdev;
89 struct platform_device *pdev_sec; 89 struct platform_device *pdev_sec;
90 90
91 /* Memory mapped SFR region */
92 void __iomem *addr;
93
94 /* Spinlock protecting access to the device's registers */
95 spinlock_t lock;
96
97 /* Lock for cross interface checks */ 91 /* Lock for cross interface checks */
98 spinlock_t pcm_lock; 92 spinlock_t pcm_lock;
99 93
@@ -122,6 +116,15 @@ struct samsung_i2s_priv {
122 /* The clock provider's data */ 116 /* The clock provider's data */
123 struct clk *clk_table[3]; 117 struct clk *clk_table[3];
124 struct clk_onecell_data clk_data; 118 struct clk_onecell_data clk_data;
119
120 /* Spinlock protecting member fields below */
121 spinlock_t lock;
122
123 /* Memory mapped SFR region */
124 void __iomem *addr;
125
126 /* A flag indicating the I2S slave mode operation */
127 bool slave_mode;
125}; 128};
126 129
127/* Returns true if this is the 'overlay' stereo DAI */ 130/* Returns true if this is the 'overlay' stereo DAI */
@@ -130,15 +133,6 @@ static inline bool is_secondary(struct i2s_dai *i2s)
130 return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY; 133 return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY;
131} 134}
132 135
133/* If operating in SoC-Slave mode */
134static inline bool is_slave(struct i2s_dai *i2s)
135{
136 struct samsung_i2s_priv *priv = i2s->priv;
137
138 u32 mod = readl(priv->addr + I2SMOD);
139 return (mod & (1 << priv->variant_regs->mss_off)) ? true : false;
140}
141
142/* If this interface of the controller is transmitting data */ 136/* If this interface of the controller is transmitting data */
143static inline bool tx_active(struct i2s_dai *i2s) 137static inline bool tx_active(struct i2s_dai *i2s)
144{ 138{
@@ -715,6 +709,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
715 mod &= ~(sdf_mask | lrp_rlow | mod_slave); 709 mod &= ~(sdf_mask | lrp_rlow | mod_slave);
716 mod |= tmp; 710 mod |= tmp;
717 writel(mod, priv->addr + I2SMOD); 711 writel(mod, priv->addr + I2SMOD);
712 priv->slave_mode = (mod & mod_slave);
718 spin_unlock_irqrestore(&priv->lock, flags); 713 spin_unlock_irqrestore(&priv->lock, flags);
719 pm_runtime_put(dai->dev); 714 pm_runtime_put(dai->dev);
720 715
@@ -917,7 +912,7 @@ static int config_setup(struct i2s_dai *i2s)
917 set_rfs(i2s, rfs); 912 set_rfs(i2s, rfs);
918 913
919 /* Don't bother with PSR in Slave mode */ 914 /* Don't bother with PSR in Slave mode */
920 if (is_slave(i2s)) 915 if (priv->slave_mode)
921 return 0; 916 return 0;
922 917
923 if (!(priv->quirks & QUIRK_NO_MUXPSR)) { 918 if (!(priv->quirks & QUIRK_NO_MUXPSR)) {
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
index a9832a9555cb..78b475ef98d9 100644
--- a/sound/soc/samsung/i2s.h
+++ b/sound/soc/samsung/i2s.h
@@ -1,13 +1,9 @@
1/* sound/soc/samsung/i2s.h 1/* SPDX-License-Identifier: GPL-2.0 */
2 * 2/*
3 * ALSA SoC Audio Layer - Samsung I2S Controller driver 3 * ALSA SoC Audio Layer - Samsung I2S Controller driver
4 * 4 *
5 * Copyright (c) 2010 Samsung Electronics Co. Ltd. 5 * Copyright (c) 2010 Samsung Electronics Co. Ltd.
6 * Jaswinder Singh <jassisinghbrar@gmail.com> 6 * Jaswinder Singh <jassisinghbrar@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */ 7 */
12 8
13#ifndef __SND_SOC_SAMSUNG_I2S_H 9#ifndef __SND_SOC_SAMSUNG_I2S_H
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index b1f09b942410..65497cd477a5 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -1,16 +1,10 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * sound/soc/samsung/idma.c 2//
3 * 3// idma.c - I2S0 internal DMA driver
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 4//
5 * http://www.samsung.com 5// Copyright (c) 2011 Samsung Electronics Co., Ltd.
6 * 6// http://www.samsung.com
7 * I2S0's Internal DMA driver 7
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14#include <linux/interrupt.h> 8#include <linux/interrupt.h>
15#include <linux/platform_device.h> 9#include <linux/platform_device.h>
16#include <linux/dma-mapping.h> 10#include <linux/dma-mapping.h>
diff --git a/sound/soc/samsung/idma.h b/sound/soc/samsung/idma.h
index 8644946973e5..8a46a918ed2a 100644
--- a/sound/soc/samsung/idma.h
+++ b/sound/soc/samsung/idma.h
@@ -1,14 +1,7 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * sound/soc/samsung/idma.h
3 *
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd 3 * Copyright (c) 2011 Samsung Electronics Co., Ltd
5 * http://www.samsung.com 4 * http://www.samsung.com
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */ 5 */
13 6
14#ifndef __SND_SOC_SAMSUNG_IDMA_H_ 7#ifndef __SND_SOC_SAMSUNG_IDMA_H_
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 529b10dc532b..f05f9e03f07d 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -1,15 +1,10 @@
1/* sound/soc/samsung/jive_wm8750.c 1// SPDX-License-Identifier: GPL-2.0
2 * 2//
3 * Copyright 2007,2008 Simtec Electronics 3// Copyright 2007,2008 Simtec Electronics
4 * 4//
5 * Based on sound/soc/pxa/spitz.c 5// Based on sound/soc/pxa/spitz.c
6 * Copyright 2005 Wolfson Microelectronics PLC. 6// Copyright 2005 Wolfson Microelectronics PLC.
7 * Copyright 2005 Openedhand Ltd. 7// Copyright 2005 Openedhand Ltd.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13 8
14#include <linux/module.h> 9#include <linux/module.h>
15#include <sound/soc.h> 10#include <sound/soc.h>
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index 087f8d738dfb..cd70b06cc99d 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -1,13 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Littlemill audio support 2//
3 * 3// Littlemill audio support
4 * Copyright 2011 Wolfson Microelectronics 4//
5 * 5// Copyright 2011 Wolfson Microelectronics
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11 6
12#include <sound/soc.h> 7#include <sound/soc.h>
13#include <sound/soc-dapm.h> 8#include <sound/soc-dapm.h>
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index c9081f42f373..2fdab2ac8e8c 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -1,13 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Lowland audio support 2//
3 * 3// Lowland audio support
4 * Copyright 2011 Wolfson Microelectronics 4//
5 * 5// Copyright 2011 Wolfson Microelectronics
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11 6
12#include <sound/soc.h> 7#include <sound/soc.h>
13#include <sound/soc-dapm.h> 8#include <sound/soc-dapm.h>
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 65602b935377..7e625066ddcd 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -1,18 +1,13 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices 2//
3 * 3// neo1973_wm8753.c - SoC audio for Openmoko Neo1973 and Freerunner devices
4 * Copyright 2007 Openmoko Inc 4//
5 * Author: Graeme Gregory <graeme@openmoko.org> 5// Copyright 2007 Openmoko Inc
6 * Copyright 2007 Wolfson Microelectronics PLC. 6// Author: Graeme Gregory <graeme@openmoko.org>
7 * Author: Graeme Gregory 7// Copyright 2007 Wolfson Microelectronics PLC.
8 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 8// Author: Graeme Gregory
9 * Copyright 2009 Wolfson Microelectronics 9// graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
10 * 10// Copyright 2009 Wolfson Microelectronics
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16 11
17#include <linux/module.h> 12#include <linux/module.h>
18#include <linux/platform_device.h> 13#include <linux/platform_device.h>
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index 1dc54c4206f0..e688169ff12a 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -1,10 +1,6 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * Copyright (C) 2017 Samsung Electronics Co., Ltd. 2//
3 * 3// Copyright (C) 2017 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8 4
9#include <linux/clk.h> 5#include <linux/clk.h>
10#include <linux/clk-provider.h> 6#include <linux/clk-provider.h>
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 3c7baa561084..f6e67d0e7882 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -1,15 +1,10 @@
1/* sound/soc/samsung/pcm.c 1// SPDX-License-Identifier: GPL-2.0
2 * 2//
3 * ALSA SoC Audio Layer - S3C PCM-Controller driver 3// ALSA SoC Audio Layer - S3C PCM-Controller driver
4 * 4//
5 * Copyright (c) 2009 Samsung Electronics Co. Ltd 5// Copyright (c) 2009 Samsung Electronics Co. Ltd
6 * Author: Jaswinder Singh <jassisinghbrar@gmail.com> 6// Author: Jaswinder Singh <jassisinghbrar@gmail.com>
7 * based upon I2S drivers by Ben Dooks. 7// based upon I2S drivers by Ben Dooks.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13 8
14#include <linux/clk.h> 9#include <linux/clk.h>
15#include <linux/io.h> 10#include <linux/io.h>
diff --git a/sound/soc/samsung/pcm.h b/sound/soc/samsung/pcm.h
index 726baf814613..208d8da27de1 100644
--- a/sound/soc/samsung/pcm.h
+++ b/sound/soc/samsung/pcm.h
@@ -1,10 +1,4 @@
1/* sound/soc/samsung/pcm.h 1/* SPDX-License-Identifier: GPL-2.0 */
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 *
7 */
8 2
9#ifndef __S3C_PCM_H 3#ifndef __S3C_PCM_H
10#define __S3C_PCM_H __FILE__ 4#define __S3C_PCM_H __FILE__
diff --git a/sound/soc/samsung/regs-i2s-v2.h b/sound/soc/samsung/regs-i2s-v2.h
index 5e5e5680580b..867984e75709 100644
--- a/sound/soc/samsung/regs-i2s-v2.h
+++ b/sound/soc/samsung/regs-i2s-v2.h
@@ -1,14 +1,10 @@
1/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h 1/* SPDX-License-Identifier: GPL-2.0 */
2 * 2/*
3 * Copyright 2007 Simtec Electronics <linux@simtec.co.uk> 3 * Copyright 2007 Simtec Electronics <linux@simtec.co.uk>
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * S3C2412 IIS register definition 6 * S3C2412 IIS register definition
11*/ 7 */
12 8
13#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H 9#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
14#define __ASM_ARCH_REGS_S3C2412_IIS_H 10#define __ASM_ARCH_REGS_S3C2412_IIS_H
diff --git a/sound/soc/samsung/regs-iis.h b/sound/soc/samsung/regs-iis.h
index dc6cbbe9c4f0..253e172ad3b6 100644
--- a/sound/soc/samsung/regs-iis.h
+++ b/sound/soc/samsung/regs-iis.h
@@ -1,13 +1,10 @@
1/* SPDX-License-Identifier: GPL-2.0 */
1/* 2/*
2 * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> 3 * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
3 * http://www.simtec.co.uk/products/SWLINUX/ 4 * http://www.simtec.co.uk/products/SWLINUX/
4 * 5 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * S3C2410 IIS register definition 6 * S3C2410 IIS register definition
10*/ 7 */
11 8
12#ifndef __SAMSUNG_REGS_IIS_H__ 9#ifndef __SAMSUNG_REGS_IIS_H__
13#define __SAMSUNG_REGS_IIS_H__ 10#define __SAMSUNG_REGS_IIS_H__
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index a064ca7d78c3..1dcc1b252ad1 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -1,21 +1,15 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * rx1950.c -- ALSA Soc Audio Layer 2//
3 * 3// rx1950.c - ALSA SoC Audio Layer
4 * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com> 4//
5 * 5// Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
6 * Based on smdk2440.c and magician.c 6//
7 * 7// Based on smdk2440.c and magician.c
8 * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com 8//
9 * Philipp Zabel <philipp.zabel@gmail.com> 9// Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
10 * Denis Grigoriev <dgreenday@gmail.com> 10// Philipp Zabel <philipp.zabel@gmail.com>
11 * Vasily Khoruzhick <anarsoul@gmail.com> 11// Denis Grigoriev <dgreenday@gmail.com>
12 * 12// Vasily Khoruzhick <anarsoul@gmail.com>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18 */
19 13
20#include <linux/types.h> 14#include <linux/types.h>
21#include <linux/gpio.h> 15#include <linux/gpio.h>
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 58c3e9bfc6b7..7e196b599be1 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -1,18 +1,14 @@
1/* ALSA Soc Audio Layer - I2S core for newer Samsung SoCs. 1// SPDX-License-Identifier: GPL-2.0+
2 * 2//
3 * Copyright (c) 2006 Wolfson Microelectronics PLC. 3// ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
4 * Graeme Gregory graeme.gregory@wolfsonmicro.com 4//
5 * linux@wolfsonmicro.com 5// Copyright (c) 2006 Wolfson Microelectronics PLC.
6 * 6// Graeme Gregory graeme.gregory@wolfsonmicro.com
7 * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics 7// linux@wolfsonmicro.com
8 * http://armlinux.simtec.co.uk/ 8//
9 * Ben Dooks <ben@simtec.co.uk> 9// Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
10 * 10// http://armlinux.simtec.co.uk/
11 * This program is free software; you can redistribute it and/or modify it 11// Ben Dooks <ben@simtec.co.uk>
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16 12
17#include <linux/module.h> 13#include <linux/module.h>
18#include <linux/delay.h> 14#include <linux/delay.h>
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
index 3fca20f7a853..fe42b77999fd 100644
--- a/sound/soc/samsung/s3c-i2s-v2.h
+++ b/sound/soc/samsung/s3c-i2s-v2.h
@@ -1,16 +1,11 @@
1/* sound/soc/samsung/s3c-i2s-v2.h 1/* SPDX-License-Identifier: GPL-2.0+ */
2 * 2/*
3 * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver 3 * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
4 * 4 *
5 * Copyright (c) 2007 Simtec Electronics 5 * Copyright (c) 2007 Simtec Electronics
6 * http://armlinux.simtec.co.uk/ 6 * http://armlinux.simtec.co.uk/
7 * Ben Dooks <ben@simtec.co.uk> 7 * Ben Dooks <ben@simtec.co.uk>
8 * 8 */
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13*/
14 9
15/* This code is the core support for the I2S block found in a number of 10/* This code is the core support for the I2S block found in a number of
16 * Samsung SoC devices which is unofficially named I2S-V2. Currently the 11 * Samsung SoC devices which is unofficially named I2S-V2. Currently the
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index c08638b0e458..787a3f6e9f24 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -1,20 +1,14 @@
1/* sound/soc/samsung/s3c2412-i2s.c 1// SPDX-License-Identifier: GPL-2.0+
2 * 2//
3 * ALSA Soc Audio Layer - S3C2412 I2S driver 3// ALSA Soc Audio Layer - S3C2412 I2S driver
4 * 4//
5 * Copyright (c) 2006 Wolfson Microelectronics PLC. 5// Copyright (c) 2006 Wolfson Microelectronics PLC.
6 * Graeme Gregory graeme.gregory@wolfsonmicro.com 6// Graeme Gregory graeme.gregory@wolfsonmicro.com
7 * linux@wolfsonmicro.com 7// linux@wolfsonmicro.com
8 * 8//
9 * Copyright (c) 2007, 2004-2005 Simtec Electronics 9// Copyright (c) 2007, 2004-2005 Simtec Electronics
10 * http://armlinux.simtec.co.uk/ 10// http://armlinux.simtec.co.uk/
11 * Ben Dooks <ben@simtec.co.uk> 11// Ben Dooks <ben@simtec.co.uk>
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 */
18 12
19#include <linux/delay.h> 13#include <linux/delay.h>
20#include <linux/gpio.h> 14#include <linux/gpio.h>
diff --git a/sound/soc/samsung/s3c2412-i2s.h b/sound/soc/samsung/s3c2412-i2s.h
index 02ad5794c0a9..bff2a797cb08 100644
--- a/sound/soc/samsung/s3c2412-i2s.h
+++ b/sound/soc/samsung/s3c2412-i2s.h
@@ -1,16 +1,11 @@
1/* sound/soc/samsung/s3c2412-i2s.c 1/* SPDX-License-Identifier: GPL-2.0+ */
2 * 2/*
3 * ALSA Soc Audio Layer - S3C2412 I2S driver 3 * ALSA Soc Audio Layer - S3C2412 I2S driver
4 * 4 *
5 * Copyright (c) 2007 Simtec Electronics 5 * Copyright (c) 2007 Simtec Electronics
6 * http://armlinux.simtec.co.uk/ 6 * http://armlinux.simtec.co.uk/
7 * Ben Dooks <ben@simtec.co.uk> 7 * Ben Dooks <ben@simtec.co.uk>
8 * 8 */
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13*/
14 9
15#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H 10#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
16#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__ 11#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index a8026b640c95..92bdaf0878f8 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -1,18 +1,13 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * s3c24xx-i2s.c -- ALSA Soc Audio Layer 2//
3 * 3// s3c24xx-i2s.c -- ALSA Soc Audio Layer
4 * (c) 2006 Wolfson Microelectronics PLC. 4//
5 * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 5// (c) 2006 Wolfson Microelectronics PLC.
6 * 6// Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
7 * Copyright 2004-2005 Simtec Electronics 7//
8 * http://armlinux.simtec.co.uk/ 8// Copyright 2004-2005 Simtec Electronics
9 * Ben Dooks <ben@simtec.co.uk> 9// http://armlinux.simtec.co.uk/
10 * 10// Ben Dooks <ben@simtec.co.uk>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16 11
17#include <linux/delay.h> 12#include <linux/delay.h>
18#include <linux/clk.h> 13#include <linux/clk.h>
diff --git a/sound/soc/samsung/s3c24xx-i2s.h b/sound/soc/samsung/s3c24xx-i2s.h
index f9ca04edacb7..e073e31855d0 100644
--- a/sound/soc/samsung/s3c24xx-i2s.h
+++ b/sound/soc/samsung/s3c24xx-i2s.h
@@ -1,3 +1,4 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
1/* 2/*
2 * s3c24xx-i2s.c -- ALSA Soc Audio Layer 3 * s3c24xx-i2s.c -- ALSA Soc Audio Layer
3 * 4 *
@@ -5,11 +6,6 @@
5 * Author: Graeme Gregory 6 * Author: Graeme Gregory
6 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 7 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * Revision history 9 * Revision history
14 * 10th Nov 2006 Initial version. 10 * 10th Nov 2006 Initial version.
15 */ 11 */
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
index 6de63f3e37d5..4543705b8d87 100644
--- a/sound/soc/samsung/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -1,11 +1,6 @@
1/* sound/soc/samsung/s3c24xx_simtec.c 1// SPDX-License-Identifier: GPL-2.0
2 * 2//
3 * Copyright 2009 Simtec Electronics 3// Copyright 2009 Simtec Electronics
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8*/
9 4
10#include <linux/gpio.h> 5#include <linux/gpio.h>
11#include <linux/clk.h> 6#include <linux/clk.h>
diff --git a/sound/soc/samsung/s3c24xx_simtec.h b/sound/soc/samsung/s3c24xx_simtec.h
index 8270748a2c41..38d8384755cd 100644
--- a/sound/soc/samsung/s3c24xx_simtec.h
+++ b/sound/soc/samsung/s3c24xx_simtec.h
@@ -1,11 +1,7 @@
1/* sound/soc/samsung/s3c24xx_simtec.h 1/* SPDX-License-Identifier: GPL-2.0 */
2 * 2/*
3 * Copyright 2009 Simtec Electronics 3 * Copyright 2009 Simtec Electronics
4 * 4 */
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8*/
9 5
10extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd); 6extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
11 7
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
index 7ac924c595bf..e3528e74a338 100644
--- a/sound/soc/samsung/s3c24xx_simtec_hermes.c
+++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c
@@ -1,11 +1,6 @@
1/* sound/soc/samsung/s3c24xx_simtec_hermes.c 1// SPDX-License-Identifier: GPL-2.0
2 * 2//
3 * Copyright 2009 Simtec Electronics 3// Copyright 2009 Simtec Electronics
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8*/
9 4
10#include <linux/module.h> 5#include <linux/module.h>
11#include <sound/soc.h> 6#include <sound/soc.h>
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
index b4ed2fc1a65c..1360b881400d 100644
--- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
@@ -1,11 +1,6 @@
1/* sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c 1// SPDX-License-Identifier: GPL-2.0
2 * 2//
3 * Copyright 2009 Simtec Electronics 3// Copyright 2009 Simtec Electronics
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8*/
9 4
10#include <linux/module.h> 5#include <linux/module.h>
11#include <sound/soc.h> 6#include <sound/soc.h>
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 5fb3bab6bbfe..9d68f8ca1fcc 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -1,15 +1,11 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * Modifications by Christian Pellegrin <chripell@evolware.org> 2//
3 * 3// Modifications by Christian Pellegrin <chripell@evolware.org>
4 * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver 4//
5 * 5// s3c24xx_uda134x.c - S3C24XX_UDA134X ALSA SoC Audio board driver
6 * Copyright 2007 Dension Audio Systems Ltd. 6//
7 * Author: Zoltan Devai 7// Copyright 2007 Dension Audio Systems Ltd.
8 * 8// Author: Zoltan Devai
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13 9
14#include <linux/clk.h> 10#include <linux/clk.h>
15#include <linux/gpio.h> 11#include <linux/gpio.h>
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index cf0f54e652c1..b9e887ea60b2 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -1,17 +1,10 @@
1/* sound/soc/samsung/smartq_wm8987.c 1// SPDX-License-Identifier: GPL-2.0+
2 * 2//
3 * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com> 3// Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com>
4 * 4//
5 * Based on smdk6410_wm8987.c 5// Based on smdk6410_wm8987.c
6 * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com 6// Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com
7 * Graeme Gregory - graeme.gregory@wolfsonmicro.com 7// Graeme Gregory - graeme.gregory@wolfsonmicro.com
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15 8
16#include <linux/gpio/consumer.h> 9#include <linux/gpio/consumer.h>
17#include <linux/module.h> 10#include <linux/module.h>
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index 7fc7cc6d1530..87a70d872c00 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -1,14 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * smdk_spdif.c -- S/PDIF audio for SMDK 2//
3 * 3// smdk_spdif.c - S/PDIF audio for SMDK
4 * Copyright 2010 Samsung Electronics Co. Ltd. 4//
5 * 5// Copyright (C) 2010 Samsung Electronics Co., Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 */
12 6
13#include <linux/clk.h> 7#include <linux/clk.h>
14#include <linux/module.h> 8#include <linux/module.h>
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
index 6e4dfa7e2c89..987807e6f8c3 100644
--- a/sound/soc/samsung/smdk_wm8580.c
+++ b/sound/soc/samsung/smdk_wm8580.c
@@ -1,14 +1,7 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * smdk_wm8580.c 2//
3 * 3// Copyright (c) 2009 Samsung Electronics Co. Ltd
4 * Copyright (c) 2009 Samsung Electronics Co. Ltd 4// Author: Jaswinder Singh <jassisinghbrar@gmail.com>
5 * Author: Jaswinder Singh <jassisinghbrar@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12 5
13#include <linux/module.h> 6#include <linux/module.h>
14#include <sound/soc.h> 7#include <sound/soc.h>
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index ff57b192d37d..135d8c2745be 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -1,11 +1,4 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * smdk_wm8994.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 */
9 2
10#include "../codecs/wm8994.h" 3#include "../codecs/wm8994.h"
11#include <sound/pcm_params.h> 4#include <sound/pcm_params.h>
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
index 2e621496be8b..43171d6457fa 100644
--- a/sound/soc/samsung/smdk_wm8994pcm.c
+++ b/sound/soc/samsung/smdk_wm8994pcm.c
@@ -1,14 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * sound/soc/samsung/smdk_wm8994pcm.c 2//
3 * 3// Copyright (c) 2011 Samsung Electronics Co., Ltd
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd 4// http://www.samsung.com
5 * http://www.samsung.com 5
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12#include <linux/module.h> 6#include <linux/module.h>
13#include <sound/soc.h> 7#include <sound/soc.h>
14#include <sound/pcm.h> 8#include <sound/pcm.h>
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 5d8efc2d5c38..57ce90fe5004 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -1,15 +1,6 @@
1/* 1// SPDX-License-Identifier: GPL-2.0
2 * ASoC machine driver for Snow boards 2//
3 * 3// ASoC machine driver for Snow boards
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 */
13 4
14#include <linux/clk.h> 5#include <linux/clk.h>
15#include <linux/module.h> 6#include <linux/module.h>
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 5e4afb330416..805c57986e0b 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -1,14 +1,9 @@
1/* sound/soc/samsung/spdif.c 1// SPDX-License-Identifier: GPL-2.0
2 * 2//
3 * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver 3// ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
4 * 4//
5 * Copyright (c) 2010 Samsung Electronics Co. Ltd 5// Copyright (c) 2010 Samsung Electronics Co. Ltd
6 * http://www.samsung.com/ 6// http://www.samsung.com/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12 7
13#include <linux/clk.h> 8#include <linux/clk.h>
14#include <linux/io.h> 9#include <linux/io.h>
diff --git a/sound/soc/samsung/spdif.h b/sound/soc/samsung/spdif.h
index 4f72cb446dbf..461da60ab040 100644
--- a/sound/soc/samsung/spdif.h
+++ b/sound/soc/samsung/spdif.h
@@ -1,13 +1,9 @@
1/* sound/soc/samsung/spdif.h 1/* SPDX-License-Identifier: GPL-2.0 */
2 * 2/*
3 * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver 3 * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
4 * 4 *
5 * Copyright (c) 2010 Samsung Electronics Co. Ltd 5 * Copyright (c) 2010 Samsung Electronics Co. Ltd
6 * http://www.samsung.com/ 6 * http://www.samsung.com/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */ 7 */
12 8
13#ifndef __SND_SOC_SAMSUNG_SPDIF_H 9#ifndef __SND_SOC_SAMSUNG_SPDIF_H
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 4b4147d07804..15465c84daa3 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -1,13 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Speyside audio support 2//
3 * 3// Speyside audio support
4 * Copyright 2011 Wolfson Microelectronics 4//
5 * 5// Copyright 2011 Wolfson Microelectronics
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11 6
12#include <sound/soc.h> 7#include <sound/soc.h>
13#include <sound/soc-dapm.h> 8#include <sound/soc-dapm.h>
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index dc93941e01c3..31f4256c6c65 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -1,14 +1,9 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd. 2//
3 * 3// Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
4 * Authors: Inha Song <ideal.song@samsung.com> 4//
5 * Sylwester Nawrocki <s.nawrocki@samsung.com> 5// Authors: Inha Song <ideal.song@samsung.com>
6 * 6// Sylwester Nawrocki <s.nawrocki@samsung.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12 7
13#include <linux/clk.h> 8#include <linux/clk.h>
14#include <linux/gpio.h> 9#include <linux/gpio.h>
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 998727cb4c31..14b11acb12a4 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -1,13 +1,8 @@
1/* 1// SPDX-License-Identifier: GPL-2.0+
2 * Tobermory audio support 2//
3 * 3// Tobermory audio support
4 * Copyright 2011 Wolfson Microelectronics 4//
5 * 5// Copyright 2011 Wolfson Microelectronics
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11 6
12#include <sound/soc.h> 7#include <sound/soc.h>
13#include <sound/soc-dapm.h> 8#include <sound/soc-dapm.h>
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 4fe83e611c01..37cb61553d5f 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -300,6 +300,18 @@ int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
300 return chan; 300 return chan;
301} 301}
302 302
303int rsnd_channel_normalization(int chan)
304{
305 if ((chan > 8) || (chan < 0))
306 return 0;
307
308 /* TDM Extend Mode needs 8ch */
309 if (chan == 6)
310 chan = 8;
311
312 return chan;
313}
314
303int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, 315int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
304 struct snd_pcm_hw_params *params) 316 struct snd_pcm_hw_params *params)
305{ 317{
@@ -312,11 +324,7 @@ int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
312 if (rsnd_runtime_is_multi_ssi(io)) 324 if (rsnd_runtime_is_multi_ssi(io))
313 chan /= rsnd_rdai_ssi_lane_get(rdai); 325 chan /= rsnd_rdai_ssi_lane_get(rdai);
314 326
315 /* TDM Extend Mode needs 8ch */ 327 return rsnd_channel_normalization(chan);
316 if (chan == 6)
317 chan = 8;
318
319 return chan;
320} 328}
321 329
322int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) 330int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io)
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 0e6ef4e18400..7727add3eb1a 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -446,6 +446,7 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
446 struct device_node *playback, 446 struct device_node *playback,
447 struct device_node *capture); 447 struct device_node *capture);
448 448
449int rsnd_channel_normalization(int chan);
449#define rsnd_runtime_channel_original(io) \ 450#define rsnd_runtime_channel_original(io) \
450 rsnd_runtime_channel_original_with_params(io, NULL) 451 rsnd_runtime_channel_original_with_params(io, NULL)
451int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, 452int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index f5afab631abb..44bda210256e 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -303,6 +303,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
303 if (rsnd_runtime_is_tdm_split(io)) 303 if (rsnd_runtime_is_tdm_split(io))
304 chan = rsnd_io_converted_chan(io); 304 chan = rsnd_io_converted_chan(io);
305 305
306 chan = rsnd_channel_normalization(chan);
307
306 main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); 308 main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
307 if (!main_rate) { 309 if (!main_rate) {
308 dev_err(dev, "unsupported clock rate\n"); 310 dev_err(dev, "unsupported clock rate\n");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 46e3ab0fced4..2403bec2fccf 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1974,10 +1974,13 @@ static void soc_check_tplg_fes(struct snd_soc_card *card)
1974 continue; 1974 continue;
1975 1975
1976 /* for this machine ? */ 1976 /* for this machine ? */
1977 if (!strcmp(component->driver->ignore_machine,
1978 card->dev->driver->name))
1979 goto match;
1977 if (strcmp(component->driver->ignore_machine, 1980 if (strcmp(component->driver->ignore_machine,
1978 card->dev->driver->name)) 1981 dev_name(card->dev)))
1979 continue; 1982 continue;
1980 1983match:
1981 /* machine matches, so override the rtd data */ 1984 /* machine matches, so override the rtd data */
1982 for_each_card_prelinks(card, i, dai_link) { 1985 for_each_card_prelinks(card, i, dai_link) {
1983 1986
@@ -2828,10 +2831,21 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
2828 2831
2829static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) 2832static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister)
2830{ 2833{
2834 struct snd_soc_pcm_runtime *rtd;
2835 int order;
2836
2831 if (card->instantiated) { 2837 if (card->instantiated) {
2832 card->instantiated = false; 2838 card->instantiated = false;
2833 snd_soc_dapm_shutdown(card); 2839 snd_soc_dapm_shutdown(card);
2834 snd_soc_flush_all_delayed_work(card); 2840 snd_soc_flush_all_delayed_work(card);
2841
2842 /* remove all components used by DAI links on this card */
2843 for_each_comp_order(order) {
2844 for_each_card_rtds(card, rtd) {
2845 soc_remove_link_components(card, rtd, order);
2846 }
2847 }
2848
2835 soc_cleanup_card_resources(card); 2849 soc_cleanup_card_resources(card);
2836 if (!unregister) 2850 if (!unregister)
2837 list_add(&card->list, &unbind_card_list); 2851 list_add(&card->list, &unbind_card_list);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 0382a47b30bd..81a7a12196ff 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -883,6 +883,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
883 case snd_soc_dapm_switch: 883 case snd_soc_dapm_switch:
884 case snd_soc_dapm_mixer: 884 case snd_soc_dapm_mixer:
885 case snd_soc_dapm_pga: 885 case snd_soc_dapm_pga:
886 case snd_soc_dapm_effect:
886 case snd_soc_dapm_out_drv: 887 case snd_soc_dapm_out_drv:
887 wname_in_long_name = true; 888 wname_in_long_name = true;
888 kcname_in_long_name = true; 889 kcname_in_long_name = true;
@@ -2370,6 +2371,7 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2370 case snd_soc_dapm_dac: 2371 case snd_soc_dapm_dac:
2371 case snd_soc_dapm_adc: 2372 case snd_soc_dapm_adc:
2372 case snd_soc_dapm_pga: 2373 case snd_soc_dapm_pga:
2374 case snd_soc_dapm_effect:
2373 case snd_soc_dapm_out_drv: 2375 case snd_soc_dapm_out_drv:
2374 case snd_soc_dapm_mixer: 2376 case snd_soc_dapm_mixer:
2375 case snd_soc_dapm_mixer_named_ctl: 2377 case snd_soc_dapm_mixer_named_ctl:
@@ -3197,6 +3199,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
3197 dapm_new_mux(w); 3199 dapm_new_mux(w);
3198 break; 3200 break;
3199 case snd_soc_dapm_pga: 3201 case snd_soc_dapm_pga:
3202 case snd_soc_dapm_effect:
3200 case snd_soc_dapm_out_drv: 3203 case snd_soc_dapm_out_drv:
3201 dapm_new_pga(w); 3204 dapm_new_pga(w);
3202 break; 3205 break;
@@ -4049,7 +4052,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
4049 struct snd_soc_dapm_widget template; 4052 struct snd_soc_dapm_widget template;
4050 struct snd_soc_dapm_widget *w; 4053 struct snd_soc_dapm_widget *w;
4051 const char **w_param_text; 4054 const char **w_param_text;
4052 unsigned long private_value; 4055 unsigned long private_value = 0;
4053 char *link_name; 4056 char *link_name;
4054 int ret; 4057 int ret;
4055 4058
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index be80a12fba27..0a4f60c7a188 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -43,8 +43,8 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream)
43 else 43 else
44 codec_stream = &dai->driver->capture; 44 codec_stream = &dai->driver->capture;
45 45
46 /* If the codec specifies any rate at all, it supports the stream. */ 46 /* If the codec specifies any channels at all, it supports the stream */
47 return codec_stream->rates; 47 return codec_stream->channels_min;
48} 48}
49 49
50/** 50/**
@@ -1033,6 +1033,9 @@ interface_err:
1033 1033
1034codec_err: 1034codec_err:
1035 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { 1035 for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) {
1036 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1037 continue;
1038
1036 if (codec_dai->driver->ops->hw_free) 1039 if (codec_dai->driver->ops->hw_free)
1037 codec_dai->driver->ops->hw_free(substream, codec_dai); 1040 codec_dai->driver->ops->hw_free(substream, codec_dai);
1038 codec_dai->rate = 0; 1041 codec_dai->rate = 0;
@@ -1090,6 +1093,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
1090 1093
1091 /* now free hw params for the DAIs */ 1094 /* now free hw params for the DAIs */
1092 for_each_rtd_codec_dai(rtd, i, codec_dai) { 1095 for_each_rtd_codec_dai(rtd, i, codec_dai) {
1096 if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
1097 continue;
1098
1093 if (codec_dai->driver->ops->hw_free) 1099 if (codec_dai->driver->ops->hw_free)
1094 codec_dai->driver->ops->hw_free(substream, codec_dai); 1100 codec_dai->driver->ops->hw_free(substream, codec_dai);
1095 } 1101 }
@@ -2166,6 +2172,10 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
2166 } 2172 }
2167 } 2173 }
2168 2174
2175 /* copy the fixed-up hw params for BE dai */
2176 memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
2177 sizeof(struct snd_pcm_hw_params));
2178
2169 /* only allow hw_params() if no connected FEs are running */ 2179 /* only allow hw_params() if no connected FEs are running */
2170 if (!snd_soc_dpcm_can_be_params(fe, be, stream)) 2180 if (!snd_soc_dpcm_can_be_params(fe, be, stream))
2171 continue; 2181 continue;
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 96852d250619..3299ebb48c1a 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -30,6 +30,8 @@
30#include <sound/soc-topology.h> 30#include <sound/soc-topology.h>
31#include <sound/tlv.h> 31#include <sound/tlv.h>
32 32
33#define SOC_TPLG_MAGIC_BIG_ENDIAN 0x436F5341 /* ASoC in reverse */
34
33/* 35/*
34 * We make several passes over the data (since it wont necessarily be ordered) 36 * We make several passes over the data (since it wont necessarily be ordered)
35 * and process objects in the following order. This guarantees the component 37 * and process objects in the following order. This guarantees the component
@@ -197,8 +199,8 @@ static int tplc_chan_get_reg(struct soc_tplg *tplg,
197 int i; 199 int i;
198 200
199 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { 201 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
200 if (chan[i].id == map) 202 if (le32_to_cpu(chan[i].id) == map)
201 return chan[i].reg; 203 return le32_to_cpu(chan[i].reg);
202 } 204 }
203 205
204 return -EINVAL; 206 return -EINVAL;
@@ -210,8 +212,8 @@ static int tplc_chan_get_shift(struct soc_tplg *tplg,
210 int i; 212 int i;
211 213
212 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { 214 for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) {
213 if (chan[i].id == map) 215 if (le32_to_cpu(chan[i].id) == map)
214 return chan[i].shift; 216 return le32_to_cpu(chan[i].shift);
215 } 217 }
216 218
217 return -EINVAL; 219 return -EINVAL;
@@ -536,6 +538,8 @@ static void remove_dai(struct snd_soc_component *comp,
536 if (dai->driver == dai_drv) 538 if (dai->driver == dai_drv)
537 dai->driver = NULL; 539 dai->driver = NULL;
538 540
541 kfree(dai_drv->playback.stream_name);
542 kfree(dai_drv->capture.stream_name);
539 kfree(dai_drv->name); 543 kfree(dai_drv->name);
540 list_del(&dobj->list); 544 list_del(&dobj->list);
541 kfree(dai_drv); 545 kfree(dai_drv);
@@ -591,7 +595,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
591 const struct snd_soc_tplg_bytes_ext_ops *ext_ops; 595 const struct snd_soc_tplg_bytes_ext_ops *ext_ops;
592 int num_ops, i; 596 int num_ops, i;
593 597
594 if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES 598 if (le32_to_cpu(hdr->ops.info) == SND_SOC_TPLG_CTL_BYTES
595 && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER 599 && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER
596 && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE 600 && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
597 && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { 601 && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
@@ -707,9 +711,9 @@ static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg,
707 711
708 p[0] = SNDRV_CTL_TLVT_DB_SCALE; 712 p[0] = SNDRV_CTL_TLVT_DB_SCALE;
709 p[1] = item_len; 713 p[1] = item_len;
710 p[2] = scale->min; 714 p[2] = le32_to_cpu(scale->min);
711 p[3] = (scale->step & TLV_DB_SCALE_MASK) 715 p[3] = (le32_to_cpu(scale->step) & TLV_DB_SCALE_MASK)
712 | (scale->mute ? TLV_DB_SCALE_MUTE : 0); 716 | (le32_to_cpu(scale->mute) ? TLV_DB_SCALE_MUTE : 0);
713 717
714 kc->tlv.p = (void *)p; 718 kc->tlv.p = (void *)p;
715 return 0; 719 return 0;
@@ -719,13 +723,14 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg,
719 struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc) 723 struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc)
720{ 724{
721 struct snd_soc_tplg_ctl_tlv *tplg_tlv; 725 struct snd_soc_tplg_ctl_tlv *tplg_tlv;
726 u32 access = le32_to_cpu(tc->access);
722 727
723 if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) 728 if (!(access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE))
724 return 0; 729 return 0;
725 730
726 if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { 731 if (!(access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
727 tplg_tlv = &tc->tlv; 732 tplg_tlv = &tc->tlv;
728 switch (tplg_tlv->type) { 733 switch (le32_to_cpu(tplg_tlv->type)) {
729 case SNDRV_CTL_TLVT_DB_SCALE: 734 case SNDRV_CTL_TLVT_DB_SCALE:
730 return soc_tplg_create_tlv_db_scale(tplg, kc, 735 return soc_tplg_create_tlv_db_scale(tplg, kc,
731 &tplg_tlv->scale); 736 &tplg_tlv->scale);
@@ -776,7 +781,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
776 return -ENOMEM; 781 return -ENOMEM;
777 782
778 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + 783 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
779 be->priv.size); 784 le32_to_cpu(be->priv.size));
780 785
781 dev_dbg(tplg->dev, 786 dev_dbg(tplg->dev,
782 "ASoC: adding bytes kcontrol %s with access 0x%x\n", 787 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
@@ -786,9 +791,9 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count,
786 kc.name = be->hdr.name; 791 kc.name = be->hdr.name;
787 kc.private_value = (long)sbe; 792 kc.private_value = (long)sbe;
788 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 793 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
789 kc.access = be->hdr.access; 794 kc.access = le32_to_cpu(be->hdr.access);
790 795
791 sbe->max = be->max; 796 sbe->max = le32_to_cpu(be->max);
792 sbe->dobj.type = SND_SOC_DOBJ_BYTES; 797 sbe->dobj.type = SND_SOC_DOBJ_BYTES;
793 sbe->dobj.ops = tplg->ops; 798 sbe->dobj.ops = tplg->ops;
794 INIT_LIST_HEAD(&sbe->dobj.list); 799 INIT_LIST_HEAD(&sbe->dobj.list);
@@ -856,7 +861,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
856 if (sm == NULL) 861 if (sm == NULL)
857 return -ENOMEM; 862 return -ENOMEM;
858 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + 863 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
859 mc->priv.size); 864 le32_to_cpu(mc->priv.size));
860 865
861 dev_dbg(tplg->dev, 866 dev_dbg(tplg->dev,
862 "ASoC: adding mixer kcontrol %s with access 0x%x\n", 867 "ASoC: adding mixer kcontrol %s with access 0x%x\n",
@@ -866,7 +871,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
866 kc.name = mc->hdr.name; 871 kc.name = mc->hdr.name;
867 kc.private_value = (long)sm; 872 kc.private_value = (long)sm;
868 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 873 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
869 kc.access = mc->hdr.access; 874 kc.access = le32_to_cpu(mc->hdr.access);
870 875
871 /* we only support FL/FR channel mapping atm */ 876 /* we only support FL/FR channel mapping atm */
872 sm->reg = tplc_chan_get_reg(tplg, mc->channel, 877 sm->reg = tplc_chan_get_reg(tplg, mc->channel,
@@ -878,10 +883,10 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
878 sm->rshift = tplc_chan_get_shift(tplg, mc->channel, 883 sm->rshift = tplc_chan_get_shift(tplg, mc->channel,
879 SNDRV_CHMAP_FR); 884 SNDRV_CHMAP_FR);
880 885
881 sm->max = mc->max; 886 sm->max = le32_to_cpu(mc->max);
882 sm->min = mc->min; 887 sm->min = le32_to_cpu(mc->min);
883 sm->invert = mc->invert; 888 sm->invert = le32_to_cpu(mc->invert);
884 sm->platform_max = mc->platform_max; 889 sm->platform_max = le32_to_cpu(mc->platform_max);
885 sm->dobj.index = tplg->index; 890 sm->dobj.index = tplg->index;
886 sm->dobj.ops = tplg->ops; 891 sm->dobj.ops = tplg->ops;
887 sm->dobj.type = SND_SOC_DOBJ_MIXER; 892 sm->dobj.type = SND_SOC_DOBJ_MIXER;
@@ -895,19 +900,20 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count,
895 continue; 900 continue;
896 } 901 }
897 902
903 /* create any TLV data */
904 soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
905
898 /* pass control to driver for optional further init */ 906 /* pass control to driver for optional further init */
899 err = soc_tplg_init_kcontrol(tplg, &kc, 907 err = soc_tplg_init_kcontrol(tplg, &kc,
900 (struct snd_soc_tplg_ctl_hdr *) mc); 908 (struct snd_soc_tplg_ctl_hdr *) mc);
901 if (err < 0) { 909 if (err < 0) {
902 dev_err(tplg->dev, "ASoC: failed to init %s\n", 910 dev_err(tplg->dev, "ASoC: failed to init %s\n",
903 mc->hdr.name); 911 mc->hdr.name);
912 soc_tplg_free_tlv(tplg, &kc);
904 kfree(sm); 913 kfree(sm);
905 continue; 914 continue;
906 } 915 }
907 916
908 /* create any TLV data */
909 soc_tplg_create_tlv(tplg, &kc, &mc->hdr);
910
911 /* register control here */ 917 /* register control here */
912 err = soc_tplg_add_kcontrol(tplg, &kc, 918 err = soc_tplg_add_kcontrol(tplg, &kc,
913 &sm->dobj.control.kcontrol); 919 &sm->dobj.control.kcontrol);
@@ -931,7 +937,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
931 int i, ret; 937 int i, ret;
932 938
933 se->dobj.control.dtexts = 939 se->dobj.control.dtexts =
934 kcalloc(ec->items, sizeof(char *), GFP_KERNEL); 940 kcalloc(le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL);
935 if (se->dobj.control.dtexts == NULL) 941 if (se->dobj.control.dtexts == NULL)
936 return -ENOMEM; 942 return -ENOMEM;
937 943
@@ -963,15 +969,22 @@ err:
963static int soc_tplg_denum_create_values(struct soc_enum *se, 969static int soc_tplg_denum_create_values(struct soc_enum *se,
964 struct snd_soc_tplg_enum_control *ec) 970 struct snd_soc_tplg_enum_control *ec)
965{ 971{
966 if (ec->items > sizeof(*ec->values)) 972 int i;
973
974 if (le32_to_cpu(ec->items) > sizeof(*ec->values))
967 return -EINVAL; 975 return -EINVAL;
968 976
969 se->dobj.control.dvalues = kmemdup(ec->values, 977 se->dobj.control.dvalues = kzalloc(le32_to_cpu(ec->items) *
970 ec->items * sizeof(u32), 978 sizeof(u32),
971 GFP_KERNEL); 979 GFP_KERNEL);
972 if (!se->dobj.control.dvalues) 980 if (!se->dobj.control.dvalues)
973 return -ENOMEM; 981 return -ENOMEM;
974 982
983 /* convert from little-endian */
984 for (i = 0; i < le32_to_cpu(ec->items); i++) {
985 se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]);
986 }
987
975 return 0; 988 return 0;
976} 989}
977 990
@@ -994,8 +1007,6 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
994 1007
995 for (i = 0; i < count; i++) { 1008 for (i = 0; i < count; i++) {
996 ec = (struct snd_soc_tplg_enum_control *)tplg->pos; 1009 ec = (struct snd_soc_tplg_enum_control *)tplg->pos;
997 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
998 ec->priv.size);
999 1010
1000 /* validate kcontrol */ 1011 /* validate kcontrol */
1001 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 1012 if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
@@ -1006,6 +1017,9 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
1006 if (se == NULL) 1017 if (se == NULL)
1007 return -ENOMEM; 1018 return -ENOMEM;
1008 1019
1020 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1021 le32_to_cpu(ec->priv.size));
1022
1009 dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", 1023 dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n",
1010 ec->hdr.name, ec->items); 1024 ec->hdr.name, ec->items);
1011 1025
@@ -1013,7 +1027,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
1013 kc.name = ec->hdr.name; 1027 kc.name = ec->hdr.name;
1014 kc.private_value = (long)se; 1028 kc.private_value = (long)se;
1015 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 1029 kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1016 kc.access = ec->hdr.access; 1030 kc.access = le32_to_cpu(ec->hdr.access);
1017 1031
1018 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); 1032 se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL);
1019 se->shift_l = tplc_chan_get_shift(tplg, ec->channel, 1033 se->shift_l = tplc_chan_get_shift(tplg, ec->channel,
@@ -1021,14 +1035,14 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count,
1021 se->shift_r = tplc_chan_get_shift(tplg, ec->channel, 1035 se->shift_r = tplc_chan_get_shift(tplg, ec->channel,
1022 SNDRV_CHMAP_FL); 1036 SNDRV_CHMAP_FL);
1023 1037
1024 se->items = ec->items; 1038 se->items = le32_to_cpu(ec->items);
1025 se->mask = ec->mask; 1039 se->mask = le32_to_cpu(ec->mask);
1026 se->dobj.index = tplg->index; 1040 se->dobj.index = tplg->index;
1027 se->dobj.type = SND_SOC_DOBJ_ENUM; 1041 se->dobj.type = SND_SOC_DOBJ_ENUM;
1028 se->dobj.ops = tplg->ops; 1042 se->dobj.ops = tplg->ops;
1029 INIT_LIST_HEAD(&se->dobj.list); 1043 INIT_LIST_HEAD(&se->dobj.list);
1030 1044
1031 switch (ec->hdr.ops.info) { 1045 switch (le32_to_cpu(ec->hdr.ops.info)) {
1032 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: 1046 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1033 case SND_SOC_TPLG_CTL_ENUM_VALUE: 1047 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1034 err = soc_tplg_denum_create_values(se, ec); 1048 err = soc_tplg_denum_create_values(se, ec);
@@ -1101,23 +1115,24 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
1101 int i; 1115 int i;
1102 1116
1103 if (tplg->pass != SOC_TPLG_PASS_MIXER) { 1117 if (tplg->pass != SOC_TPLG_PASS_MIXER) {
1104 tplg->pos += hdr->size + hdr->payload_size; 1118 tplg->pos += le32_to_cpu(hdr->size) +
1119 le32_to_cpu(hdr->payload_size);
1105 return 0; 1120 return 0;
1106 } 1121 }
1107 1122
1108 dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count, 1123 dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count,
1109 soc_tplg_get_offset(tplg)); 1124 soc_tplg_get_offset(tplg));
1110 1125
1111 for (i = 0; i < hdr->count; i++) { 1126 for (i = 0; i < le32_to_cpu(hdr->count); i++) {
1112 1127
1113 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; 1128 control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
1114 1129
1115 if (control_hdr->size != sizeof(*control_hdr)) { 1130 if (le32_to_cpu(control_hdr->size) != sizeof(*control_hdr)) {
1116 dev_err(tplg->dev, "ASoC: invalid control size\n"); 1131 dev_err(tplg->dev, "ASoC: invalid control size\n");
1117 return -EINVAL; 1132 return -EINVAL;
1118 } 1133 }
1119 1134
1120 switch (control_hdr->ops.info) { 1135 switch (le32_to_cpu(control_hdr->ops.info)) {
1121 case SND_SOC_TPLG_CTL_VOLSW: 1136 case SND_SOC_TPLG_CTL_VOLSW:
1122 case SND_SOC_TPLG_CTL_STROBE: 1137 case SND_SOC_TPLG_CTL_STROBE:
1123 case SND_SOC_TPLG_CTL_VOLSW_SX: 1138 case SND_SOC_TPLG_CTL_VOLSW_SX:
@@ -1125,17 +1140,20 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
1125 case SND_SOC_TPLG_CTL_RANGE: 1140 case SND_SOC_TPLG_CTL_RANGE:
1126 case SND_SOC_TPLG_DAPM_CTL_VOLSW: 1141 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1127 case SND_SOC_TPLG_DAPM_CTL_PIN: 1142 case SND_SOC_TPLG_DAPM_CTL_PIN:
1128 soc_tplg_dmixer_create(tplg, 1, hdr->payload_size); 1143 soc_tplg_dmixer_create(tplg, 1,
1144 le32_to_cpu(hdr->payload_size));
1129 break; 1145 break;
1130 case SND_SOC_TPLG_CTL_ENUM: 1146 case SND_SOC_TPLG_CTL_ENUM:
1131 case SND_SOC_TPLG_CTL_ENUM_VALUE: 1147 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1132 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: 1148 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1133 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: 1149 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1134 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: 1150 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1135 soc_tplg_denum_create(tplg, 1, hdr->payload_size); 1151 soc_tplg_denum_create(tplg, 1,
1152 le32_to_cpu(hdr->payload_size));
1136 break; 1153 break;
1137 case SND_SOC_TPLG_CTL_BYTES: 1154 case SND_SOC_TPLG_CTL_BYTES:
1138 soc_tplg_dbytes_create(tplg, 1, hdr->payload_size); 1155 soc_tplg_dbytes_create(tplg, 1,
1156 le32_to_cpu(hdr->payload_size));
1139 break; 1157 break;
1140 default: 1158 default:
1141 soc_bind_err(tplg, control_hdr, i); 1159 soc_bind_err(tplg, control_hdr, i);
@@ -1163,17 +1181,22 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
1163 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; 1181 struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
1164 struct snd_soc_tplg_dapm_graph_elem *elem; 1182 struct snd_soc_tplg_dapm_graph_elem *elem;
1165 struct snd_soc_dapm_route **routes; 1183 struct snd_soc_dapm_route **routes;
1166 int count = hdr->count, i, j; 1184 int count, i, j;
1167 int ret = 0; 1185 int ret = 0;
1168 1186
1187 count = le32_to_cpu(hdr->count);
1188
1169 if (tplg->pass != SOC_TPLG_PASS_GRAPH) { 1189 if (tplg->pass != SOC_TPLG_PASS_GRAPH) {
1170 tplg->pos += hdr->size + hdr->payload_size; 1190 tplg->pos +=
1191 le32_to_cpu(hdr->size) +
1192 le32_to_cpu(hdr->payload_size);
1193
1171 return 0; 1194 return 0;
1172 } 1195 }
1173 1196
1174 if (soc_tplg_check_elem_count(tplg, 1197 if (soc_tplg_check_elem_count(tplg,
1175 sizeof(struct snd_soc_tplg_dapm_graph_elem), 1198 sizeof(struct snd_soc_tplg_dapm_graph_elem),
1176 count, hdr->payload_size, "graph")) { 1199 count, le32_to_cpu(hdr->payload_size), "graph")) {
1177 1200
1178 dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n", 1201 dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n",
1179 count); 1202 count);
@@ -1282,14 +1305,14 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
1282 if (sm == NULL) 1305 if (sm == NULL)
1283 goto err; 1306 goto err;
1284 1307
1285 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
1286 mc->priv.size);
1287
1288 /* validate kcontrol */ 1308 /* validate kcontrol */
1289 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 1309 if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
1290 SNDRV_CTL_ELEM_ID_NAME_MAXLEN) 1310 SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
1291 goto err_str; 1311 goto err_str;
1292 1312
1313 tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) +
1314 le32_to_cpu(mc->priv.size));
1315
1293 dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", 1316 dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n",
1294 mc->hdr.name, i); 1317 mc->hdr.name, i);
1295 1318
@@ -1325,18 +1348,19 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create(
1325 continue; 1348 continue;
1326 } 1349 }
1327 1350
1351 /* create any TLV data */
1352 soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr);
1353
1328 /* pass control to driver for optional further init */ 1354 /* pass control to driver for optional further init */
1329 err = soc_tplg_init_kcontrol(tplg, &kc[i], 1355 err = soc_tplg_init_kcontrol(tplg, &kc[i],
1330 (struct snd_soc_tplg_ctl_hdr *)mc); 1356 (struct snd_soc_tplg_ctl_hdr *)mc);
1331 if (err < 0) { 1357 if (err < 0) {
1332 dev_err(tplg->dev, "ASoC: failed to init %s\n", 1358 dev_err(tplg->dev, "ASoC: failed to init %s\n",
1333 mc->hdr.name); 1359 mc->hdr.name);
1360 soc_tplg_free_tlv(tplg, &kc[i]);
1334 kfree(sm); 1361 kfree(sm);
1335 continue; 1362 continue;
1336 } 1363 }
1337
1338 /* create any TLV data */
1339 soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr);
1340 } 1364 }
1341 return kc; 1365 return kc;
1342 1366
@@ -1374,6 +1398,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1374 if (se == NULL) 1398 if (se == NULL)
1375 goto err; 1399 goto err;
1376 1400
1401 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1402 ec->priv.size);
1403
1377 dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", 1404 dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n",
1378 ec->hdr.name); 1405 ec->hdr.name);
1379 1406
@@ -1397,7 +1424,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1397 se->mask = ec->mask; 1424 se->mask = ec->mask;
1398 se->dobj.index = tplg->index; 1425 se->dobj.index = tplg->index;
1399 1426
1400 switch (ec->hdr.ops.info) { 1427 switch (le32_to_cpu(ec->hdr.ops.info)) {
1401 case SND_SOC_TPLG_CTL_ENUM_VALUE: 1428 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1402 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: 1429 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1403 err = soc_tplg_denum_create_values(se, ec); 1430 err = soc_tplg_denum_create_values(se, ec);
@@ -1438,9 +1465,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create(
1438 ec->hdr.name); 1465 ec->hdr.name);
1439 goto err_se; 1466 goto err_se;
1440 } 1467 }
1441
1442 tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) +
1443 ec->priv.size);
1444 } 1468 }
1445 1469
1446 return kc; 1470 return kc;
@@ -1491,7 +1515,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create(
1491 goto err; 1515 goto err;
1492 1516
1493 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + 1517 tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) +
1494 be->priv.size); 1518 le32_to_cpu(be->priv.size));
1495 1519
1496 dev_dbg(tplg->dev, 1520 dev_dbg(tplg->dev,
1497 "ASoC: adding bytes kcontrol %s with access 0x%x\n", 1521 "ASoC: adding bytes kcontrol %s with access 0x%x\n",
@@ -1563,7 +1587,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1563 memset(&template, 0, sizeof(template)); 1587 memset(&template, 0, sizeof(template));
1564 1588
1565 /* map user to kernel widget ID */ 1589 /* map user to kernel widget ID */
1566 template.id = get_widget_id(w->id); 1590 template.id = get_widget_id(le32_to_cpu(w->id));
1567 if (template.id < 0) 1591 if (template.id < 0)
1568 return template.id; 1592 return template.id;
1569 1593
@@ -1576,18 +1600,20 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1576 ret = -ENOMEM; 1600 ret = -ENOMEM;
1577 goto err; 1601 goto err;
1578 } 1602 }
1579 template.reg = w->reg; 1603 template.reg = le32_to_cpu(w->reg);
1580 template.shift = w->shift; 1604 template.shift = le32_to_cpu(w->shift);
1581 template.mask = w->mask; 1605 template.mask = le32_to_cpu(w->mask);
1582 template.subseq = w->subseq; 1606 template.subseq = le32_to_cpu(w->subseq);
1583 template.on_val = w->invert ? 0 : 1; 1607 template.on_val = w->invert ? 0 : 1;
1584 template.off_val = w->invert ? 1 : 0; 1608 template.off_val = w->invert ? 1 : 0;
1585 template.ignore_suspend = w->ignore_suspend; 1609 template.ignore_suspend = le32_to_cpu(w->ignore_suspend);
1586 template.event_flags = w->event_flags; 1610 template.event_flags = le16_to_cpu(w->event_flags);
1587 template.dobj.index = tplg->index; 1611 template.dobj.index = tplg->index;
1588 1612
1589 tplg->pos += 1613 tplg->pos +=
1590 (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size); 1614 (sizeof(struct snd_soc_tplg_dapm_widget) +
1615 le32_to_cpu(w->priv.size));
1616
1591 if (w->num_kcontrols == 0) { 1617 if (w->num_kcontrols == 0) {
1592 kcontrol_type = 0; 1618 kcontrol_type = 0;
1593 template.num_kcontrols = 0; 1619 template.num_kcontrols = 0;
@@ -1598,7 +1624,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1598 dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", 1624 dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n",
1599 w->name, w->num_kcontrols, control_hdr->type); 1625 w->name, w->num_kcontrols, control_hdr->type);
1600 1626
1601 switch (control_hdr->ops.info) { 1627 switch (le32_to_cpu(control_hdr->ops.info)) {
1602 case SND_SOC_TPLG_CTL_VOLSW: 1628 case SND_SOC_TPLG_CTL_VOLSW:
1603 case SND_SOC_TPLG_CTL_STROBE: 1629 case SND_SOC_TPLG_CTL_STROBE:
1604 case SND_SOC_TPLG_CTL_VOLSW_SX: 1630 case SND_SOC_TPLG_CTL_VOLSW_SX:
@@ -1606,7 +1632,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1606 case SND_SOC_TPLG_CTL_RANGE: 1632 case SND_SOC_TPLG_CTL_RANGE:
1607 case SND_SOC_TPLG_DAPM_CTL_VOLSW: 1633 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1608 kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */ 1634 kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */
1609 template.num_kcontrols = w->num_kcontrols; 1635 template.num_kcontrols = le32_to_cpu(w->num_kcontrols);
1610 template.kcontrol_news = 1636 template.kcontrol_news =
1611 soc_tplg_dapm_widget_dmixer_create(tplg, 1637 soc_tplg_dapm_widget_dmixer_create(tplg,
1612 template.num_kcontrols); 1638 template.num_kcontrols);
@@ -1621,7 +1647,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1621 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: 1647 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1622 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: 1648 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1623 kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */ 1649 kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */
1624 template.num_kcontrols = w->num_kcontrols; 1650 template.num_kcontrols = le32_to_cpu(w->num_kcontrols);
1625 template.kcontrol_news = 1651 template.kcontrol_news =
1626 soc_tplg_dapm_widget_denum_create(tplg, 1652 soc_tplg_dapm_widget_denum_create(tplg,
1627 template.num_kcontrols); 1653 template.num_kcontrols);
@@ -1632,7 +1658,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1632 break; 1658 break;
1633 case SND_SOC_TPLG_CTL_BYTES: 1659 case SND_SOC_TPLG_CTL_BYTES:
1634 kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */ 1660 kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */
1635 template.num_kcontrols = w->num_kcontrols; 1661 template.num_kcontrols = le32_to_cpu(w->num_kcontrols);
1636 template.kcontrol_news = 1662 template.kcontrol_news =
1637 soc_tplg_dapm_widget_dbytes_create(tplg, 1663 soc_tplg_dapm_widget_dbytes_create(tplg,
1638 template.num_kcontrols); 1664 template.num_kcontrols);
@@ -1644,7 +1670,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
1644 default: 1670 default:
1645 dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n", 1671 dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n",
1646 control_hdr->ops.get, control_hdr->ops.put, 1672 control_hdr->ops.get, control_hdr->ops.put,
1647 control_hdr->ops.info); 1673 le32_to_cpu(control_hdr->ops.info));
1648 ret = -EINVAL; 1674 ret = -EINVAL;
1649 goto hdr_err; 1675 goto hdr_err;
1650 } 1676 }
@@ -1694,7 +1720,9 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
1694 struct snd_soc_tplg_hdr *hdr) 1720 struct snd_soc_tplg_hdr *hdr)
1695{ 1721{
1696 struct snd_soc_tplg_dapm_widget *widget; 1722 struct snd_soc_tplg_dapm_widget *widget;
1697 int ret, count = hdr->count, i; 1723 int ret, count, i;
1724
1725 count = le32_to_cpu(hdr->count);
1698 1726
1699 if (tplg->pass != SOC_TPLG_PASS_WIDGET) 1727 if (tplg->pass != SOC_TPLG_PASS_WIDGET)
1700 return 0; 1728 return 0;
@@ -1703,7 +1731,7 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg,
1703 1731
1704 for (i = 0; i < count; i++) { 1732 for (i = 0; i < count; i++) {
1705 widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; 1733 widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos;
1706 if (widget->size != sizeof(*widget)) { 1734 if (le32_to_cpu(widget->size) != sizeof(*widget)) {
1707 dev_err(tplg->dev, "ASoC: invalid widget size\n"); 1735 dev_err(tplg->dev, "ASoC: invalid widget size\n");
1708 return -EINVAL; 1736 return -EINVAL;
1709 } 1737 }
@@ -1745,13 +1773,13 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream,
1745 struct snd_soc_tplg_stream_caps *caps) 1773 struct snd_soc_tplg_stream_caps *caps)
1746{ 1774{
1747 stream->stream_name = kstrdup(caps->name, GFP_KERNEL); 1775 stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
1748 stream->channels_min = caps->channels_min; 1776 stream->channels_min = le32_to_cpu(caps->channels_min);
1749 stream->channels_max = caps->channels_max; 1777 stream->channels_max = le32_to_cpu(caps->channels_max);
1750 stream->rates = caps->rates; 1778 stream->rates = le32_to_cpu(caps->rates);
1751 stream->rate_min = caps->rate_min; 1779 stream->rate_min = le32_to_cpu(caps->rate_min);
1752 stream->rate_max = caps->rate_max; 1780 stream->rate_max = le32_to_cpu(caps->rate_max);
1753 stream->formats = caps->formats; 1781 stream->formats = le64_to_cpu(caps->formats);
1754 stream->sig_bits = caps->sig_bits; 1782 stream->sig_bits = le32_to_cpu(caps->sig_bits);
1755} 1783}
1756 1784
1757static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, 1785static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
@@ -1786,7 +1814,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
1786 1814
1787 if (strlen(pcm->dai_name)) 1815 if (strlen(pcm->dai_name))
1788 dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL); 1816 dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
1789 dai_drv->id = pcm->dai_id; 1817 dai_drv->id = le32_to_cpu(pcm->dai_id);
1790 1818
1791 if (pcm->playback) { 1819 if (pcm->playback) {
1792 stream = &dai_drv->playback; 1820 stream = &dai_drv->playback;
@@ -1807,6 +1835,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
1807 ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); 1835 ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
1808 if (ret < 0) { 1836 if (ret < 0) {
1809 dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); 1837 dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
1838 kfree(dai_drv->playback.stream_name);
1839 kfree(dai_drv->capture.stream_name);
1840 kfree(dai_drv->name);
1810 kfree(dai_drv); 1841 kfree(dai_drv);
1811 return ret; 1842 return ret;
1812 } 1843 }
@@ -1858,7 +1889,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
1858 link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); 1889 link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
1859 link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); 1890 link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
1860 } 1891 }
1861 link->id = pcm->pcm_id; 1892 link->id = le32_to_cpu(pcm->pcm_id);
1862 1893
1863 if (strlen(pcm->dai_name)) 1894 if (strlen(pcm->dai_name))
1864 link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); 1895 link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
@@ -1868,15 +1899,20 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
1868 1899
1869 /* enable DPCM */ 1900 /* enable DPCM */
1870 link->dynamic = 1; 1901 link->dynamic = 1;
1871 link->dpcm_playback = pcm->playback; 1902 link->dpcm_playback = le32_to_cpu(pcm->playback);
1872 link->dpcm_capture = pcm->capture; 1903 link->dpcm_capture = le32_to_cpu(pcm->capture);
1873 if (pcm->flag_mask) 1904 if (pcm->flag_mask)
1874 set_link_flags(link, pcm->flag_mask, pcm->flags); 1905 set_link_flags(link,
1906 le32_to_cpu(pcm->flag_mask),
1907 le32_to_cpu(pcm->flags));
1875 1908
1876 /* pass control to component driver for optional further init */ 1909 /* pass control to component driver for optional further init */
1877 ret = soc_tplg_dai_link_load(tplg, link, NULL); 1910 ret = soc_tplg_dai_link_load(tplg, link, NULL);
1878 if (ret < 0) { 1911 if (ret < 0) {
1879 dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); 1912 dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
1913 kfree(link->name);
1914 kfree(link->stream_name);
1915 kfree(link->cpu_dai_name);
1880 kfree(link); 1916 kfree(link);
1881 return ret; 1917 return ret;
1882 } 1918 }
@@ -1907,7 +1943,7 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg,
1907static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest, 1943static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest,
1908 struct snd_soc_tplg_stream_caps_v4 *src) 1944 struct snd_soc_tplg_stream_caps_v4 *src)
1909{ 1945{
1910 dest->size = sizeof(*dest); 1946 dest->size = cpu_to_le32(sizeof(*dest));
1911 memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 1947 memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1912 dest->formats = src->formats; 1948 dest->formats = src->formats;
1913 dest->rates = src->rates; 1949 dest->rates = src->rates;
@@ -1941,7 +1977,7 @@ static int pcm_new_ver(struct soc_tplg *tplg,
1941 1977
1942 *pcm = NULL; 1978 *pcm = NULL;
1943 1979
1944 if (src->size != sizeof(*src_v4)) { 1980 if (le32_to_cpu(src->size) != sizeof(*src_v4)) {
1945 dev_err(tplg->dev, "ASoC: invalid PCM size\n"); 1981 dev_err(tplg->dev, "ASoC: invalid PCM size\n");
1946 return -EINVAL; 1982 return -EINVAL;
1947 } 1983 }
@@ -1952,7 +1988,7 @@ static int pcm_new_ver(struct soc_tplg *tplg,
1952 if (!dest) 1988 if (!dest)
1953 return -ENOMEM; 1989 return -ENOMEM;
1954 1990
1955 dest->size = sizeof(*dest); /* size of latest abi version */ 1991 dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */
1956 memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 1992 memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1957 memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 1993 memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1958 dest->pcm_id = src_v4->pcm_id; 1994 dest->pcm_id = src_v4->pcm_id;
@@ -1961,7 +1997,7 @@ static int pcm_new_ver(struct soc_tplg *tplg,
1961 dest->capture = src_v4->capture; 1997 dest->capture = src_v4->capture;
1962 dest->compress = src_v4->compress; 1998 dest->compress = src_v4->compress;
1963 dest->num_streams = src_v4->num_streams; 1999 dest->num_streams = src_v4->num_streams;
1964 for (i = 0; i < dest->num_streams; i++) 2000 for (i = 0; i < le32_to_cpu(dest->num_streams); i++)
1965 memcpy(&dest->stream[i], &src_v4->stream[i], 2001 memcpy(&dest->stream[i], &src_v4->stream[i],
1966 sizeof(struct snd_soc_tplg_stream)); 2002 sizeof(struct snd_soc_tplg_stream));
1967 2003
@@ -1976,25 +2012,30 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
1976 struct snd_soc_tplg_hdr *hdr) 2012 struct snd_soc_tplg_hdr *hdr)
1977{ 2013{
1978 struct snd_soc_tplg_pcm *pcm, *_pcm; 2014 struct snd_soc_tplg_pcm *pcm, *_pcm;
1979 int count = hdr->count; 2015 int count;
2016 int size;
1980 int i; 2017 int i;
1981 bool abi_match; 2018 bool abi_match;
1982 2019
2020 count = le32_to_cpu(hdr->count);
2021
1983 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) 2022 if (tplg->pass != SOC_TPLG_PASS_PCM_DAI)
1984 return 0; 2023 return 0;
1985 2024
1986 /* check the element size and count */ 2025 /* check the element size and count */
1987 pcm = (struct snd_soc_tplg_pcm *)tplg->pos; 2026 pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
1988 if (pcm->size > sizeof(struct snd_soc_tplg_pcm) 2027 size = le32_to_cpu(pcm->size);
1989 || pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) { 2028 if (size > sizeof(struct snd_soc_tplg_pcm)
2029 || size < sizeof(struct snd_soc_tplg_pcm_v4)) {
1990 dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n", 2030 dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n",
1991 pcm->size); 2031 size);
1992 return -EINVAL; 2032 return -EINVAL;
1993 } 2033 }
1994 2034
1995 if (soc_tplg_check_elem_count(tplg, 2035 if (soc_tplg_check_elem_count(tplg,
1996 pcm->size, count, 2036 size, count,
1997 hdr->payload_size, "PCM DAI")) { 2037 le32_to_cpu(hdr->payload_size),
2038 "PCM DAI")) {
1998 dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n", 2039 dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n",
1999 count); 2040 count);
2000 return -EINVAL; 2041 return -EINVAL;
@@ -2002,11 +2043,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
2002 2043
2003 for (i = 0; i < count; i++) { 2044 for (i = 0; i < count; i++) {
2004 pcm = (struct snd_soc_tplg_pcm *)tplg->pos; 2045 pcm = (struct snd_soc_tplg_pcm *)tplg->pos;
2046 size = le32_to_cpu(pcm->size);
2005 2047
2006 /* check ABI version by size, create a new version of pcm 2048 /* check ABI version by size, create a new version of pcm
2007 * if abi not match. 2049 * if abi not match.
2008 */ 2050 */
2009 if (pcm->size == sizeof(*pcm)) { 2051 if (size == sizeof(*pcm)) {
2010 abi_match = true; 2052 abi_match = true;
2011 _pcm = pcm; 2053 _pcm = pcm;
2012 } else { 2054 } else {
@@ -2020,7 +2062,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg,
2020 /* offset by version-specific struct size and 2062 /* offset by version-specific struct size and
2021 * real priv data size 2063 * real priv data size
2022 */ 2064 */
2023 tplg->pos += pcm->size + _pcm->priv.size; 2065 tplg->pos += size + le32_to_cpu(_pcm->priv.size);
2024 2066
2025 if (!abi_match) 2067 if (!abi_match)
2026 kfree(_pcm); /* free the duplicated one */ 2068 kfree(_pcm); /* free the duplicated one */
@@ -2048,12 +2090,13 @@ static void set_link_hw_format(struct snd_soc_dai_link *link,
2048 unsigned char invert_bclk, invert_fsync; 2090 unsigned char invert_bclk, invert_fsync;
2049 int i; 2091 int i;
2050 2092
2051 for (i = 0; i < cfg->num_hw_configs; i++) { 2093 for (i = 0; i < le32_to_cpu(cfg->num_hw_configs); i++) {
2052 hw_config = &cfg->hw_config[i]; 2094 hw_config = &cfg->hw_config[i];
2053 if (hw_config->id != cfg->default_hw_config_id) 2095 if (hw_config->id != cfg->default_hw_config_id)
2054 continue; 2096 continue;
2055 2097
2056 link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; 2098 link->dai_fmt = le32_to_cpu(hw_config->fmt) &
2099 SND_SOC_DAIFMT_FORMAT_MASK;
2057 2100
2058 /* clock gating */ 2101 /* clock gating */
2059 switch (hw_config->clock_gated) { 2102 switch (hw_config->clock_gated) {
@@ -2117,7 +2160,8 @@ static int link_new_ver(struct soc_tplg *tplg,
2117 2160
2118 *link = NULL; 2161 *link = NULL;
2119 2162
2120 if (src->size != sizeof(struct snd_soc_tplg_link_config_v4)) { 2163 if (le32_to_cpu(src->size) !=
2164 sizeof(struct snd_soc_tplg_link_config_v4)) {
2121 dev_err(tplg->dev, "ASoC: invalid physical link config size\n"); 2165 dev_err(tplg->dev, "ASoC: invalid physical link config size\n");
2122 return -EINVAL; 2166 return -EINVAL;
2123 } 2167 }
@@ -2129,10 +2173,10 @@ static int link_new_ver(struct soc_tplg *tplg,
2129 if (!dest) 2173 if (!dest)
2130 return -ENOMEM; 2174 return -ENOMEM;
2131 2175
2132 dest->size = sizeof(*dest); 2176 dest->size = cpu_to_le32(sizeof(*dest));
2133 dest->id = src_v4->id; 2177 dest->id = src_v4->id;
2134 dest->num_streams = src_v4->num_streams; 2178 dest->num_streams = src_v4->num_streams;
2135 for (i = 0; i < dest->num_streams; i++) 2179 for (i = 0; i < le32_to_cpu(dest->num_streams); i++)
2136 memcpy(&dest->stream[i], &src_v4->stream[i], 2180 memcpy(&dest->stream[i], &src_v4->stream[i],
2137 sizeof(struct snd_soc_tplg_stream)); 2181 sizeof(struct snd_soc_tplg_stream));
2138 2182
@@ -2165,7 +2209,7 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,
2165 else 2209 else
2166 stream_name = NULL; 2210 stream_name = NULL;
2167 2211
2168 link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, 2212 link = snd_soc_find_dai_link(tplg->comp->card, le32_to_cpu(cfg->id),
2169 name, stream_name); 2213 name, stream_name);
2170 if (!link) { 2214 if (!link) {
2171 dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n", 2215 dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n",
@@ -2179,7 +2223,9 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,
2179 2223
2180 /* flags */ 2224 /* flags */
2181 if (cfg->flag_mask) 2225 if (cfg->flag_mask)
2182 set_link_flags(link, cfg->flag_mask, cfg->flags); 2226 set_link_flags(link,
2227 le32_to_cpu(cfg->flag_mask),
2228 le32_to_cpu(cfg->flags));
2183 2229
2184 /* pass control to component driver for optional further init */ 2230 /* pass control to component driver for optional further init */
2185 ret = soc_tplg_dai_link_load(tplg, link, cfg); 2231 ret = soc_tplg_dai_link_load(tplg, link, cfg);
@@ -2203,27 +2249,33 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
2203 struct snd_soc_tplg_hdr *hdr) 2249 struct snd_soc_tplg_hdr *hdr)
2204{ 2250{
2205 struct snd_soc_tplg_link_config *link, *_link; 2251 struct snd_soc_tplg_link_config *link, *_link;
2206 int count = hdr->count; 2252 int count;
2253 int size;
2207 int i, ret; 2254 int i, ret;
2208 bool abi_match; 2255 bool abi_match;
2209 2256
2257 count = le32_to_cpu(hdr->count);
2258
2210 if (tplg->pass != SOC_TPLG_PASS_LINK) { 2259 if (tplg->pass != SOC_TPLG_PASS_LINK) {
2211 tplg->pos += hdr->size + hdr->payload_size; 2260 tplg->pos += le32_to_cpu(hdr->size) +
2261 le32_to_cpu(hdr->payload_size);
2212 return 0; 2262 return 0;
2213 }; 2263 };
2214 2264
2215 /* check the element size and count */ 2265 /* check the element size and count */
2216 link = (struct snd_soc_tplg_link_config *)tplg->pos; 2266 link = (struct snd_soc_tplg_link_config *)tplg->pos;
2217 if (link->size > sizeof(struct snd_soc_tplg_link_config) 2267 size = le32_to_cpu(link->size);
2218 || link->size < sizeof(struct snd_soc_tplg_link_config_v4)) { 2268 if (size > sizeof(struct snd_soc_tplg_link_config)
2269 || size < sizeof(struct snd_soc_tplg_link_config_v4)) {
2219 dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n", 2270 dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n",
2220 link->size); 2271 size);
2221 return -EINVAL; 2272 return -EINVAL;
2222 } 2273 }
2223 2274
2224 if (soc_tplg_check_elem_count(tplg, 2275 if (soc_tplg_check_elem_count(tplg,
2225 link->size, count, 2276 size, count,
2226 hdr->payload_size, "physical link config")) { 2277 le32_to_cpu(hdr->payload_size),
2278 "physical link config")) {
2227 dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n", 2279 dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n",
2228 count); 2280 count);
2229 return -EINVAL; 2281 return -EINVAL;
@@ -2232,7 +2284,8 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
2232 /* config physical DAI links */ 2284 /* config physical DAI links */
2233 for (i = 0; i < count; i++) { 2285 for (i = 0; i < count; i++) {
2234 link = (struct snd_soc_tplg_link_config *)tplg->pos; 2286 link = (struct snd_soc_tplg_link_config *)tplg->pos;
2235 if (link->size == sizeof(*link)) { 2287 size = le32_to_cpu(link->size);
2288 if (size == sizeof(*link)) {
2236 abi_match = true; 2289 abi_match = true;
2237 _link = link; 2290 _link = link;
2238 } else { 2291 } else {
@@ -2249,7 +2302,7 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
2249 /* offset by version-specific struct size and 2302 /* offset by version-specific struct size and
2250 * real priv data size 2303 * real priv data size
2251 */ 2304 */
2252 tplg->pos += link->size + _link->priv.size; 2305 tplg->pos += size + le32_to_cpu(_link->priv.size);
2253 2306
2254 if (!abi_match) 2307 if (!abi_match)
2255 kfree(_link); /* free the duplicated one */ 2308 kfree(_link); /* free the duplicated one */
@@ -2269,13 +2322,15 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
2269static int soc_tplg_dai_config(struct soc_tplg *tplg, 2322static int soc_tplg_dai_config(struct soc_tplg *tplg,
2270 struct snd_soc_tplg_dai *d) 2323 struct snd_soc_tplg_dai *d)
2271{ 2324{
2272 struct snd_soc_dai_link_component dai_component = {0}; 2325 struct snd_soc_dai_link_component dai_component;
2273 struct snd_soc_dai *dai; 2326 struct snd_soc_dai *dai;
2274 struct snd_soc_dai_driver *dai_drv; 2327 struct snd_soc_dai_driver *dai_drv;
2275 struct snd_soc_pcm_stream *stream; 2328 struct snd_soc_pcm_stream *stream;
2276 struct snd_soc_tplg_stream_caps *caps; 2329 struct snd_soc_tplg_stream_caps *caps;
2277 int ret; 2330 int ret;
2278 2331
2332 memset(&dai_component, 0, sizeof(dai_component));
2333
2279 dai_component.dai_name = d->dai_name; 2334 dai_component.dai_name = d->dai_name;
2280 dai = snd_soc_find_dai(&dai_component); 2335 dai = snd_soc_find_dai(&dai_component);
2281 if (!dai) { 2336 if (!dai) {
@@ -2284,7 +2339,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
2284 return -EINVAL; 2339 return -EINVAL;
2285 } 2340 }
2286 2341
2287 if (d->dai_id != dai->id) { 2342 if (le32_to_cpu(d->dai_id) != dai->id) {
2288 dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n", 2343 dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n",
2289 d->dai_name); 2344 d->dai_name);
2290 return -EINVAL; 2345 return -EINVAL;
@@ -2307,7 +2362,9 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
2307 } 2362 }
2308 2363
2309 if (d->flag_mask) 2364 if (d->flag_mask)
2310 set_dai_flags(dai_drv, d->flag_mask, d->flags); 2365 set_dai_flags(dai_drv,
2366 le32_to_cpu(d->flag_mask),
2367 le32_to_cpu(d->flags));
2311 2368
2312 /* pass control to component driver for optional further init */ 2369 /* pass control to component driver for optional further init */
2313 ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai); 2370 ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
@@ -2324,22 +2381,24 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg,
2324 struct snd_soc_tplg_hdr *hdr) 2381 struct snd_soc_tplg_hdr *hdr)
2325{ 2382{
2326 struct snd_soc_tplg_dai *dai; 2383 struct snd_soc_tplg_dai *dai;
2327 int count = hdr->count; 2384 int count;
2328 int i; 2385 int i;
2329 2386
2387 count = le32_to_cpu(hdr->count);
2388
2330 if (tplg->pass != SOC_TPLG_PASS_BE_DAI) 2389 if (tplg->pass != SOC_TPLG_PASS_BE_DAI)
2331 return 0; 2390 return 0;
2332 2391
2333 /* config the existing BE DAIs */ 2392 /* config the existing BE DAIs */
2334 for (i = 0; i < count; i++) { 2393 for (i = 0; i < count; i++) {
2335 dai = (struct snd_soc_tplg_dai *)tplg->pos; 2394 dai = (struct snd_soc_tplg_dai *)tplg->pos;
2336 if (dai->size != sizeof(*dai)) { 2395 if (le32_to_cpu(dai->size) != sizeof(*dai)) {
2337 dev_err(tplg->dev, "ASoC: invalid physical DAI size\n"); 2396 dev_err(tplg->dev, "ASoC: invalid physical DAI size\n");
2338 return -EINVAL; 2397 return -EINVAL;
2339 } 2398 }
2340 2399
2341 soc_tplg_dai_config(tplg, dai); 2400 soc_tplg_dai_config(tplg, dai);
2342 tplg->pos += (sizeof(*dai) + dai->priv.size); 2401 tplg->pos += (sizeof(*dai) + le32_to_cpu(dai->priv.size));
2343 } 2402 }
2344 2403
2345 dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); 2404 dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count);
@@ -2361,25 +2420,28 @@ static int manifest_new_ver(struct soc_tplg *tplg,
2361{ 2420{
2362 struct snd_soc_tplg_manifest *dest; 2421 struct snd_soc_tplg_manifest *dest;
2363 struct snd_soc_tplg_manifest_v4 *src_v4; 2422 struct snd_soc_tplg_manifest_v4 *src_v4;
2423 int size;
2364 2424
2365 *manifest = NULL; 2425 *manifest = NULL;
2366 2426
2367 if (src->size != sizeof(*src_v4)) { 2427 size = le32_to_cpu(src->size);
2428 if (size != sizeof(*src_v4)) {
2368 dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n", 2429 dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n",
2369 src->size); 2430 size);
2370 if (src->size) 2431 if (size)
2371 return -EINVAL; 2432 return -EINVAL;
2372 src->size = sizeof(*src_v4); 2433 src->size = cpu_to_le32(sizeof(*src_v4));
2373 } 2434 }
2374 2435
2375 dev_warn(tplg->dev, "ASoC: old version of manifest\n"); 2436 dev_warn(tplg->dev, "ASoC: old version of manifest\n");
2376 2437
2377 src_v4 = (struct snd_soc_tplg_manifest_v4 *)src; 2438 src_v4 = (struct snd_soc_tplg_manifest_v4 *)src;
2378 dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL); 2439 dest = kzalloc(sizeof(*dest) + le32_to_cpu(src_v4->priv.size),
2440 GFP_KERNEL);
2379 if (!dest) 2441 if (!dest)
2380 return -ENOMEM; 2442 return -ENOMEM;
2381 2443
2382 dest->size = sizeof(*dest); /* size of latest abi version */ 2444 dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */
2383 dest->control_elems = src_v4->control_elems; 2445 dest->control_elems = src_v4->control_elems;
2384 dest->widget_elems = src_v4->widget_elems; 2446 dest->widget_elems = src_v4->widget_elems;
2385 dest->graph_elems = src_v4->graph_elems; 2447 dest->graph_elems = src_v4->graph_elems;
@@ -2388,7 +2450,7 @@ static int manifest_new_ver(struct soc_tplg *tplg,
2388 dest->priv.size = src_v4->priv.size; 2450 dest->priv.size = src_v4->priv.size;
2389 if (dest->priv.size) 2451 if (dest->priv.size)
2390 memcpy(dest->priv.data, src_v4->priv.data, 2452 memcpy(dest->priv.data, src_v4->priv.data,
2391 src_v4->priv.size); 2453 le32_to_cpu(src_v4->priv.size));
2392 2454
2393 *manifest = dest; 2455 *manifest = dest;
2394 return 0; 2456 return 0;
@@ -2407,7 +2469,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
2407 manifest = (struct snd_soc_tplg_manifest *)tplg->pos; 2469 manifest = (struct snd_soc_tplg_manifest *)tplg->pos;
2408 2470
2409 /* check ABI version by size, create a new manifest if abi not match */ 2471 /* check ABI version by size, create a new manifest if abi not match */
2410 if (manifest->size == sizeof(*manifest)) { 2472 if (le32_to_cpu(manifest->size) == sizeof(*manifest)) {
2411 abi_match = true; 2473 abi_match = true;
2412 _manifest = manifest; 2474 _manifest = manifest;
2413 } else { 2475 } else {
@@ -2434,16 +2496,16 @@ static int soc_valid_header(struct soc_tplg *tplg,
2434 if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) 2496 if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size)
2435 return 0; 2497 return 0;
2436 2498
2437 if (hdr->size != sizeof(*hdr)) { 2499 if (le32_to_cpu(hdr->size) != sizeof(*hdr)) {
2438 dev_err(tplg->dev, 2500 dev_err(tplg->dev,
2439 "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n", 2501 "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n",
2440 hdr->type, soc_tplg_get_hdr_offset(tplg), 2502 le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg),
2441 tplg->fw->size); 2503 tplg->fw->size);
2442 return -EINVAL; 2504 return -EINVAL;
2443 } 2505 }
2444 2506
2445 /* big endian firmware objects not supported atm */ 2507 /* big endian firmware objects not supported atm */
2446 if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { 2508 if (hdr->magic == SOC_TPLG_MAGIC_BIG_ENDIAN) {
2447 dev_err(tplg->dev, 2509 dev_err(tplg->dev,
2448 "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n", 2510 "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
2449 tplg->pass, hdr->magic, 2511 tplg->pass, hdr->magic,
@@ -2451,7 +2513,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
2451 return -EINVAL; 2513 return -EINVAL;
2452 } 2514 }
2453 2515
2454 if (hdr->magic != SND_SOC_TPLG_MAGIC) { 2516 if (le32_to_cpu(hdr->magic) != SND_SOC_TPLG_MAGIC) {
2455 dev_err(tplg->dev, 2517 dev_err(tplg->dev,
2456 "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n", 2518 "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n",
2457 tplg->pass, hdr->magic, 2519 tplg->pass, hdr->magic,
@@ -2460,8 +2522,8 @@ static int soc_valid_header(struct soc_tplg *tplg,
2460 } 2522 }
2461 2523
2462 /* Support ABI from version 4 */ 2524 /* Support ABI from version 4 */
2463 if (hdr->abi > SND_SOC_TPLG_ABI_VERSION 2525 if (le32_to_cpu(hdr->abi) > SND_SOC_TPLG_ABI_VERSION ||
2464 || hdr->abi < SND_SOC_TPLG_ABI_VERSION_MIN) { 2526 le32_to_cpu(hdr->abi) < SND_SOC_TPLG_ABI_VERSION_MIN) {
2465 dev_err(tplg->dev, 2527 dev_err(tplg->dev,
2466 "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n", 2528 "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n",
2467 tplg->pass, hdr->abi, 2529 tplg->pass, hdr->abi,
@@ -2476,7 +2538,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
2476 return -EINVAL; 2538 return -EINVAL;
2477 } 2539 }
2478 2540
2479 if (tplg->pass == hdr->type) 2541 if (tplg->pass == le32_to_cpu(hdr->type))
2480 dev_dbg(tplg->dev, 2542 dev_dbg(tplg->dev,
2481 "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n", 2543 "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n",
2482 hdr->payload_size, hdr->type, hdr->version, 2544 hdr->payload_size, hdr->type, hdr->version,
@@ -2492,13 +2554,13 @@ static int soc_tplg_load_header(struct soc_tplg *tplg,
2492 tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr); 2554 tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr);
2493 2555
2494 /* check for matching ID */ 2556 /* check for matching ID */
2495 if (hdr->index != tplg->req_index && 2557 if (le32_to_cpu(hdr->index) != tplg->req_index &&
2496 tplg->req_index != SND_SOC_TPLG_INDEX_ALL) 2558 tplg->req_index != SND_SOC_TPLG_INDEX_ALL)
2497 return 0; 2559 return 0;
2498 2560
2499 tplg->index = hdr->index; 2561 tplg->index = le32_to_cpu(hdr->index);
2500 2562
2501 switch (hdr->type) { 2563 switch (le32_to_cpu(hdr->type)) {
2502 case SND_SOC_TPLG_TYPE_MIXER: 2564 case SND_SOC_TPLG_TYPE_MIXER:
2503 case SND_SOC_TPLG_TYPE_ENUM: 2565 case SND_SOC_TPLG_TYPE_ENUM:
2504 case SND_SOC_TPLG_TYPE_BYTES: 2566 case SND_SOC_TPLG_TYPE_BYTES:
@@ -2554,7 +2616,7 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg)
2554 return ret; 2616 return ret;
2555 2617
2556 /* goto next header */ 2618 /* goto next header */
2557 tplg->hdr_pos += hdr->payload_size + 2619 tplg->hdr_pos += le32_to_cpu(hdr->payload_size) +
2558 sizeof(struct snd_soc_tplg_hdr); 2620 sizeof(struct snd_soc_tplg_hdr);
2559 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos; 2621 hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos;
2560 } 2622 }
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
new file mode 100644
index 000000000000..b204c65698f9
--- /dev/null
+++ b/sound/soc/sof/Kconfig
@@ -0,0 +1,156 @@
1config SND_SOC_SOF_TOPLEVEL
2 bool "Sound Open Firmware Support"
3 help
4 This adds support for Sound Open Firmware (SOF). SOF is a free and
5 generic open source audio DSP firmware for multiple devices.
6 Say Y if you have such a device that is supported by SOF.
7 If unsure select "N".
8
9if SND_SOC_SOF_TOPLEVEL
10
11config SND_SOC_SOF_PCI
12 tristate "SOF PCI enumeration support"
13 depends on PCI
14 select SND_SOC_SOF
15 select SND_SOC_ACPI if ACPI
16 select SND_SOC_SOF_OPTIONS
17 select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL
18 help
19 This adds support for PCI enumeration. This option is
20 required to enable Intel Skylake+ devices
21 Say Y if you need this option
22 If unsure select "N".
23
24config SND_SOC_SOF_ACPI
25 tristate "SOF ACPI enumeration support"
26 depends on ACPI || COMPILE_TEST
27 select SND_SOC_SOF
28 select SND_SOC_ACPI if ACPI
29 select SND_SOC_SOF_OPTIONS
30 select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL
31 select IOSF_MBI if X86 && PCI
32 help
33 This adds support for ACPI enumeration. This option is required
34 to enable Intel Haswell/Broadwell/Baytrail/Cherrytrail devices
35 Say Y if you need this option
36 If unsure select "N".
37
38config SND_SOC_SOF_OPTIONS
39 tristate
40 help
41 This option is not user-selectable but automagically handled by
42 'select' statements at a higher level
43
44if SND_SOC_SOF_OPTIONS
45
46config SND_SOC_SOF_NOCODEC
47 tristate "SOF nocodec mode Support"
48 help
49 This adds support for a dummy/nocodec machine driver fallback
50 option if no known codec is detected. This is typically only
51 enabled for developers or devices where the sound card is
52 controlled externally
53 Say Y if you need this nocodec fallback option
54 If unsure select "N".
55
56config SND_SOC_SOF_STRICT_ABI_CHECKS
57 bool "SOF strict ABI checks"
58 help
59 This option enables strict ABI checks for firmware and topology
60 files.
61 When these files are more recent than the kernel, the kernel
62 will handle the functionality it supports and may report errors
63 during topology creation or run-time usage if new functionality
64 is invoked.
65 This option will stop topology creation and firmware load upfront.
66 It is intended for SOF CI/releases and not for users or distros.
67 Say Y if you want strict ABI checks for an SOF release
68 If you are not involved in SOF releases and CI development
69 select "N".
70
71config SND_SOC_SOF_DEBUG
72 bool "SOF debugging features"
73 help
74 This option can be used to enable or disable individual SOF firmware
75 and driver debugging options.
76 Say Y if you are debugging SOF FW or drivers.
77 If unsure select "N".
78
79if SND_SOC_SOF_DEBUG
80
81config SND_SOC_SOF_FORCE_NOCODEC_MODE
82 bool "SOF force nocodec Mode"
83 depends on SND_SOC_SOF_NOCODEC
84 help
85 This forces SOF to use dummy/nocodec as machine driver, even
86 though there is a codec detected on the real platform. This is
87 typically only enabled for developers for debug purposes, before
88 codec/machine driver is ready, or to exclude the impact of those
89 drivers
90 Say Y if you need this force nocodec mode option
91 If unsure select "N".
92
93config SND_SOC_SOF_DEBUG_XRUN_STOP
94 bool "SOF stop on XRUN"
95 help
96 This option forces PCMs to stop on any XRUN event. This is useful to
97 preserve any trace data ond pipeline status prior to the XRUN.
98 Say Y if you are debugging SOF FW pipeline XRUNs.
99 If unsure select "N".
100
101config SND_SOC_SOF_DEBUG_VERBOSE_IPC
102 bool "SOF verbose IPC logs"
103 help
104 This option enables more verbose IPC logs, with command types in
105 human-readable form instead of just 32-bit hex dumps. This is useful
106 if you are trying to debug IPC with the DSP firmware.
107 If unsure select "N".
108
109config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION
110 bool "SOF force to use IPC for position update on SKL+"
111 help
112 This option force to handle stream position update IPCs and run pcm
113 elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that
114 with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM.
115 On platforms (e.g. Intel SKL-) where position update IPC is the only
116 one choice, this setting won't impact anything.
117 if you are trying to debug pointer update with position IPCs or where
118 DPIB/posbuf is not ready, select "Y".
119 If unsure select "N".
120
121config SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE
122 bool "SOF enable debugfs caching"
123 help
124 This option enables caching of debugfs
125 memory -> DSP resource (memory, register, etc)
126 before the audio DSP is suspended. This will increase the suspend
127 latency and therefore should be used for debug purposes only.
128 Say Y if you want to enable caching the memory windows.
129 If unsure, select "N".
130
131endif ## SND_SOC_SOF_DEBUG
132
133endif ## SND_SOC_SOF_OPTIONS
134
135config SND_SOC_SOF
136 tristate
137 select SND_SOC_TOPOLOGY
138 help
139 This option is not user-selectable but automagically handled by
140 'select' statements at a higher level
141 The selection is made at the top level and does not exactly follow
142 module dependencies but since the module or built-in type is decided
143 at the top level it doesn't matter.
144
145config SND_SOC_SOF_PROBE_WORK_QUEUE
146 bool
147 help
148 This option is not user-selectable but automagically handled by
149 'select' statements at a higher level
150 When selected, the probe is handled in two steps, for example to
151 avoid lockdeps if request_module is used in the probe.
152
153source "sound/soc/sof/intel/Kconfig"
154source "sound/soc/sof/xtensa/Kconfig"
155
156endif
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
new file mode 100644
index 000000000000..8f14c9d2950b
--- /dev/null
+++ b/sound/soc/sof/Makefile
@@ -0,0 +1,18 @@
1# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2
3snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
4 control.o trace.o utils.o
5
6snd-sof-pci-objs := sof-pci-dev.o
7snd-sof-acpi-objs := sof-acpi-dev.o
8snd-sof-nocodec-objs := nocodec.o
9
10obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o
11obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o
12
13
14obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o
15obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o
16
17obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/
18obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
new file mode 100644
index 000000000000..11762c4580f1
--- /dev/null
+++ b/sound/soc/sof/control.c
@@ -0,0 +1,552 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11/* Mixer Controls */
12
13#include <linux/pm_runtime.h>
14#include "sof-priv.h"
15
16static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
17{
18 if (value >= size)
19 return volume_map[size - 1];
20
21 return volume_map[value];
22}
23
24static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
25{
26 int i;
27
28 for (i = 0; i < size; i++) {
29 if (volume_map[i] >= value)
30 return i;
31 }
32
33 return i - 1;
34}
35
36int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
37 struct snd_ctl_elem_value *ucontrol)
38{
39 struct soc_mixer_control *sm =
40 (struct soc_mixer_control *)kcontrol->private_value;
41 struct snd_sof_control *scontrol = sm->dobj.private;
42 struct snd_sof_dev *sdev = scontrol->sdev;
43 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
44 unsigned int i, channels = scontrol->num_channels;
45 int err, ret;
46
47 ret = pm_runtime_get_sync(sdev->dev);
48 if (ret < 0) {
49 dev_err_ratelimited(sdev->dev,
50 "error: volume get failed to resume %d\n",
51 ret);
52 pm_runtime_put_noidle(sdev->dev);
53 return ret;
54 }
55
56 /* get all the mixer data from DSP */
57 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
58 SOF_IPC_COMP_GET_VALUE,
59 SOF_CTRL_TYPE_VALUE_CHAN_GET,
60 SOF_CTRL_CMD_VOLUME,
61 false);
62
63 /* read back each channel */
64 for (i = 0; i < channels; i++)
65 ucontrol->value.integer.value[i] =
66 ipc_to_mixer(cdata->chanv[i].value,
67 scontrol->volume_table, sm->max + 1);
68
69 pm_runtime_mark_last_busy(sdev->dev);
70 err = pm_runtime_put_autosuspend(sdev->dev);
71 if (err < 0)
72 dev_err_ratelimited(sdev->dev,
73 "error: volume get failed to idle %d\n",
74 err);
75 return 0;
76}
77
78int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
79 struct snd_ctl_elem_value *ucontrol)
80{
81 struct soc_mixer_control *sm =
82 (struct soc_mixer_control *)kcontrol->private_value;
83 struct snd_sof_control *scontrol = sm->dobj.private;
84 struct snd_sof_dev *sdev = scontrol->sdev;
85 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
86 unsigned int i, channels = scontrol->num_channels;
87 int ret, err;
88
89 ret = pm_runtime_get_sync(sdev->dev);
90 if (ret < 0) {
91 dev_err_ratelimited(sdev->dev,
92 "error: volume put failed to resume %d\n",
93 ret);
94 pm_runtime_put_noidle(sdev->dev);
95 return ret;
96 }
97
98 /* update each channel */
99 for (i = 0; i < channels; i++) {
100 cdata->chanv[i].value =
101 mixer_to_ipc(ucontrol->value.integer.value[i],
102 scontrol->volume_table, sm->max + 1);
103 cdata->chanv[i].channel = i;
104 }
105
106 /* notify DSP of mixer updates */
107 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
108 SOF_IPC_COMP_SET_VALUE,
109 SOF_CTRL_TYPE_VALUE_CHAN_GET,
110 SOF_CTRL_CMD_VOLUME,
111 true);
112
113 pm_runtime_mark_last_busy(sdev->dev);
114 err = pm_runtime_put_autosuspend(sdev->dev);
115 if (err < 0)
116 dev_err_ratelimited(sdev->dev,
117 "error: volume put failed to idle %d\n",
118 err);
119 return 0;
120}
121
122int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
123 struct snd_ctl_elem_value *ucontrol)
124{
125 struct soc_mixer_control *sm =
126 (struct soc_mixer_control *)kcontrol->private_value;
127 struct snd_sof_control *scontrol = sm->dobj.private;
128 struct snd_sof_dev *sdev = scontrol->sdev;
129 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
130 unsigned int i, channels = scontrol->num_channels;
131 int err, ret;
132
133 ret = pm_runtime_get_sync(sdev->dev);
134 if (ret < 0) {
135 dev_err_ratelimited(sdev->dev,
136 "error: switch get failed to resume %d\n",
137 ret);
138 pm_runtime_put_noidle(sdev->dev);
139 return ret;
140 }
141
142 /* get all the mixer data from DSP */
143 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
144 SOF_IPC_COMP_GET_VALUE,
145 SOF_CTRL_TYPE_VALUE_CHAN_GET,
146 SOF_CTRL_CMD_SWITCH,
147 false);
148
149 /* read back each channel */
150 for (i = 0; i < channels; i++)
151 ucontrol->value.integer.value[i] = cdata->chanv[i].value;
152
153 pm_runtime_mark_last_busy(sdev->dev);
154 err = pm_runtime_put_autosuspend(sdev->dev);
155 if (err < 0)
156 dev_err_ratelimited(sdev->dev,
157 "error: switch get failed to idle %d\n",
158 err);
159 return 0;
160}
161
162int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
163 struct snd_ctl_elem_value *ucontrol)
164{
165 struct soc_mixer_control *sm =
166 (struct soc_mixer_control *)kcontrol->private_value;
167 struct snd_sof_control *scontrol = sm->dobj.private;
168 struct snd_sof_dev *sdev = scontrol->sdev;
169 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
170 unsigned int i, channels = scontrol->num_channels;
171 int ret, err;
172
173 ret = pm_runtime_get_sync(sdev->dev);
174 if (ret < 0) {
175 dev_err_ratelimited(sdev->dev,
176 "error: switch put failed to resume %d\n",
177 ret);
178 pm_runtime_put_noidle(sdev->dev);
179 return ret;
180 }
181
182 /* update each channel */
183 for (i = 0; i < channels; i++) {
184 cdata->chanv[i].value = ucontrol->value.integer.value[i];
185 cdata->chanv[i].channel = i;
186 }
187
188 /* notify DSP of mixer updates */
189 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
190 SOF_IPC_COMP_SET_VALUE,
191 SOF_CTRL_TYPE_VALUE_CHAN_GET,
192 SOF_CTRL_CMD_SWITCH,
193 true);
194
195 pm_runtime_mark_last_busy(sdev->dev);
196 err = pm_runtime_put_autosuspend(sdev->dev);
197 if (err < 0)
198 dev_err_ratelimited(sdev->dev,
199 "error: switch put failed to idle %d\n",
200 err);
201 return 0;
202}
203
204int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
205 struct snd_ctl_elem_value *ucontrol)
206{
207 struct soc_enum *se =
208 (struct soc_enum *)kcontrol->private_value;
209 struct snd_sof_control *scontrol = se->dobj.private;
210 struct snd_sof_dev *sdev = scontrol->sdev;
211 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
212 unsigned int i, channels = scontrol->num_channels;
213 int err, ret;
214
215 ret = pm_runtime_get_sync(sdev->dev);
216 if (ret < 0) {
217 dev_err_ratelimited(sdev->dev,
218 "error: enum get failed to resume %d\n",
219 ret);
220 pm_runtime_put_noidle(sdev->dev);
221 return ret;
222 }
223
224 /* get all the enum data from DSP */
225 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
226 SOF_IPC_COMP_GET_VALUE,
227 SOF_CTRL_TYPE_VALUE_CHAN_GET,
228 SOF_CTRL_CMD_ENUM,
229 false);
230
231 /* read back each channel */
232 for (i = 0; i < channels; i++)
233 ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
234
235 pm_runtime_mark_last_busy(sdev->dev);
236 err = pm_runtime_put_autosuspend(sdev->dev);
237 if (err < 0)
238 dev_err_ratelimited(sdev->dev,
239 "error: enum get failed to idle %d\n",
240 err);
241 return 0;
242}
243
244int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
245 struct snd_ctl_elem_value *ucontrol)
246{
247 struct soc_enum *se =
248 (struct soc_enum *)kcontrol->private_value;
249 struct snd_sof_control *scontrol = se->dobj.private;
250 struct snd_sof_dev *sdev = scontrol->sdev;
251 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
252 unsigned int i, channels = scontrol->num_channels;
253 int ret, err;
254
255 ret = pm_runtime_get_sync(sdev->dev);
256 if (ret < 0) {
257 dev_err_ratelimited(sdev->dev,
258 "error: enum put failed to resume %d\n",
259 ret);
260 pm_runtime_put_noidle(sdev->dev);
261 return ret;
262 }
263
264 /* update each channel */
265 for (i = 0; i < channels; i++) {
266 cdata->chanv[i].value = ucontrol->value.enumerated.item[i];
267 cdata->chanv[i].channel = i;
268 }
269
270 /* notify DSP of enum updates */
271 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
272 SOF_IPC_COMP_SET_VALUE,
273 SOF_CTRL_TYPE_VALUE_CHAN_GET,
274 SOF_CTRL_CMD_ENUM,
275 true);
276
277 pm_runtime_mark_last_busy(sdev->dev);
278 err = pm_runtime_put_autosuspend(sdev->dev);
279 if (err < 0)
280 dev_err_ratelimited(sdev->dev,
281 "error: enum put failed to idle %d\n",
282 err);
283 return 0;
284}
285
286int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
287 struct snd_ctl_elem_value *ucontrol)
288{
289 struct soc_bytes_ext *be =
290 (struct soc_bytes_ext *)kcontrol->private_value;
291 struct snd_sof_control *scontrol = be->dobj.private;
292 struct snd_sof_dev *sdev = scontrol->sdev;
293 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
294 struct sof_abi_hdr *data = cdata->data;
295 size_t size;
296 int ret, err;
297
298 if (be->max > sizeof(ucontrol->value.bytes.data)) {
299 dev_err_ratelimited(sdev->dev,
300 "error: data max %d exceeds ucontrol data array size\n",
301 be->max);
302 return -EINVAL;
303 }
304
305 ret = pm_runtime_get_sync(sdev->dev);
306 if (ret < 0) {
307 dev_err_ratelimited(sdev->dev,
308 "error: bytes get failed to resume %d\n",
309 ret);
310 pm_runtime_put_noidle(sdev->dev);
311 return ret;
312 }
313
314 /* get all the binary data from DSP */
315 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
316 SOF_IPC_COMP_GET_DATA,
317 SOF_CTRL_TYPE_DATA_GET,
318 scontrol->cmd,
319 false);
320
321 size = data->size + sizeof(*data);
322 if (size > be->max) {
323 dev_err_ratelimited(sdev->dev,
324 "error: DSP sent %zu bytes max is %d\n",
325 size, be->max);
326 ret = -EINVAL;
327 goto out;
328 }
329
330 /* copy back to kcontrol */
331 memcpy(ucontrol->value.bytes.data, data, size);
332
333out:
334 pm_runtime_mark_last_busy(sdev->dev);
335 err = pm_runtime_put_autosuspend(sdev->dev);
336 if (err < 0)
337 dev_err_ratelimited(sdev->dev,
338 "error: bytes get failed to idle %d\n",
339 err);
340 return ret;
341}
342
343int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_value *ucontrol)
345{
346 struct soc_bytes_ext *be =
347 (struct soc_bytes_ext *)kcontrol->private_value;
348 struct snd_sof_control *scontrol = be->dobj.private;
349 struct snd_sof_dev *sdev = scontrol->sdev;
350 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
351 struct sof_abi_hdr *data = cdata->data;
352 int ret, err;
353
354 if (be->max > sizeof(ucontrol->value.bytes.data)) {
355 dev_err_ratelimited(sdev->dev,
356 "error: data max %d exceeds ucontrol data array size\n",
357 be->max);
358 return -EINVAL;
359 }
360
361 if (data->size > be->max) {
362 dev_err_ratelimited(sdev->dev,
363 "error: size too big %d bytes max is %d\n",
364 data->size, be->max);
365 return -EINVAL;
366 }
367
368 ret = pm_runtime_get_sync(sdev->dev);
369 if (ret < 0) {
370 dev_err_ratelimited(sdev->dev,
371 "error: bytes put failed to resume %d\n",
372 ret);
373 pm_runtime_put_noidle(sdev->dev);
374 return ret;
375 }
376
377 /* copy from kcontrol */
378 memcpy(data, ucontrol->value.bytes.data, data->size);
379
380 /* notify DSP of byte control updates */
381 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
382 SOF_IPC_COMP_SET_DATA,
383 SOF_CTRL_TYPE_DATA_SET,
384 scontrol->cmd,
385 true);
386
387 pm_runtime_mark_last_busy(sdev->dev);
388 err = pm_runtime_put_autosuspend(sdev->dev);
389 if (err < 0)
390 dev_err_ratelimited(sdev->dev,
391 "error: bytes put failed to idle %d\n",
392 err);
393 return ret;
394}
395
396int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
397 const unsigned int __user *binary_data,
398 unsigned int size)
399{
400 struct soc_bytes_ext *be =
401 (struct soc_bytes_ext *)kcontrol->private_value;
402 struct snd_sof_control *scontrol = be->dobj.private;
403 struct snd_sof_dev *sdev = scontrol->sdev;
404 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
405 struct snd_ctl_tlv header;
406 const struct snd_ctl_tlv __user *tlvd =
407 (const struct snd_ctl_tlv __user *)binary_data;
408 int ret;
409 int err;
410
411 /*
412 * The beginning of bytes data contains a header from where
413 * the length (as bytes) is needed to know the correct copy
414 * length of data from tlvd->tlv.
415 */
416 if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv)))
417 return -EFAULT;
418
419 /* be->max is coming from topology */
420 if (header.length > be->max) {
421 dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n",
422 header.length, be->max);
423 return -EINVAL;
424 }
425
426 /* Check that header id matches the command */
427 if (header.numid != scontrol->cmd) {
428 dev_err_ratelimited(sdev->dev,
429 "error: incorrect numid %d\n",
430 header.numid);
431 return -EINVAL;
432 }
433
434 if (copy_from_user(cdata->data, tlvd->tlv, header.length))
435 return -EFAULT;
436
437 if (cdata->data->magic != SOF_ABI_MAGIC) {
438 dev_err_ratelimited(sdev->dev,
439 "error: Wrong ABI magic 0x%08x.\n",
440 cdata->data->magic);
441 return -EINVAL;
442 }
443
444 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
445 dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n",
446 cdata->data->abi);
447 return -EINVAL;
448 }
449
450 if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) {
451 dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n");
452 return -EINVAL;
453 }
454
455 ret = pm_runtime_get_sync(sdev->dev);
456 if (ret < 0) {
457 dev_err_ratelimited(sdev->dev,
458 "error: bytes_ext put failed to resume %d\n",
459 ret);
460 pm_runtime_put_noidle(sdev->dev);
461 return ret;
462 }
463
464 /* notify DSP of byte control updates */
465 snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
466 SOF_IPC_COMP_SET_DATA,
467 SOF_CTRL_TYPE_DATA_SET,
468 scontrol->cmd,
469 true);
470
471 pm_runtime_mark_last_busy(sdev->dev);
472 err = pm_runtime_put_autosuspend(sdev->dev);
473 if (err < 0)
474 dev_err_ratelimited(sdev->dev,
475 "error: bytes_ext put failed to idle %d\n",
476 err);
477
478 return ret;
479}
480
481int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
482 unsigned int __user *binary_data,
483 unsigned int size)
484{
485 struct soc_bytes_ext *be =
486 (struct soc_bytes_ext *)kcontrol->private_value;
487 struct snd_sof_control *scontrol = be->dobj.private;
488 struct snd_sof_dev *sdev = scontrol->sdev;
489 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
490 struct snd_ctl_tlv header;
491 struct snd_ctl_tlv __user *tlvd =
492 (struct snd_ctl_tlv __user *)binary_data;
493 int data_size;
494 int err;
495 int ret;
496
497 ret = pm_runtime_get_sync(sdev->dev);
498 if (ret < 0) {
499 dev_err_ratelimited(sdev->dev,
500 "error: bytes_ext get failed to resume %d\n",
501 ret);
502 pm_runtime_put_noidle(sdev->dev);
503 return ret;
504 }
505
506 /*
507 * Decrement the limit by ext bytes header size to
508 * ensure the user space buffer is not exceeded.
509 */
510 size -= sizeof(const struct snd_ctl_tlv);
511
512 /* set the ABI header values */
513 cdata->data->magic = SOF_ABI_MAGIC;
514 cdata->data->abi = SOF_ABI_VERSION;
515
516 /* get all the component data from DSP */
517 ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
518 SOF_IPC_COMP_GET_DATA,
519 SOF_CTRL_TYPE_DATA_GET,
520 scontrol->cmd,
521 false);
522
523 /* Prevent read of other kernel data or possibly corrupt response */
524 data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
525
526 /* check data size doesn't exceed max coming from topology */
527 if (data_size > be->max) {
528 dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n",
529 data_size, be->max);
530 ret = -EINVAL;
531 goto out;
532 }
533
534 header.numid = scontrol->cmd;
535 header.length = data_size;
536 if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) {
537 ret = -EFAULT;
538 goto out;
539 }
540
541 if (copy_to_user(tlvd->tlv, cdata->data, data_size))
542 ret = -EFAULT;
543
544out:
545 pm_runtime_mark_last_busy(sdev->dev);
546 err = pm_runtime_put_autosuspend(sdev->dev);
547 if (err < 0)
548 dev_err_ratelimited(sdev->dev,
549 "error: bytes_ext get failed to idle %d\n",
550 err);
551 return ret;
552}
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
new file mode 100644
index 000000000000..32105e0fabe8
--- /dev/null
+++ b/sound/soc/sof/core.c
@@ -0,0 +1,508 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/firmware.h>
12#include <linux/module.h>
13#include <asm/unaligned.h>
14#include <sound/soc.h>
15#include <sound/sof.h>
16#include "sof-priv.h"
17#include "ops.h"
18
19/* SOF defaults if not provided by the platform in ms */
20#define TIMEOUT_DEFAULT_IPC_MS 5
21#define TIMEOUT_DEFAULT_BOOT_MS 100
22
23/*
24 * Generic object lookup APIs.
25 */
26
27struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
28 const char *name)
29{
30 struct snd_sof_pcm *spcm;
31
32 list_for_each_entry(spcm, &sdev->pcm_list, list) {
33 /* match with PCM dai name */
34 if (strcmp(spcm->pcm.dai_name, name) == 0)
35 return spcm;
36
37 /* match with playback caps name if set */
38 if (*spcm->pcm.caps[0].name &&
39 !strcmp(spcm->pcm.caps[0].name, name))
40 return spcm;
41
42 /* match with capture caps name if set */
43 if (*spcm->pcm.caps[1].name &&
44 !strcmp(spcm->pcm.caps[1].name, name))
45 return spcm;
46 }
47
48 return NULL;
49}
50
51struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
52 unsigned int comp_id,
53 int *direction)
54{
55 struct snd_sof_pcm *spcm;
56
57 list_for_each_entry(spcm, &sdev->pcm_list, list) {
58 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) {
59 *direction = SNDRV_PCM_STREAM_PLAYBACK;
60 return spcm;
61 }
62 if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) {
63 *direction = SNDRV_PCM_STREAM_CAPTURE;
64 return spcm;
65 }
66 }
67
68 return NULL;
69}
70
71struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
72 unsigned int pcm_id)
73{
74 struct snd_sof_pcm *spcm;
75
76 list_for_each_entry(spcm, &sdev->pcm_list, list) {
77 if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
78 return spcm;
79 }
80
81 return NULL;
82}
83
84struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
85 const char *name)
86{
87 struct snd_sof_widget *swidget;
88
89 list_for_each_entry(swidget, &sdev->widget_list, list) {
90 if (strcmp(name, swidget->widget->name) == 0)
91 return swidget;
92 }
93
94 return NULL;
95}
96
97/* find widget by stream name and direction */
98struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
99 const char *pcm_name, int dir)
100{
101 struct snd_sof_widget *swidget;
102 enum snd_soc_dapm_type type;
103
104 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
105 type = snd_soc_dapm_aif_in;
106 else
107 type = snd_soc_dapm_aif_out;
108
109 list_for_each_entry(swidget, &sdev->widget_list, list) {
110 if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type)
111 return swidget;
112 }
113
114 return NULL;
115}
116
117struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
118 const char *name)
119{
120 struct snd_sof_dai *dai;
121
122 list_for_each_entry(dai, &sdev->dai_list, list) {
123 if (dai->name && (strcmp(name, dai->name) == 0))
124 return dai;
125 }
126
127 return NULL;
128}
129
130/*
131 * FW Panic/fault handling.
132 */
133
134struct sof_panic_msg {
135 u32 id;
136 const char *msg;
137};
138
139/* standard FW panic types */
140static const struct sof_panic_msg panic_msg[] = {
141 {SOF_IPC_PANIC_MEM, "out of memory"},
142 {SOF_IPC_PANIC_WORK, "work subsystem init failed"},
143 {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"},
144 {SOF_IPC_PANIC_ARCH, "arch init failed"},
145 {SOF_IPC_PANIC_PLATFORM, "platform init failed"},
146 {SOF_IPC_PANIC_TASK, "scheduler init failed"},
147 {SOF_IPC_PANIC_EXCEPTION, "runtime exception"},
148 {SOF_IPC_PANIC_DEADLOCK, "deadlock"},
149 {SOF_IPC_PANIC_STACK, "stack overflow"},
150 {SOF_IPC_PANIC_IDLE, "can't enter idle"},
151 {SOF_IPC_PANIC_WFI, "invalid wait state"},
152 {SOF_IPC_PANIC_ASSERT, "assertion failed"},
153};
154
155/*
156 * helper to be called from .dbg_dump callbacks. No error code is
157 * provided, it's left as an exercise for the caller of .dbg_dump
158 * (typically IPC or loader)
159 */
160void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
161 u32 tracep_code, void *oops,
162 struct sof_ipc_panic_info *panic_info,
163 void *stack, size_t stack_words)
164{
165 u32 code;
166 int i;
167
168 /* is firmware dead ? */
169 if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) {
170 dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n",
171 panic_code, tracep_code);
172 return; /* no fault ? */
173 }
174
175 code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK);
176
177 for (i = 0; i < ARRAY_SIZE(panic_msg); i++) {
178 if (panic_msg[i].id == code) {
179 dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg);
180 dev_err(sdev->dev, "error: trace point %8.8x\n",
181 tracep_code);
182 goto out;
183 }
184 }
185
186 /* unknown error */
187 dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code);
188 dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code);
189
190out:
191 dev_err(sdev->dev, "error: panic at %s:%d\n",
192 panic_info->filename, panic_info->linenum);
193 sof_oops(sdev, oops);
194 sof_stack(sdev, oops, stack, stack_words);
195}
196EXPORT_SYMBOL(snd_sof_get_status);
197
198/*
199 * Generic buffer page table creation.
200 * Take the each physical page address and drop the least significant unused
201 * bits from each (based on PAGE_SIZE). Then pack valid page address bits
202 * into compressed page table.
203 */
204
205int snd_sof_create_page_table(struct snd_sof_dev *sdev,
206 struct snd_dma_buffer *dmab,
207 unsigned char *page_table, size_t size)
208{
209 int i, pages;
210
211 pages = snd_sgbuf_aligned_pages(size);
212
213 dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n",
214 dmab->area, size, pages);
215
216 for (i = 0; i < pages; i++) {
217 /*
218 * The number of valid address bits for each page is 20.
219 * idx determines the byte position within page_table
220 * where the current page's address is stored
221 * in the compressed page_table.
222 * This can be calculated by multiplying the page number by 2.5.
223 */
224 u32 idx = (5 * i) >> 1;
225 u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
226 u8 *pg_table;
227
228 dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
229
230 pg_table = (u8 *)(page_table + idx);
231
232 /*
233 * pagetable compression:
234 * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
235 * ___________pfn 0__________ __________pfn 1___________ _pfn 2...
236 * .... .... .... .... .... .... .... .... .... .... ....
237 * It is created by:
238 * 1. set current location to 0, PFN index i to 0
239 * 2. put pfn[i] at current location in Little Endian byte order
240 * 3. calculate an intermediate value as
241 * x = (pfn[i+1] << 4) | (pfn[i] & 0xf)
242 * 4. put x at offset (current location + 2) in LE byte order
243 * 5. increment current location by 5 bytes, increment i by 2
244 * 6. continue to (2)
245 */
246 if (i & 1)
247 put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4,
248 pg_table);
249 else
250 put_unaligned_le32(pfn, pg_table);
251 }
252
253 return pages;
254}
255
256/*
257 * SOF Driver enumeration.
258 */
259static int sof_machine_check(struct snd_sof_dev *sdev)
260{
261 struct snd_sof_pdata *plat_data = sdev->pdata;
262#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
263 struct snd_soc_acpi_mach *machine;
264 int ret;
265#endif
266
267 if (plat_data->machine)
268 return 0;
269
270#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)
271 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
272 return -ENODEV;
273#else
274 /* fallback to nocodec mode */
275 dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n");
276 machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL);
277 if (!machine)
278 return -ENOMEM;
279
280 ret = sof_nocodec_setup(sdev->dev, plat_data, machine,
281 plat_data->desc, plat_data->desc->ops);
282 if (ret < 0)
283 return ret;
284
285 plat_data->machine = machine;
286
287 return 0;
288#endif
289}
290
291static int sof_probe_continue(struct snd_sof_dev *sdev)
292{
293 struct snd_sof_pdata *plat_data = sdev->pdata;
294 const char *drv_name;
295 const void *mach;
296 int size;
297 int ret;
298
299 /* probe the DSP hardware */
300 ret = snd_sof_probe(sdev);
301 if (ret < 0) {
302 dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
303 return ret;
304 }
305
306 /* check machine info */
307 ret = sof_machine_check(sdev);
308 if (ret < 0) {
309 dev_err(sdev->dev, "error: failed to get machine info %d\n",
310 ret);
311 goto dbg_err;
312 }
313
314 /* set up platform component driver */
315 snd_sof_new_platform_drv(sdev);
316
317 /* register any debug/trace capabilities */
318 ret = snd_sof_dbg_init(sdev);
319 if (ret < 0) {
320 /*
321 * debugfs issues are suppressed in snd_sof_dbg_init() since
322 * we cannot rely on debugfs
323 * here we trap errors due to memory allocation only.
324 */
325 dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n",
326 ret);
327 goto dbg_err;
328 }
329
330 /* init the IPC */
331 sdev->ipc = snd_sof_ipc_init(sdev);
332 if (!sdev->ipc) {
333 dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret);
334 goto ipc_err;
335 }
336
337 /* load the firmware */
338 ret = snd_sof_load_firmware(sdev);
339 if (ret < 0) {
340 dev_err(sdev->dev, "error: failed to load DSP firmware %d\n",
341 ret);
342 goto fw_load_err;
343 }
344
345 /* boot the firmware */
346 ret = snd_sof_run_firmware(sdev);
347 if (ret < 0) {
348 dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n",
349 ret);
350 goto fw_run_err;
351 }
352
353 /* init DMA trace */
354 ret = snd_sof_init_trace(sdev);
355 if (ret < 0) {
356 /* non fatal */
357 dev_warn(sdev->dev,
358 "warning: failed to initialize trace %d\n", ret);
359 }
360
361 /* hereafter all FW boot flows are for PM reasons */
362 sdev->first_boot = false;
363
364 /* now register audio DSP platform driver and dai */
365 ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv,
366 sof_ops(sdev)->drv,
367 sof_ops(sdev)->num_drv);
368 if (ret < 0) {
369 dev_err(sdev->dev,
370 "error: failed to register DSP DAI driver %d\n", ret);
371 goto fw_run_err;
372 }
373
374 drv_name = plat_data->machine->drv_name;
375 mach = (const void *)plat_data->machine;
376 size = sizeof(*plat_data->machine);
377
378 /* register machine driver, pass machine info as pdata */
379 plat_data->pdev_mach =
380 platform_device_register_data(sdev->dev, drv_name,
381 PLATFORM_DEVID_NONE, mach, size);
382
383 if (IS_ERR(plat_data->pdev_mach)) {
384 ret = PTR_ERR(plat_data->pdev_mach);
385 goto comp_err;
386 }
387
388 dev_dbg(sdev->dev, "created machine %s\n",
389 dev_name(&plat_data->pdev_mach->dev));
390
391 if (plat_data->sof_probe_complete)
392 plat_data->sof_probe_complete(sdev->dev);
393
394 return 0;
395
396comp_err:
397 snd_soc_unregister_component(sdev->dev);
398fw_run_err:
399 snd_sof_fw_unload(sdev);
400fw_load_err:
401 snd_sof_ipc_free(sdev);
402ipc_err:
403 snd_sof_free_debug(sdev);
404dbg_err:
405 snd_sof_remove(sdev);
406
407 return ret;
408}
409
410static void sof_probe_work(struct work_struct *work)
411{
412 struct snd_sof_dev *sdev =
413 container_of(work, struct snd_sof_dev, probe_work);
414 int ret;
415
416 ret = sof_probe_continue(sdev);
417 if (ret < 0) {
418 /* errors cannot be propagated, log */
419 dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret);
420 }
421}
422
423int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
424{
425 struct snd_sof_dev *sdev;
426
427 sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
428 if (!sdev)
429 return -ENOMEM;
430
431 /* initialize sof device */
432 sdev->dev = dev;
433
434 sdev->pdata = plat_data;
435 sdev->first_boot = true;
436 dev_set_drvdata(dev, sdev);
437
438 /* check all mandatory ops */
439 if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run ||
440 !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
441 !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
442 !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params)
443 return -EINVAL;
444
445 INIT_LIST_HEAD(&sdev->pcm_list);
446 INIT_LIST_HEAD(&sdev->kcontrol_list);
447 INIT_LIST_HEAD(&sdev->widget_list);
448 INIT_LIST_HEAD(&sdev->dai_list);
449 INIT_LIST_HEAD(&sdev->route_list);
450 spin_lock_init(&sdev->ipc_lock);
451 spin_lock_init(&sdev->hw_lock);
452
453 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
454 INIT_WORK(&sdev->probe_work, sof_probe_work);
455
456 /* set default timeouts if none provided */
457 if (plat_data->desc->ipc_timeout == 0)
458 sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS;
459 else
460 sdev->ipc_timeout = plat_data->desc->ipc_timeout;
461 if (plat_data->desc->boot_timeout == 0)
462 sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS;
463 else
464 sdev->boot_timeout = plat_data->desc->boot_timeout;
465
466 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) {
467 schedule_work(&sdev->probe_work);
468 return 0;
469 }
470
471 return sof_probe_continue(sdev);
472}
473EXPORT_SYMBOL(snd_sof_device_probe);
474
475int snd_sof_device_remove(struct device *dev)
476{
477 struct snd_sof_dev *sdev = dev_get_drvdata(dev);
478 struct snd_sof_pdata *pdata = sdev->pdata;
479
480 if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
481 cancel_work_sync(&sdev->probe_work);
482
483 snd_sof_fw_unload(sdev);
484 snd_sof_ipc_free(sdev);
485 snd_sof_free_debug(sdev);
486 snd_sof_free_trace(sdev);
487 snd_sof_remove(sdev);
488
489 /*
490 * Unregister machine driver. This will unbind the snd_card which
491 * will remove the component driver and unload the topology
492 * before freeing the snd_card.
493 */
494 if (!IS_ERR_OR_NULL(pdata->pdev_mach))
495 platform_device_unregister(pdata->pdev_mach);
496
497 /* release firmware */
498 release_firmware(pdata->fw);
499 pdata->fw = NULL;
500
501 return 0;
502}
503EXPORT_SYMBOL(snd_sof_device_remove);
504
505MODULE_AUTHOR("Liam Girdwood");
506MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
507MODULE_LICENSE("Dual BSD/GPL");
508MODULE_ALIAS("platform:sof-audio");
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
new file mode 100644
index 000000000000..55f1d808dba0
--- /dev/null
+++ b/sound/soc/sof/debug.c
@@ -0,0 +1,232 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10// Generic debug routines used to export DSP MMIO and memories to userspace
11// for firmware debugging.
12//
13
14#include <linux/debugfs.h>
15#include <linux/io.h>
16#include <linux/pm_runtime.h>
17#include "sof-priv.h"
18#include "ops.h"
19
20static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer,
21 size_t count, loff_t *ppos)
22{
23 struct snd_sof_dfsentry *dfse = file->private_data;
24 struct snd_sof_dev *sdev = dfse->sdev;
25 loff_t pos = *ppos;
26 size_t size_ret;
27 int skip = 0;
28 int size;
29 u8 *buf;
30
31 size = dfse->size;
32
33 /* validate position & count */
34 if (pos < 0)
35 return -EINVAL;
36 if (pos >= size || !count)
37 return 0;
38 /* find the minimum. min() is not used since it adds sparse warnings */
39 if (count > size - pos)
40 count = size - pos;
41
42 /* align io read start to u32 multiple */
43 pos = ALIGN_DOWN(pos, 4);
44
45 /* intermediate buffer size must be u32 multiple */
46 size = ALIGN(count, 4);
47
48 /* if start position is unaligned, read extra u32 */
49 if (unlikely(pos != *ppos)) {
50 skip = *ppos - pos;
51 if (pos + size + 4 < dfse->size)
52 size += 4;
53 }
54
55 buf = kzalloc(size, GFP_KERNEL);
56 if (!buf)
57 return -ENOMEM;
58
59 if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) {
60#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
61 /*
62 * If the DSP is active: copy from IO.
63 * If the DSP is suspended:
64 * - Copy from IO if the memory is always accessible.
65 * - Otherwise, copy from cached buffer.
66 */
67 if (pm_runtime_active(sdev->dev) ||
68 dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) {
69 memcpy_fromio(buf, dfse->io_mem + pos, size);
70 } else {
71 dev_info(sdev->dev,
72 "Copying cached debugfs data\n");
73 memcpy(buf, dfse->cache_buf + pos, size);
74 }
75#else
76 /* if the DSP is in D3 */
77 if (!pm_runtime_active(sdev->dev) &&
78 dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) {
79 dev_err(sdev->dev,
80 "error: debugfs entry %s cannot be read in DSP D3\n",
81 dfse->dfsentry->d_name.name);
82 kfree(buf);
83 return -EINVAL;
84 }
85
86 memcpy_fromio(buf, dfse->io_mem + pos, size);
87#endif
88 } else {
89 memcpy(buf, ((u8 *)(dfse->buf) + pos), size);
90 }
91
92 /* copy to userspace */
93 size_ret = copy_to_user(buffer, buf + skip, count);
94
95 kfree(buf);
96
97 /* update count & position if copy succeeded */
98 if (size_ret)
99 return -EFAULT;
100
101 *ppos = pos + count;
102
103 return count;
104}
105
106static const struct file_operations sof_dfs_fops = {
107 .open = simple_open,
108 .read = sof_dfsentry_read,
109 .llseek = default_llseek,
110};
111
112/* create FS entry for debug files that can expose DSP memories, registers */
113int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev,
114 void __iomem *base, size_t size,
115 const char *name,
116 enum sof_debugfs_access_type access_type)
117{
118 struct snd_sof_dfsentry *dfse;
119
120 if (!sdev)
121 return -EINVAL;
122
123 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
124 if (!dfse)
125 return -ENOMEM;
126
127 dfse->type = SOF_DFSENTRY_TYPE_IOMEM;
128 dfse->io_mem = base;
129 dfse->size = size;
130 dfse->sdev = sdev;
131 dfse->access_type = access_type;
132
133#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
134 /*
135 * allocate cache buffer that will be used to save the mem window
136 * contents prior to suspend
137 */
138 if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) {
139 dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL);
140 if (!dfse->cache_buf)
141 return -ENOMEM;
142 }
143#endif
144
145 dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root,
146 dfse, &sof_dfs_fops);
147 if (!dfse->dfsentry) {
148 /* can't rely on debugfs, only log error and keep going */
149 dev_err(sdev->dev, "error: cannot create debugfs entry %s\n",
150 name);
151 } else {
152 /* add to dfsentry list */
153 list_add(&dfse->list, &sdev->dfsentry_list);
154
155 }
156
157 return 0;
158}
159EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item);
160
161/* create FS entry for debug files to expose kernel memory */
162int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
163 void *base, size_t size,
164 const char *name)
165{
166 struct snd_sof_dfsentry *dfse;
167
168 if (!sdev)
169 return -EINVAL;
170
171 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
172 if (!dfse)
173 return -ENOMEM;
174
175 dfse->type = SOF_DFSENTRY_TYPE_BUF;
176 dfse->buf = base;
177 dfse->size = size;
178 dfse->sdev = sdev;
179
180 dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root,
181 dfse, &sof_dfs_fops);
182 if (!dfse->dfsentry) {
183 /* can't rely on debugfs, only log error and keep going */
184 dev_err(sdev->dev, "error: cannot create debugfs entry %s\n",
185 name);
186 } else {
187 /* add to dfsentry list */
188 list_add(&dfse->list, &sdev->dfsentry_list);
189 }
190
191 return 0;
192}
193EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item);
194
195int snd_sof_dbg_init(struct snd_sof_dev *sdev)
196{
197 const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
198 const struct snd_sof_debugfs_map *map;
199 int i;
200 int err;
201
202 /* use "sof" as top level debugFS dir */
203 sdev->debugfs_root = debugfs_create_dir("sof", NULL);
204 if (IS_ERR_OR_NULL(sdev->debugfs_root)) {
205 dev_err(sdev->dev, "error: failed to create debugfs directory\n");
206 return 0;
207 }
208
209 /* init dfsentry list */
210 INIT_LIST_HEAD(&sdev->dfsentry_list);
211
212 /* create debugFS files for platform specific MMIO/DSP memories */
213 for (i = 0; i < ops->debug_map_count; i++) {
214 map = &ops->debug_map[i];
215
216 err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] +
217 map->offset, map->size,
218 map->name, map->access_type);
219 /* errors are only due to memory allocation, not debugfs */
220 if (err < 0)
221 return err;
222 }
223
224 return 0;
225}
226EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
227
228void snd_sof_free_debug(struct snd_sof_dev *sdev)
229{
230 debugfs_remove_recursive(sdev->debugfs_root);
231}
232EXPORT_SYMBOL_GPL(snd_sof_free_debug);
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
new file mode 100644
index 000000000000..603e0db4f012
--- /dev/null
+++ b/sound/soc/sof/intel/Kconfig
@@ -0,0 +1,230 @@
1config SND_SOC_SOF_INTEL_TOPLEVEL
2 bool "SOF support for Intel audio DSPs"
3 depends on X86 || COMPILE_TEST
4 help
5 This adds support for Sound Open Firmware for Intel(R) platforms.
6 Say Y if you have such a device.
7 If unsure select "N".
8
9if SND_SOC_SOF_INTEL_TOPLEVEL
10
11config SND_SOC_SOF_INTEL_ACPI
12 tristate
13 select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT
14 select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT
15 help
16 This option is not user-selectable but automagically handled by
17 'select' statements at a higher level
18
19config SND_SOC_SOF_INTEL_PCI
20 tristate
21 select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT
22 select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT
23 select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT
24 select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT
25 select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT
26 select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT
27 help
28 This option is not user-selectable but automagically handled by
29 'select' statements at a higher level
30
31config SND_SOC_SOF_INTEL_HIFI_EP_IPC
32 tristate
33 help
34 This option is not user-selectable but automagically handled by
35 'select' statements at a higher level
36
37config SND_SOC_SOF_INTEL_ATOM_HIFI_EP
38 tristate
39 select SND_SOC_SOF_INTEL_COMMON
40 select SND_SOC_SOF_INTEL_HIFI_EP_IPC
41 help
42 This option is not user-selectable but automagically handled by
43 'select' statements at a higher level
44
45config SND_SOC_SOF_INTEL_COMMON
46 tristate
47 select SND_SOC_ACPI_INTEL_MATCH
48 select SND_SOC_SOF_XTENSA
49 select SND_SOC_INTEL_MACH
50 select SND_SOC_ACPI if ACPI
51 help
52 This option is not user-selectable but automagically handled by
53 'select' statements at a higher level
54
55if SND_SOC_SOF_INTEL_ACPI
56
57config SND_SOC_SOF_BAYTRAIL_SUPPORT
58 bool "SOF support for Baytrail, Braswell and Cherrytrail"
59 help
60 This adds support for Sound Open Firmware for Intel(R) platforms
61 using the Baytrail, Braswell or Cherrytrail processors.
62 Say Y if you have such a device.
63 If unsure select "N".
64
65config SND_SOC_SOF_BAYTRAIL
66 tristate
67 select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
68 help
69 This option is not user-selectable but automagically handled by
70 'select' statements at a higher level
71
72config SND_SOC_SOF_BROADWELL_SUPPORT
73 bool "SOF support for Broadwell"
74 help
75 This adds support for Sound Open Firmware for Intel(R) platforms
76 using the Broadwell processors.
77 Say Y if you have such a device.
78 If unsure select "N".
79
80config SND_SOC_SOF_BROADWELL
81 tristate
82 select SND_SOC_SOF_INTEL_COMMON
83 select SND_SOC_SOF_INTEL_HIFI_EP_IPC
84 help
85 This option is not user-selectable but automagically handled by
86 'select' statements at a higher level
87
88endif ## SND_SOC_SOF_INTEL_ACPI
89
90if SND_SOC_SOF_INTEL_PCI
91
92config SND_SOC_SOF_MERRIFIELD_SUPPORT
93 bool "SOF support for Tangier/Merrifield"
94 help
95 This adds support for Sound Open Firmware for Intel(R) platforms
96 using the Tangier/Merrifield processors.
97 Say Y if you have such a device.
98 If unsure select "N".
99
100config SND_SOC_SOF_MERRIFIELD
101 tristate
102 select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
103 help
104 This option is not user-selectable but automagically handled by
105 'select' statements at a higher level
106
107config SND_SOC_SOF_APOLLOLAKE_SUPPORT
108 bool "SOF support for Apollolake"
109 help
110 This adds support for Sound Open Firmware for Intel(R) platforms
111 using the Apollolake processors.
112 Say Y if you have such a device.
113 If unsure select "N".
114
115config SND_SOC_SOF_APOLLOLAKE
116 tristate
117 select SND_SOC_SOF_HDA_COMMON
118 help
119 This option is not user-selectable but automagically handled by
120 'select' statements at a higher level
121
122config SND_SOC_SOF_GEMINILAKE_SUPPORT
123 bool "SOF support for GeminiLake"
124 help
125 This adds support for Sound Open Firmware for Intel(R) platforms
126 using the Geminilake processors.
127 Say Y if you have such a device.
128 If unsure select "N".
129
130config SND_SOC_SOF_GEMINILAKE
131 tristate
132 select SND_SOC_SOF_HDA_COMMON
133 help
134 This option is not user-selectable but automagically handled by
135 'select' statements at a higher level
136
137config SND_SOC_SOF_CANNONLAKE_SUPPORT
138 bool "SOF support for Cannonlake"
139 help
140 This adds support for Sound Open Firmware for Intel(R) platforms
141 using the Cannonlake processors.
142 Say Y if you have such a device.
143 If unsure select "N".
144
145config SND_SOC_SOF_CANNONLAKE
146 tristate
147 select SND_SOC_SOF_HDA_COMMON
148 help
149 This option is not user-selectable but automagically handled by
150 'select' statements at a higher level
151
152config SND_SOC_SOF_COFFEELAKE_SUPPORT
153 bool "SOF support for CoffeeLake"
154 help
155 This adds support for Sound Open Firmware for Intel(R) platforms
156 using the Coffeelake processors.
157 Say Y if you have such a device.
158 If unsure select "N".
159
160config SND_SOC_SOF_COFFEELAKE
161 tristate
162 select SND_SOC_SOF_HDA_COMMON
163 help
164 This option is not user-selectable but automagically handled by
165 'select' statements at a higher level
166
167config SND_SOC_SOF_ICELAKE_SUPPORT
168 bool "SOF support for Icelake"
169 help
170 This adds support for Sound Open Firmware for Intel(R) platforms
171 using the Icelake processors.
172 Say Y if you have such a device.
173 If unsure select "N".
174
175config SND_SOC_SOF_ICELAKE
176 tristate
177 select SND_SOC_SOF_HDA_COMMON
178 help
179 This option is not user-selectable but automagically handled by
180 'select' statements at a higher level
181
182config SND_SOC_SOF_HDA_COMMON
183 tristate
184 select SND_SOC_SOF_INTEL_COMMON
185 select SND_SOC_SOF_HDA_LINK_BASELINE
186 help
187 This option is not user-selectable but automagically handled by
188 'select' statements at a higher level
189
190if SND_SOC_SOF_HDA_COMMON
191
192config SND_SOC_SOF_HDA_LINK
193 bool "SOF support for HDA Links(HDA/HDMI)"
194 depends on SND_SOC_SOF_NOCODEC=n
195 select SND_SOC_SOF_PROBE_WORK_QUEUE
196 help
197 This adds support for HDA links(HDA/HDMI) with Sound Open Firmware
198 for Intel(R) platforms.
199 Say Y if you want to enable HDA links with SOF.
200 If unsure select "N".
201
202config SND_SOC_SOF_HDA_AUDIO_CODEC
203 bool "SOF support for HDAudio codecs"
204 depends on SND_SOC_SOF_HDA_LINK
205 help
206 This adds support for HDAudio codecs with Sound Open Firmware
207 for Intel(R) platforms.
208 Say Y if you want to enable HDAudio codecs with SOF.
209 If unsure select "N".
210
211endif ## SND_SOC_SOF_HDA_COMMON
212
213config SND_SOC_SOF_HDA_LINK_BASELINE
214 tristate
215 select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK
216 help
217 This option is not user-selectable but automagically handled by
218 'select' statements at a higher level
219
220config SND_SOC_SOF_HDA
221 tristate
222 select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
223 select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
224 help
225 This option is not user-selectable but automagically handled by
226 'select' statements at a higher level
227
228endif ## SND_SOC_SOF_INTEL_PCI
229
230endif ## SND_SOC_SOF_INTEL_TOPLEVEL
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
new file mode 100644
index 000000000000..b8f58e006e29
--- /dev/null
+++ b/sound/soc/sof/intel/Makefile
@@ -0,0 +1,19 @@
1# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2
3snd-sof-intel-byt-objs := byt.o
4snd-sof-intel-bdw-objs := bdw.o
5
6snd-sof-intel-ipc-objs := intel-ipc.o
7
8snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
9 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
10 hda-dai.o hda-bus.o \
11 apl.o cnl.o
12
13snd-sof-intel-hda-objs := hda-codec.o
14
15obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-byt.o
16obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o
17obj-$(CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC) += snd-sof-intel-ipc.o
18obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o
19obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
new file mode 100644
index 000000000000..f215d80dce2c
--- /dev/null
+++ b/sound/soc/sof/intel/apl.c
@@ -0,0 +1,113 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for audio DSP on Apollolake and GeminiLake
16 */
17
18#include "../sof-priv.h"
19#include "hda.h"
20
21static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = {
22 {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
23 {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
24 {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
25};
26
27/* apollolake ops */
28const struct snd_sof_dsp_ops sof_apl_ops = {
29 /* probe and remove */
30 .probe = hda_dsp_probe,
31 .remove = hda_dsp_remove,
32
33 /* Register IO */
34 .write = sof_io_write,
35 .read = sof_io_read,
36 .write64 = sof_io_write64,
37 .read64 = sof_io_read64,
38
39 /* Block IO */
40 .block_read = sof_block_read,
41 .block_write = sof_block_write,
42
43 /* doorbell */
44 .irq_handler = hda_dsp_ipc_irq_handler,
45 .irq_thread = hda_dsp_ipc_irq_thread,
46
47 /* ipc */
48 .send_msg = hda_dsp_ipc_send_msg,
49 .fw_ready = hda_dsp_ipc_fw_ready,
50
51 .ipc_msg_data = hda_ipc_msg_data,
52 .ipc_pcm_params = hda_ipc_pcm_params,
53
54 /* debug */
55 .debug_map = apl_dsp_debugfs,
56 .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs),
57 .dbg_dump = hda_dsp_dump,
58 .ipc_dump = hda_ipc_dump,
59
60 /* stream callbacks */
61 .pcm_open = hda_dsp_pcm_open,
62 .pcm_close = hda_dsp_pcm_close,
63 .pcm_hw_params = hda_dsp_pcm_hw_params,
64 .pcm_trigger = hda_dsp_pcm_trigger,
65 .pcm_pointer = hda_dsp_pcm_pointer,
66
67 /* firmware loading */
68 .load_firmware = snd_sof_load_firmware_raw,
69
70 /* firmware run */
71 .run = hda_dsp_cl_boot_firmware,
72
73 /* pre/post fw run */
74 .pre_fw_run = hda_dsp_pre_fw_run,
75 .post_fw_run = hda_dsp_post_fw_run,
76
77 /* dsp core power up/down */
78 .core_power_up = hda_dsp_enable_core,
79 .core_power_down = hda_dsp_core_reset_power_down,
80
81 /* trace callback */
82 .trace_init = hda_dsp_trace_init,
83 .trace_release = hda_dsp_trace_release,
84 .trace_trigger = hda_dsp_trace_trigger,
85
86 /* DAI drivers */
87 .drv = skl_dai,
88 .num_drv = SOF_SKL_NUM_DAIS,
89
90 /* PM */
91 .suspend = hda_dsp_suspend,
92 .resume = hda_dsp_resume,
93 .runtime_suspend = hda_dsp_runtime_suspend,
94 .runtime_resume = hda_dsp_runtime_resume,
95 .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
96};
97EXPORT_SYMBOL(sof_apl_ops);
98
99const struct sof_intel_dsp_desc apl_chip_info = {
100 /* Apollolake */
101 .cores_num = 2,
102 .init_core_mask = 1,
103 .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1),
104 .ipc_req = HDA_DSP_REG_HIPCI,
105 .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY,
106 .ipc_ack = HDA_DSP_REG_HIPCIE,
107 .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE,
108 .ipc_ctl = HDA_DSP_REG_HIPCCTL,
109 .rom_init_timeout = 150,
110 .ssp_count = APL_SSP_COUNT,
111 .ssp_base_offset = APL_SSP_BASE_OFFSET,
112};
113EXPORT_SYMBOL(apl_chip_info);
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
new file mode 100644
index 000000000000..065cb868bdfa
--- /dev/null
+++ b/sound/soc/sof/intel/bdw.c
@@ -0,0 +1,713 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11/*
12 * Hardware interface for audio DSP on Broadwell
13 */
14
15#include <linux/module.h>
16#include <sound/sof.h>
17#include <sound/sof/xtensa.h>
18#include "../ops.h"
19#include "shim.h"
20
21/* BARs */
22#define BDW_DSP_BAR 0
23#define BDW_PCI_BAR 1
24
25/*
26 * Debug
27 */
28
29/* DSP memories for BDW */
30#define IRAM_OFFSET 0xA0000
31#define BDW_IRAM_SIZE (10 * 32 * 1024)
32#define DRAM_OFFSET 0x00000
33#define BDW_DRAM_SIZE (20 * 32 * 1024)
34#define SHIM_OFFSET 0xFB000
35#define SHIM_SIZE 0x100
36#define MBOX_OFFSET 0x9E000
37#define MBOX_SIZE 0x1000
38#define MBOX_DUMP_SIZE 0x30
39#define EXCEPT_OFFSET 0x800
40
41/* DSP peripherals */
42#define DMAC0_OFFSET 0xFE000
43#define DMAC1_OFFSET 0xFF000
44#define DMAC_SIZE 0x420
45#define SSP0_OFFSET 0xFC000
46#define SSP1_OFFSET 0xFD000
47#define SSP_SIZE 0x100
48
49#define BDW_STACK_DUMP_SIZE 32
50
51#define BDW_PANIC_OFFSET(x) ((x) & 0xFFFF)
52
53static const struct snd_sof_debugfs_map bdw_debugfs[] = {
54 {"dmac0", BDW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE,
55 SOF_DEBUGFS_ACCESS_ALWAYS},
56 {"dmac1", BDW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE,
57 SOF_DEBUGFS_ACCESS_ALWAYS},
58 {"ssp0", BDW_DSP_BAR, SSP0_OFFSET, SSP_SIZE,
59 SOF_DEBUGFS_ACCESS_ALWAYS},
60 {"ssp1", BDW_DSP_BAR, SSP1_OFFSET, SSP_SIZE,
61 SOF_DEBUGFS_ACCESS_ALWAYS},
62 {"iram", BDW_DSP_BAR, IRAM_OFFSET, BDW_IRAM_SIZE,
63 SOF_DEBUGFS_ACCESS_D0_ONLY},
64 {"dram", BDW_DSP_BAR, DRAM_OFFSET, BDW_DRAM_SIZE,
65 SOF_DEBUGFS_ACCESS_D0_ONLY},
66 {"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE,
67 SOF_DEBUGFS_ACCESS_ALWAYS},
68};
69
70static void bdw_host_done(struct snd_sof_dev *sdev);
71static void bdw_dsp_done(struct snd_sof_dev *sdev);
72static void bdw_get_reply(struct snd_sof_dev *sdev);
73
74/*
75 * DSP Control.
76 */
77
78static int bdw_run(struct snd_sof_dev *sdev)
79{
80 /* set opportunistic mode on engine 0,1 for all channels */
81 snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC,
82 SHIM_HMDC_HDDA_E0_ALLCH |
83 SHIM_HMDC_HDDA_E1_ALLCH, 0);
84
85 /* set DSP to RUN */
86 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR,
87 SHIM_CSR_STALL, 0x0);
88
89 /* return init core mask */
90 return 1;
91}
92
93static int bdw_reset(struct snd_sof_dev *sdev)
94{
95 /* put DSP into reset and stall */
96 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR,
97 SHIM_CSR_RST | SHIM_CSR_STALL,
98 SHIM_CSR_RST | SHIM_CSR_STALL);
99
100 /* keep in reset for 10ms */
101 mdelay(10);
102
103 /* take DSP out of reset and keep stalled for FW loading */
104 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR,
105 SHIM_CSR_RST | SHIM_CSR_STALL,
106 SHIM_CSR_STALL);
107
108 return 0;
109}
110
111static int bdw_set_dsp_D0(struct snd_sof_dev *sdev)
112{
113 int tries = 10;
114 u32 reg;
115
116 /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
117 snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2,
118 PCI_VDRTCL2_DCLCGE |
119 PCI_VDRTCL2_DTCGE, 0);
120
121 /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
122 snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL0,
123 PCI_VDRTCL0_D3PGD, PCI_VDRTCL0_D3PGD);
124
125 /* Set D0 state */
126 snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_PMCS,
127 PCI_PMCS_PS_MASK, 0);
128
129 /* check that ADSP shim is enabled */
130 while (tries--) {
131 reg = readl(sdev->bar[BDW_PCI_BAR] + PCI_PMCS)
132 & PCI_PMCS_PS_MASK;
133 if (reg == 0)
134 goto finish;
135
136 msleep(20);
137 }
138
139 return -ENODEV;
140
141finish:
142 /*
143 * select SSP1 19.2MHz base clock, SSP clock 0,
144 * turn off Low Power Clock
145 */
146 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR,
147 SHIM_CSR_S1IOCS | SHIM_CSR_SBCS1 |
148 SHIM_CSR_LPCS, 0x0);
149
150 /* stall DSP core, set clk to 192/96Mhz */
151 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR,
152 SHIM_CSR, SHIM_CSR_STALL |
153 SHIM_CSR_DCS_MASK,
154 SHIM_CSR_STALL |
155 SHIM_CSR_DCS(4));
156
157 /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
158 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CLKCTL,
159 SHIM_CLKCTL_MASK |
160 SHIM_CLKCTL_DCPLCG |
161 SHIM_CLKCTL_SCOE0,
162 SHIM_CLKCTL_MASK |
163 SHIM_CLKCTL_DCPLCG |
164 SHIM_CLKCTL_SCOE0);
165
166 /* Stall and reset core, set CSR */
167 bdw_reset(sdev);
168
169 /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
170 snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2,
171 PCI_VDRTCL2_DCLCGE |
172 PCI_VDRTCL2_DTCGE,
173 PCI_VDRTCL2_DCLCGE |
174 PCI_VDRTCL2_DTCGE);
175
176 usleep_range(50, 55);
177
178 /* switch on audio PLL */
179 snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2,
180 PCI_VDRTCL2_APLLSE_MASK, 0);
181
182 /*
183 * set default power gating control, enable power gating control for
184 * all blocks. that is, can't be accessed, please enable each block
185 * before accessing.
186 */
187 snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL0,
188 0xfffffffC, 0x0);
189
190 /* disable DMA finish function for SSP0 & SSP1 */
191 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR2,
192 SHIM_CSR2_SDFD_SSP1,
193 SHIM_CSR2_SDFD_SSP1);
194
195 /* set on-demond mode on engine 0,1 for all channels */
196 snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC,
197 SHIM_HMDC_HDDA_E0_ALLCH |
198 SHIM_HMDC_HDDA_E1_ALLCH,
199 SHIM_HMDC_HDDA_E0_ALLCH |
200 SHIM_HMDC_HDDA_E1_ALLCH);
201
202 /* Enable Interrupt from both sides */
203 snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_IMRX,
204 (SHIM_IMRX_BUSY | SHIM_IMRX_DONE), 0x0);
205 snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_IMRD,
206 (SHIM_IMRD_DONE | SHIM_IMRD_BUSY |
207 SHIM_IMRD_SSP0 | SHIM_IMRD_DMAC), 0x0);
208
209 /* clear IPC registers */
210 snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, 0x0);
211 snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCD, 0x0);
212 snd_sof_dsp_write(sdev, BDW_DSP_BAR, 0x80, 0x6);
213 snd_sof_dsp_write(sdev, BDW_DSP_BAR, 0xe0, 0x300a);
214
215 return 0;
216}
217
218static void bdw_get_registers(struct snd_sof_dev *sdev,
219 struct sof_ipc_dsp_oops_xtensa *xoops,
220 struct sof_ipc_panic_info *panic_info,
221 u32 *stack, size_t stack_words)
222{
223 /* first read regsisters */
224 sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops));
225
226 /* then get panic info */
227 sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops),
228 panic_info, sizeof(*panic_info));
229
230 /* then get the stack */
231 sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) +
232 sizeof(*panic_info), stack,
233 stack_words * sizeof(u32));
234}
235
236static void bdw_dump(struct snd_sof_dev *sdev, u32 flags)
237{
238 struct sof_ipc_dsp_oops_xtensa xoops;
239 struct sof_ipc_panic_info panic_info;
240 u32 stack[BDW_STACK_DUMP_SIZE];
241 u32 status, panic;
242
243 /* now try generic SOF status messages */
244 status = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD);
245 panic = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX);
246 bdw_get_registers(sdev, &xoops, &panic_info, stack,
247 BDW_STACK_DUMP_SIZE);
248 snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack,
249 BDW_STACK_DUMP_SIZE);
250}
251
252/*
253 * IPC Doorbell IRQ handler and thread.
254 */
255
256static irqreturn_t bdw_irq_handler(int irq, void *context)
257{
258 struct snd_sof_dev *sdev = context;
259 u32 isr;
260 int ret = IRQ_NONE;
261
262 /* Interrupt arrived, check src */
263 isr = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_ISRX);
264 if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY))
265 ret = IRQ_WAKE_THREAD;
266
267 return ret;
268}
269
270static irqreturn_t bdw_irq_thread(int irq, void *context)
271{
272 struct snd_sof_dev *sdev = context;
273 u32 ipcx, ipcd, imrx;
274
275 imrx = snd_sof_dsp_read64(sdev, BDW_DSP_BAR, SHIM_IMRX);
276 ipcx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX);
277
278 /* reply message from DSP */
279 if (ipcx & SHIM_IPCX_DONE &&
280 !(imrx & SHIM_IMRX_DONE)) {
281 /* Mask Done interrupt before return */
282 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR,
283 SHIM_IMRX, SHIM_IMRX_DONE,
284 SHIM_IMRX_DONE);
285
286 /*
287 * handle immediate reply from DSP core. If the msg is
288 * found, set done bit in cmd_done which is called at the
289 * end of message processing function, else set it here
290 * because the done bit can't be set in cmd_done function
291 * which is triggered by msg
292 */
293 bdw_get_reply(sdev);
294 snd_sof_ipc_reply(sdev, ipcx);
295
296 bdw_dsp_done(sdev);
297 }
298
299 ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD);
300
301 /* new message from DSP */
302 if (ipcd & SHIM_IPCD_BUSY &&
303 !(imrx & SHIM_IMRX_BUSY)) {
304 /* Mask Busy interrupt before return */
305 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR,
306 SHIM_IMRX, SHIM_IMRX_BUSY,
307 SHIM_IMRX_BUSY);
308
309 /* Handle messages from DSP Core */
310 if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
311 snd_sof_dsp_panic(sdev, BDW_PANIC_OFFSET(ipcx) +
312 MBOX_OFFSET);
313 } else {
314 snd_sof_ipc_msgs_rx(sdev);
315 }
316
317 bdw_host_done(sdev);
318 }
319
320 return IRQ_HANDLED;
321}
322
323/*
324 * IPC Firmware ready.
325 */
326static void bdw_get_windows(struct snd_sof_dev *sdev)
327{
328 struct sof_ipc_window_elem *elem;
329 u32 outbox_offset = 0;
330 u32 stream_offset = 0;
331 u32 inbox_offset = 0;
332 u32 outbox_size = 0;
333 u32 stream_size = 0;
334 u32 inbox_size = 0;
335 int i;
336
337 if (!sdev->info_window) {
338 dev_err(sdev->dev, "error: have no window info\n");
339 return;
340 }
341
342 for (i = 0; i < sdev->info_window->num_windows; i++) {
343 elem = &sdev->info_window->window[i];
344
345 switch (elem->type) {
346 case SOF_IPC_REGION_UPBOX:
347 inbox_offset = elem->offset + MBOX_OFFSET;
348 inbox_size = elem->size;
349 snd_sof_debugfs_io_item(sdev,
350 sdev->bar[BDW_DSP_BAR] +
351 inbox_offset,
352 elem->size, "inbox",
353 SOF_DEBUGFS_ACCESS_D0_ONLY);
354 break;
355 case SOF_IPC_REGION_DOWNBOX:
356 outbox_offset = elem->offset + MBOX_OFFSET;
357 outbox_size = elem->size;
358 snd_sof_debugfs_io_item(sdev,
359 sdev->bar[BDW_DSP_BAR] +
360 outbox_offset,
361 elem->size, "outbox",
362 SOF_DEBUGFS_ACCESS_D0_ONLY);
363 break;
364 case SOF_IPC_REGION_TRACE:
365 snd_sof_debugfs_io_item(sdev,
366 sdev->bar[BDW_DSP_BAR] +
367 elem->offset +
368 MBOX_OFFSET,
369 elem->size, "etrace",
370 SOF_DEBUGFS_ACCESS_D0_ONLY);
371 break;
372 case SOF_IPC_REGION_DEBUG:
373 snd_sof_debugfs_io_item(sdev,
374 sdev->bar[BDW_DSP_BAR] +
375 elem->offset +
376 MBOX_OFFSET,
377 elem->size, "debug",
378 SOF_DEBUGFS_ACCESS_D0_ONLY);
379 break;
380 case SOF_IPC_REGION_STREAM:
381 stream_offset = elem->offset + MBOX_OFFSET;
382 stream_size = elem->size;
383 snd_sof_debugfs_io_item(sdev,
384 sdev->bar[BDW_DSP_BAR] +
385 stream_offset,
386 elem->size, "stream",
387 SOF_DEBUGFS_ACCESS_D0_ONLY);
388 break;
389 case SOF_IPC_REGION_REGS:
390 snd_sof_debugfs_io_item(sdev,
391 sdev->bar[BDW_DSP_BAR] +
392 elem->offset +
393 MBOX_OFFSET,
394 elem->size, "regs",
395 SOF_DEBUGFS_ACCESS_D0_ONLY);
396 break;
397 case SOF_IPC_REGION_EXCEPTION:
398 sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET;
399 snd_sof_debugfs_io_item(sdev,
400 sdev->bar[BDW_DSP_BAR] +
401 elem->offset +
402 MBOX_OFFSET,
403 elem->size, "exception",
404 SOF_DEBUGFS_ACCESS_D0_ONLY);
405 break;
406 default:
407 dev_err(sdev->dev, "error: get illegal window info\n");
408 return;
409 }
410 }
411
412 if (outbox_size == 0 || inbox_size == 0) {
413 dev_err(sdev->dev, "error: get illegal mailbox window\n");
414 return;
415 }
416
417 snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
418 outbox_offset, outbox_size);
419 sdev->stream_box.offset = stream_offset;
420 sdev->stream_box.size = stream_size;
421
422 dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
423 inbox_offset, inbox_size);
424 dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
425 outbox_offset, outbox_size);
426 dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
427 stream_offset, stream_size);
428}
429
430/* check for ABI compatibility and create memory windows on first boot */
431static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
432{
433 struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
434 u32 offset;
435 int ret;
436
437 /* mailbox must be on 4k boundary */
438 offset = MBOX_OFFSET;
439
440 dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
441 msg_id, offset);
442
443 /* no need to re-check version/ABI for subsequent boots */
444 if (!sdev->first_boot)
445 return 0;
446
447 /* copy data from the DSP FW ready offset */
448 sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready,
449 sizeof(*fw_ready));
450
451 snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset,
452 fw_ready->dspbox_size,
453 fw_ready->hostbox_offset,
454 fw_ready->hostbox_size);
455
456 /* make sure ABI version is compatible */
457 ret = snd_sof_ipc_valid(sdev);
458 if (ret < 0)
459 return ret;
460
461 /* now check for extended data */
462 snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET +
463 sizeof(struct sof_ipc_fw_ready));
464
465 bdw_get_windows(sdev);
466
467 return 0;
468}
469
470/*
471 * IPC Mailbox IO
472 */
473
474static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
475{
476 /* send the message */
477 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
478 msg->msg_size);
479 snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY);
480
481 return 0;
482}
483
484static void bdw_get_reply(struct snd_sof_dev *sdev)
485{
486 struct snd_sof_ipc_msg *msg = sdev->msg;
487 struct sof_ipc_reply reply;
488 unsigned long flags;
489 int ret = 0;
490
491 /*
492 * Sometimes, there is unexpected reply ipc arriving. The reply
493 * ipc belongs to none of the ipcs sent from driver.
494 * In this case, the driver must ignore the ipc.
495 */
496 if (!msg) {
497 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
498 return;
499 }
500
501 /* get reply */
502 sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
503
504 spin_lock_irqsave(&sdev->ipc_lock, flags);
505
506 if (reply.error < 0) {
507 memcpy(msg->reply_data, &reply, sizeof(reply));
508 ret = reply.error;
509 } else {
510 /* reply correct size ? */
511 if (reply.hdr.size != msg->reply_size) {
512 dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
513 msg->reply_size, reply.hdr.size);
514 ret = -EINVAL;
515 }
516
517 /* read the message */
518 if (msg->reply_size > 0)
519 sof_mailbox_read(sdev, sdev->host_box.offset,
520 msg->reply_data, msg->reply_size);
521 }
522
523 msg->reply_error = ret;
524
525 spin_unlock_irqrestore(&sdev->ipc_lock, flags);
526}
527
528static void bdw_host_done(struct snd_sof_dev *sdev)
529{
530 /* clear BUSY bit and set DONE bit - accept new messages */
531 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD,
532 SHIM_IPCD_BUSY | SHIM_IPCD_DONE,
533 SHIM_IPCD_DONE);
534
535 /* unmask busy interrupt */
536 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX,
537 SHIM_IMRX_BUSY, 0);
538}
539
540static void bdw_dsp_done(struct snd_sof_dev *sdev)
541{
542 /* clear DONE bit - tell DSP we have completed */
543 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX,
544 SHIM_IPCX_DONE, 0);
545
546 /* unmask Done interrupt */
547 snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX,
548 SHIM_IMRX_DONE, 0);
549}
550
551/*
552 * Probe and remove.
553 */
554static int bdw_probe(struct snd_sof_dev *sdev)
555{
556 struct snd_sof_pdata *pdata = sdev->pdata;
557 const struct sof_dev_desc *desc = pdata->desc;
558 struct platform_device *pdev =
559 container_of(sdev->dev, struct platform_device, dev);
560 struct resource *mmio;
561 u32 base, size;
562 int ret;
563
564 /* LPE base */
565 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
566 desc->resindex_lpe_base);
567 if (mmio) {
568 base = mmio->start;
569 size = resource_size(mmio);
570 } else {
571 dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n",
572 desc->resindex_lpe_base);
573 return -EINVAL;
574 }
575
576 dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size);
577 sdev->bar[BDW_DSP_BAR] = devm_ioremap(sdev->dev, base, size);
578 if (!sdev->bar[BDW_DSP_BAR]) {
579 dev_err(sdev->dev,
580 "error: failed to ioremap LPE base 0x%x size 0x%x\n",
581 base, size);
582 return -ENODEV;
583 }
584 dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BDW_DSP_BAR]);
585
586 /* TODO: add offsets */
587 sdev->mmio_bar = BDW_DSP_BAR;
588 sdev->mailbox_bar = BDW_DSP_BAR;
589
590 /* PCI base */
591 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
592 desc->resindex_pcicfg_base);
593 if (mmio) {
594 base = mmio->start;
595 size = resource_size(mmio);
596 } else {
597 dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n",
598 desc->resindex_pcicfg_base);
599 return -ENODEV;
600 }
601
602 dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size);
603 sdev->bar[BDW_PCI_BAR] = devm_ioremap(sdev->dev, base, size);
604 if (!sdev->bar[BDW_PCI_BAR]) {
605 dev_err(sdev->dev,
606 "error: failed to ioremap PCI base 0x%x size 0x%x\n",
607 base, size);
608 return -ENODEV;
609 }
610 dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[BDW_PCI_BAR]);
611
612 /* register our IRQ */
613 sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
614 if (sdev->ipc_irq < 0) {
615 dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
616 desc->irqindex_host_ipc);
617 return sdev->ipc_irq;
618 }
619
620 dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
621 ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
622 bdw_irq_handler, bdw_irq_thread,
623 IRQF_SHARED, "AudioDSP", sdev);
624 if (ret < 0) {
625 dev_err(sdev->dev, "error: failed to register IRQ %d\n",
626 sdev->ipc_irq);
627 return ret;
628 }
629
630 /* enable the DSP SHIM */
631 ret = bdw_set_dsp_D0(sdev);
632 if (ret < 0) {
633 dev_err(sdev->dev, "error: failed to set DSP D0\n");
634 return ret;
635 }
636
637 /* DSP DMA can only access low 31 bits of host memory */
638 ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31));
639 if (ret < 0) {
640 dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret);
641 return ret;
642 }
643
644 /* set default mailbox */
645 snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0);
646
647 return ret;
648}
649
650/* Broadwell DAIs */
651static struct snd_soc_dai_driver bdw_dai[] = {
652{
653 .name = "ssp0-port",
654},
655{
656 .name = "ssp1-port",
657},
658};
659
660/* broadwell ops */
661const struct snd_sof_dsp_ops sof_bdw_ops = {
662 /*Device init */
663 .probe = bdw_probe,
664
665 /* DSP Core Control */
666 .run = bdw_run,
667 .reset = bdw_reset,
668
669 /* Register IO */
670 .write = sof_io_write,
671 .read = sof_io_read,
672 .write64 = sof_io_write64,
673 .read64 = sof_io_read64,
674
675 /* Block IO */
676 .block_read = sof_block_read,
677 .block_write = sof_block_write,
678
679 /* ipc */
680 .send_msg = bdw_send_msg,
681 .fw_ready = bdw_fw_ready,
682
683 .ipc_msg_data = intel_ipc_msg_data,
684 .ipc_pcm_params = intel_ipc_pcm_params,
685
686 /* debug */
687 .debug_map = bdw_debugfs,
688 .debug_map_count = ARRAY_SIZE(bdw_debugfs),
689 .dbg_dump = bdw_dump,
690
691 /* stream callbacks */
692 .pcm_open = intel_pcm_open,
693 .pcm_close = intel_pcm_close,
694
695 /* Module loading */
696 .load_module = snd_sof_parse_module_memcpy,
697
698 /*Firmware loading */
699 .load_firmware = snd_sof_load_firmware_memcpy,
700
701 /* DAI drivers */
702 .drv = bdw_dai,
703 .num_drv = ARRAY_SIZE(bdw_dai)
704};
705EXPORT_SYMBOL(sof_bdw_ops);
706
707const struct sof_intel_dsp_desc bdw_chip_info = {
708 .cores_num = 1,
709 .cores_mask = 1,
710};
711EXPORT_SYMBOL(bdw_chip_info);
712
713MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
new file mode 100644
index 000000000000..7bf9143d3106
--- /dev/null
+++ b/sound/soc/sof/intel/byt.c
@@ -0,0 +1,874 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11/*
12 * Hardware interface for audio DSP on Baytrail, Braswell and Cherrytrail.
13 */
14
15#include <linux/module.h>
16#include <sound/sof.h>
17#include <sound/sof/xtensa.h>
18#include "../ops.h"
19#include "shim.h"
20
21/* DSP memories */
22#define IRAM_OFFSET 0x0C0000
23#define IRAM_SIZE (80 * 1024)
24#define DRAM_OFFSET 0x100000
25#define DRAM_SIZE (160 * 1024)
26#define SHIM_OFFSET 0x140000
27#define SHIM_SIZE 0x100
28#define MBOX_OFFSET 0x144000
29#define MBOX_SIZE 0x1000
30#define EXCEPT_OFFSET 0x800
31
32/* DSP peripherals */
33#define DMAC0_OFFSET 0x098000
34#define DMAC1_OFFSET 0x09c000
35#define DMAC2_OFFSET 0x094000
36#define DMAC_SIZE 0x420
37#define SSP0_OFFSET 0x0a0000
38#define SSP1_OFFSET 0x0a1000
39#define SSP2_OFFSET 0x0a2000
40#define SSP3_OFFSET 0x0a4000
41#define SSP4_OFFSET 0x0a5000
42#define SSP5_OFFSET 0x0a6000
43#define SSP_SIZE 0x100
44
45#define BYT_STACK_DUMP_SIZE 32
46
47#define BYT_PCI_BAR_SIZE 0x200000
48
49#define BYT_PANIC_OFFSET(x) (((x) & GENMASK_ULL(47, 32)) >> 32)
50
51/*
52 * Debug
53 */
54
55#define MBOX_DUMP_SIZE 0x30
56
57/* BARs */
58#define BYT_DSP_BAR 0
59#define BYT_PCI_BAR 1
60#define BYT_IMR_BAR 2
61
62static const struct snd_sof_debugfs_map byt_debugfs[] = {
63 {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE,
64 SOF_DEBUGFS_ACCESS_ALWAYS},
65 {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE,
66 SOF_DEBUGFS_ACCESS_ALWAYS},
67 {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE,
68 SOF_DEBUGFS_ACCESS_ALWAYS},
69 {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE,
70 SOF_DEBUGFS_ACCESS_ALWAYS},
71 {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE,
72 SOF_DEBUGFS_ACCESS_ALWAYS},
73 {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE,
74 SOF_DEBUGFS_ACCESS_D0_ONLY},
75 {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
76 SOF_DEBUGFS_ACCESS_D0_ONLY},
77 {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE,
78 SOF_DEBUGFS_ACCESS_ALWAYS},
79};
80
81static const struct snd_sof_debugfs_map cht_debugfs[] = {
82 {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE,
83 SOF_DEBUGFS_ACCESS_ALWAYS},
84 {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE,
85 SOF_DEBUGFS_ACCESS_ALWAYS},
86 {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE,
87 SOF_DEBUGFS_ACCESS_ALWAYS},
88 {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE,
89 SOF_DEBUGFS_ACCESS_ALWAYS},
90 {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE,
91 SOF_DEBUGFS_ACCESS_ALWAYS},
92 {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE,
93 SOF_DEBUGFS_ACCESS_ALWAYS},
94 {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE,
95 SOF_DEBUGFS_ACCESS_ALWAYS},
96 {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE,
97 SOF_DEBUGFS_ACCESS_ALWAYS},
98 {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE,
99 SOF_DEBUGFS_ACCESS_ALWAYS},
100 {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE,
101 SOF_DEBUGFS_ACCESS_D0_ONLY},
102 {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE,
103 SOF_DEBUGFS_ACCESS_D0_ONLY},
104 {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE,
105 SOF_DEBUGFS_ACCESS_ALWAYS},
106};
107
108static void byt_host_done(struct snd_sof_dev *sdev);
109static void byt_dsp_done(struct snd_sof_dev *sdev);
110static void byt_get_reply(struct snd_sof_dev *sdev);
111
112/*
113 * IPC Firmware ready.
114 */
115static void byt_get_windows(struct snd_sof_dev *sdev)
116{
117 struct sof_ipc_window_elem *elem;
118 u32 outbox_offset = 0;
119 u32 stream_offset = 0;
120 u32 inbox_offset = 0;
121 u32 outbox_size = 0;
122 u32 stream_size = 0;
123 u32 inbox_size = 0;
124 int i;
125
126 if (!sdev->info_window) {
127 dev_err(sdev->dev, "error: have no window info\n");
128 return;
129 }
130
131 for (i = 0; i < sdev->info_window->num_windows; i++) {
132 elem = &sdev->info_window->window[i];
133
134 switch (elem->type) {
135 case SOF_IPC_REGION_UPBOX:
136 inbox_offset = elem->offset + MBOX_OFFSET;
137 inbox_size = elem->size;
138 snd_sof_debugfs_io_item(sdev,
139 sdev->bar[BYT_DSP_BAR] +
140 inbox_offset,
141 elem->size, "inbox",
142 SOF_DEBUGFS_ACCESS_D0_ONLY);
143 break;
144 case SOF_IPC_REGION_DOWNBOX:
145 outbox_offset = elem->offset + MBOX_OFFSET;
146 outbox_size = elem->size;
147 snd_sof_debugfs_io_item(sdev,
148 sdev->bar[BYT_DSP_BAR] +
149 outbox_offset,
150 elem->size, "outbox",
151 SOF_DEBUGFS_ACCESS_D0_ONLY);
152 break;
153 case SOF_IPC_REGION_TRACE:
154 snd_sof_debugfs_io_item(sdev,
155 sdev->bar[BYT_DSP_BAR] +
156 elem->offset +
157 MBOX_OFFSET,
158 elem->size, "etrace",
159 SOF_DEBUGFS_ACCESS_D0_ONLY);
160 break;
161 case SOF_IPC_REGION_DEBUG:
162 snd_sof_debugfs_io_item(sdev,
163 sdev->bar[BYT_DSP_BAR] +
164 elem->offset +
165 MBOX_OFFSET,
166 elem->size, "debug",
167 SOF_DEBUGFS_ACCESS_D0_ONLY);
168 break;
169 case SOF_IPC_REGION_STREAM:
170 stream_offset = elem->offset + MBOX_OFFSET;
171 stream_size = elem->size;
172 snd_sof_debugfs_io_item(sdev,
173 sdev->bar[BYT_DSP_BAR] +
174 stream_offset,
175 elem->size, "stream",
176 SOF_DEBUGFS_ACCESS_D0_ONLY);
177 break;
178 case SOF_IPC_REGION_REGS:
179 snd_sof_debugfs_io_item(sdev,
180 sdev->bar[BYT_DSP_BAR] +
181 elem->offset +
182 MBOX_OFFSET,
183 elem->size, "regs",
184 SOF_DEBUGFS_ACCESS_D0_ONLY);
185 break;
186 case SOF_IPC_REGION_EXCEPTION:
187 sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET;
188 snd_sof_debugfs_io_item(sdev,
189 sdev->bar[BYT_DSP_BAR] +
190 elem->offset +
191 MBOX_OFFSET,
192 elem->size, "exception",
193 SOF_DEBUGFS_ACCESS_D0_ONLY);
194 break;
195 default:
196 dev_err(sdev->dev, "error: get illegal window info\n");
197 return;
198 }
199 }
200
201 if (outbox_size == 0 || inbox_size == 0) {
202 dev_err(sdev->dev, "error: get illegal mailbox window\n");
203 return;
204 }
205
206 snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
207 outbox_offset, outbox_size);
208 sdev->stream_box.offset = stream_offset;
209 sdev->stream_box.size = stream_size;
210
211 dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
212 inbox_offset, inbox_size);
213 dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
214 outbox_offset, outbox_size);
215 dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
216 stream_offset, stream_size);
217}
218
219/* check for ABI compatibility and create memory windows on first boot */
220static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
221{
222 struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
223 u32 offset;
224 int ret;
225
226 /* mailbox must be on 4k boundary */
227 offset = MBOX_OFFSET;
228
229 dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
230 msg_id, offset);
231
232 /* no need to re-check version/ABI for subsequent boots */
233 if (!sdev->first_boot)
234 return 0;
235
236 /* copy data from the DSP FW ready offset */
237 sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready,
238 sizeof(*fw_ready));
239
240 snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset,
241 fw_ready->dspbox_size,
242 fw_ready->hostbox_offset,
243 fw_ready->hostbox_size);
244
245 /* make sure ABI version is compatible */
246 ret = snd_sof_ipc_valid(sdev);
247 if (ret < 0)
248 return ret;
249
250 /* now check for extended data */
251 snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET +
252 sizeof(struct sof_ipc_fw_ready));
253
254 byt_get_windows(sdev);
255
256 return 0;
257}
258
259/*
260 * Debug
261 */
262
263static void byt_get_registers(struct snd_sof_dev *sdev,
264 struct sof_ipc_dsp_oops_xtensa *xoops,
265 struct sof_ipc_panic_info *panic_info,
266 u32 *stack, size_t stack_words)
267{
268 /* first read regsisters */
269 sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops));
270
271 /* then get panic info */
272 sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops),
273 panic_info, sizeof(*panic_info));
274
275 /* then get the stack */
276 sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) +
277 sizeof(*panic_info), stack,
278 stack_words * sizeof(u32));
279}
280
281static void byt_dump(struct snd_sof_dev *sdev, u32 flags)
282{
283 struct sof_ipc_dsp_oops_xtensa xoops;
284 struct sof_ipc_panic_info panic_info;
285 u32 stack[BYT_STACK_DUMP_SIZE];
286 u32 status, panic;
287
288 /* now try generic SOF status messages */
289 status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD);
290 panic = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCX);
291 byt_get_registers(sdev, &xoops, &panic_info, stack,
292 BYT_STACK_DUMP_SIZE);
293 snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack,
294 BYT_STACK_DUMP_SIZE);
295}
296
297/*
298 * IPC Doorbell IRQ handler and thread.
299 */
300
301static irqreturn_t byt_irq_handler(int irq, void *context)
302{
303 struct snd_sof_dev *sdev = context;
304 u64 isr;
305 int ret = IRQ_NONE;
306
307 /* Interrupt arrived, check src */
308 isr = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_ISRX);
309 if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY))
310 ret = IRQ_WAKE_THREAD;
311
312 return ret;
313}
314
315static irqreturn_t byt_irq_thread(int irq, void *context)
316{
317 struct snd_sof_dev *sdev = context;
318 u64 ipcx, ipcd;
319 u64 imrx;
320
321 imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX);
322 ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX);
323
324 /* reply message from DSP */
325 if (ipcx & SHIM_BYT_IPCX_DONE &&
326 !(imrx & SHIM_IMRX_DONE)) {
327 /* Mask Done interrupt before first */
328 snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR,
329 SHIM_IMRX,
330 SHIM_IMRX_DONE,
331 SHIM_IMRX_DONE);
332 /*
333 * handle immediate reply from DSP core. If the msg is
334 * found, set done bit in cmd_done which is called at the
335 * end of message processing function, else set it here
336 * because the done bit can't be set in cmd_done function
337 * which is triggered by msg
338 */
339 byt_get_reply(sdev);
340 snd_sof_ipc_reply(sdev, ipcx);
341
342 byt_dsp_done(sdev);
343 }
344
345 /* new message from DSP */
346 ipcd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD);
347 if (ipcd & SHIM_BYT_IPCD_BUSY &&
348 !(imrx & SHIM_IMRX_BUSY)) {
349 /* Mask Busy interrupt before return */
350 snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR,
351 SHIM_IMRX,
352 SHIM_IMRX_BUSY,
353 SHIM_IMRX_BUSY);
354
355 /* Handle messages from DSP Core */
356 if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
357 snd_sof_dsp_panic(sdev, BYT_PANIC_OFFSET(ipcd) +
358 MBOX_OFFSET);
359 } else {
360 snd_sof_ipc_msgs_rx(sdev);
361 }
362
363 byt_host_done(sdev);
364 }
365
366 return IRQ_HANDLED;
367}
368
369static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
370{
371 u64 cmd = msg->header;
372
373 /* send the message */
374 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
375 msg->msg_size);
376 snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX,
377 cmd | SHIM_BYT_IPCX_BUSY);
378
379 return 0;
380}
381
382static void byt_get_reply(struct snd_sof_dev *sdev)
383{
384 struct snd_sof_ipc_msg *msg = sdev->msg;
385 struct sof_ipc_reply reply;
386 unsigned long flags;
387 int ret = 0;
388
389 /*
390 * Sometimes, there is unexpected reply ipc arriving. The reply
391 * ipc belongs to none of the ipcs sent from driver.
392 * In this case, the driver must ignore the ipc.
393 */
394 if (!msg) {
395 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
396 return;
397 }
398
399 /* get reply */
400 sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
401
402 spin_lock_irqsave(&sdev->ipc_lock, flags);
403
404 if (reply.error < 0) {
405 memcpy(msg->reply_data, &reply, sizeof(reply));
406 ret = reply.error;
407 } else {
408 /* reply correct size ? */
409 if (reply.hdr.size != msg->reply_size) {
410 dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
411 msg->reply_size, reply.hdr.size);
412 ret = -EINVAL;
413 }
414
415 /* read the message */
416 if (msg->reply_size > 0)
417 sof_mailbox_read(sdev, sdev->host_box.offset,
418 msg->reply_data, msg->reply_size);
419 }
420
421 msg->reply_error = ret;
422
423 spin_unlock_irqrestore(&sdev->ipc_lock, flags);
424}
425
426static void byt_host_done(struct snd_sof_dev *sdev)
427{
428 /* clear BUSY bit and set DONE bit - accept new messages */
429 snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD,
430 SHIM_BYT_IPCD_BUSY |
431 SHIM_BYT_IPCD_DONE,
432 SHIM_BYT_IPCD_DONE);
433
434 /* unmask busy interrupt */
435 snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX,
436 SHIM_IMRX_BUSY, 0);
437}
438
439static void byt_dsp_done(struct snd_sof_dev *sdev)
440{
441 /* clear DONE bit - tell DSP we have completed */
442 snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX,
443 SHIM_BYT_IPCX_DONE, 0);
444
445 /* unmask Done interrupt */
446 snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX,
447 SHIM_IMRX_DONE, 0);
448}
449
450/*
451 * DSP control.
452 */
453
454static int byt_run(struct snd_sof_dev *sdev)
455{
456 int tries = 10;
457
458 /* release stall and wait to unstall */
459 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR,
460 SHIM_BYT_CSR_STALL, 0x0);
461 while (tries--) {
462 if (!(snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_CSR) &
463 SHIM_BYT_CSR_PWAITMODE))
464 break;
465 msleep(100);
466 }
467 if (tries < 0) {
468 dev_err(sdev->dev, "error: unable to run DSP firmware\n");
469 byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
470 return -ENODEV;
471 }
472
473 /* return init core mask */
474 return 1;
475}
476
477static int byt_reset(struct snd_sof_dev *sdev)
478{
479 /* put DSP into reset, set reset vector and stall */
480 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR,
481 SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL |
482 SHIM_BYT_CSR_STALL,
483 SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL |
484 SHIM_BYT_CSR_STALL);
485
486 usleep_range(10, 15);
487
488 /* take DSP out of reset and keep stalled for FW loading */
489 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR,
490 SHIM_BYT_CSR_RST, 0);
491
492 return 0;
493}
494
495/* Baytrail DAIs */
496static struct snd_soc_dai_driver byt_dai[] = {
497{
498 .name = "ssp0-port",
499},
500{
501 .name = "ssp1-port",
502},
503{
504 .name = "ssp2-port",
505},
506{
507 .name = "ssp3-port",
508},
509{
510 .name = "ssp4-port",
511},
512{
513 .name = "ssp5-port",
514},
515};
516
517/*
518 * Probe and remove.
519 */
520
521#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
522
523static int tangier_pci_probe(struct snd_sof_dev *sdev)
524{
525 struct snd_sof_pdata *pdata = sdev->pdata;
526 const struct sof_dev_desc *desc = pdata->desc;
527 struct pci_dev *pci = to_pci_dev(sdev->dev);
528 u32 base, size;
529 int ret;
530
531 /* DSP DMA can only access low 31 bits of host memory */
532 ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31));
533 if (ret < 0) {
534 dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret);
535 return ret;
536 }
537
538 /* LPE base */
539 base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET;
540 size = BYT_PCI_BAR_SIZE;
541
542 dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size);
543 sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size);
544 if (!sdev->bar[BYT_DSP_BAR]) {
545 dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n",
546 base, size);
547 return -ENODEV;
548 }
549 dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]);
550
551 /* IMR base - optional */
552 if (desc->resindex_imr_base == -1)
553 goto irq;
554
555 base = pci_resource_start(pci, desc->resindex_imr_base);
556 size = pci_resource_len(pci, desc->resindex_imr_base);
557
558 /* some BIOSes don't map IMR */
559 if (base == 0x55aa55aa || base == 0x0) {
560 dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n");
561 goto irq;
562 }
563
564 dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size);
565 sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size);
566 if (!sdev->bar[BYT_IMR_BAR]) {
567 dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n",
568 base, size);
569 return -ENODEV;
570 }
571 dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]);
572
573irq:
574 /* register our IRQ */
575 sdev->ipc_irq = pci->irq;
576 dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
577 ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
578 byt_irq_handler, byt_irq_thread,
579 0, "AudioDSP", sdev);
580 if (ret < 0) {
581 dev_err(sdev->dev, "error: failed to register IRQ %d\n",
582 sdev->ipc_irq);
583 return ret;
584 }
585
586 /* enable Interrupt from both sides */
587 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0);
588 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0);
589
590 /* set default mailbox offset for FW ready message */
591 sdev->dsp_box.offset = MBOX_OFFSET;
592
593 return ret;
594}
595
596const struct snd_sof_dsp_ops sof_tng_ops = {
597 /* device init */
598 .probe = tangier_pci_probe,
599
600 /* DSP core boot / reset */
601 .run = byt_run,
602 .reset = byt_reset,
603
604 /* Register IO */
605 .write = sof_io_write,
606 .read = sof_io_read,
607 .write64 = sof_io_write64,
608 .read64 = sof_io_read64,
609
610 /* Block IO */
611 .block_read = sof_block_read,
612 .block_write = sof_block_write,
613
614 /* doorbell */
615 .irq_handler = byt_irq_handler,
616 .irq_thread = byt_irq_thread,
617
618 /* ipc */
619 .send_msg = byt_send_msg,
620 .fw_ready = byt_fw_ready,
621
622 .ipc_msg_data = intel_ipc_msg_data,
623 .ipc_pcm_params = intel_ipc_pcm_params,
624
625 /* debug */
626 .debug_map = byt_debugfs,
627 .debug_map_count = ARRAY_SIZE(byt_debugfs),
628 .dbg_dump = byt_dump,
629
630 /* stream callbacks */
631 .pcm_open = intel_pcm_open,
632 .pcm_close = intel_pcm_close,
633
634 /* module loading */
635 .load_module = snd_sof_parse_module_memcpy,
636
637 /*Firmware loading */
638 .load_firmware = snd_sof_load_firmware_memcpy,
639
640 /* DAI drivers */
641 .drv = byt_dai,
642 .num_drv = 3, /* we have only 3 SSPs on byt*/
643};
644EXPORT_SYMBOL(sof_tng_ops);
645
646const struct sof_intel_dsp_desc tng_chip_info = {
647 .cores_num = 1,
648 .cores_mask = 1,
649};
650EXPORT_SYMBOL(tng_chip_info);
651
652#endif /* CONFIG_SND_SOC_SOF_MERRIFIELD */
653
654#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
655
656static int byt_acpi_probe(struct snd_sof_dev *sdev)
657{
658 struct snd_sof_pdata *pdata = sdev->pdata;
659 const struct sof_dev_desc *desc = pdata->desc;
660 struct platform_device *pdev =
661 container_of(sdev->dev, struct platform_device, dev);
662 struct resource *mmio;
663 u32 base, size;
664 int ret;
665
666 /* DSP DMA can only access low 31 bits of host memory */
667 ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31));
668 if (ret < 0) {
669 dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret);
670 return ret;
671 }
672
673 /* LPE base */
674 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
675 desc->resindex_lpe_base);
676 if (mmio) {
677 base = mmio->start;
678 size = resource_size(mmio);
679 } else {
680 dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n",
681 desc->resindex_lpe_base);
682 return -EINVAL;
683 }
684
685 dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size);
686 sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size);
687 if (!sdev->bar[BYT_DSP_BAR]) {
688 dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n",
689 base, size);
690 return -ENODEV;
691 }
692 dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]);
693
694 /* TODO: add offsets */
695 sdev->mmio_bar = BYT_DSP_BAR;
696 sdev->mailbox_bar = BYT_DSP_BAR;
697
698 /* IMR base - optional */
699 if (desc->resindex_imr_base == -1)
700 goto irq;
701
702 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
703 desc->resindex_imr_base);
704 if (mmio) {
705 base = mmio->start;
706 size = resource_size(mmio);
707 } else {
708 dev_err(sdev->dev, "error: failed to get IMR base at idx %d\n",
709 desc->resindex_imr_base);
710 return -ENODEV;
711 }
712
713 /* some BIOSes don't map IMR */
714 if (base == 0x55aa55aa || base == 0x0) {
715 dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n");
716 goto irq;
717 }
718
719 dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size);
720 sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size);
721 if (!sdev->bar[BYT_IMR_BAR]) {
722 dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n",
723 base, size);
724 return -ENODEV;
725 }
726 dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]);
727
728irq:
729 /* register our IRQ */
730 sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
731 if (sdev->ipc_irq < 0) {
732 dev_err(sdev->dev, "error: failed to get IRQ at index %d\n",
733 desc->irqindex_host_ipc);
734 return sdev->ipc_irq;
735 }
736
737 dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
738 ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
739 byt_irq_handler, byt_irq_thread,
740 IRQF_SHARED, "AudioDSP", sdev);
741 if (ret < 0) {
742 dev_err(sdev->dev, "error: failed to register IRQ %d\n",
743 sdev->ipc_irq);
744 return ret;
745 }
746
747 /* enable Interrupt from both sides */
748 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0);
749 snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0);
750
751 /* set default mailbox offset for FW ready message */
752 sdev->dsp_box.offset = MBOX_OFFSET;
753
754 return ret;
755}
756
757/* baytrail ops */
758const struct snd_sof_dsp_ops sof_byt_ops = {
759 /* device init */
760 .probe = byt_acpi_probe,
761
762 /* DSP core boot / reset */
763 .run = byt_run,
764 .reset = byt_reset,
765
766 /* Register IO */
767 .write = sof_io_write,
768 .read = sof_io_read,
769 .write64 = sof_io_write64,
770 .read64 = sof_io_read64,
771
772 /* Block IO */
773 .block_read = sof_block_read,
774 .block_write = sof_block_write,
775
776 /* doorbell */
777 .irq_handler = byt_irq_handler,
778 .irq_thread = byt_irq_thread,
779
780 /* ipc */
781 .send_msg = byt_send_msg,
782 .fw_ready = byt_fw_ready,
783
784 .ipc_msg_data = intel_ipc_msg_data,
785 .ipc_pcm_params = intel_ipc_pcm_params,
786
787 /* debug */
788 .debug_map = byt_debugfs,
789 .debug_map_count = ARRAY_SIZE(byt_debugfs),
790 .dbg_dump = byt_dump,
791
792 /* stream callbacks */
793 .pcm_open = intel_pcm_open,
794 .pcm_close = intel_pcm_close,
795
796 /* module loading */
797 .load_module = snd_sof_parse_module_memcpy,
798
799 /*Firmware loading */
800 .load_firmware = snd_sof_load_firmware_memcpy,
801
802 /* DAI drivers */
803 .drv = byt_dai,
804 .num_drv = 3, /* we have only 3 SSPs on byt*/
805};
806EXPORT_SYMBOL(sof_byt_ops);
807
808const struct sof_intel_dsp_desc byt_chip_info = {
809 .cores_num = 1,
810 .cores_mask = 1,
811};
812EXPORT_SYMBOL(byt_chip_info);
813
814/* cherrytrail and braswell ops */
815const struct snd_sof_dsp_ops sof_cht_ops = {
816 /* device init */
817 .probe = byt_acpi_probe,
818
819 /* DSP core boot / reset */
820 .run = byt_run,
821 .reset = byt_reset,
822
823 /* Register IO */
824 .write = sof_io_write,
825 .read = sof_io_read,
826 .write64 = sof_io_write64,
827 .read64 = sof_io_read64,
828
829 /* Block IO */
830 .block_read = sof_block_read,
831 .block_write = sof_block_write,
832
833 /* doorbell */
834 .irq_handler = byt_irq_handler,
835 .irq_thread = byt_irq_thread,
836
837 /* ipc */
838 .send_msg = byt_send_msg,
839 .fw_ready = byt_fw_ready,
840
841 .ipc_msg_data = intel_ipc_msg_data,
842 .ipc_pcm_params = intel_ipc_pcm_params,
843
844 /* debug */
845 .debug_map = cht_debugfs,
846 .debug_map_count = ARRAY_SIZE(cht_debugfs),
847 .dbg_dump = byt_dump,
848
849 /* stream callbacks */
850 .pcm_open = intel_pcm_open,
851 .pcm_close = intel_pcm_close,
852
853 /* module loading */
854 .load_module = snd_sof_parse_module_memcpy,
855
856 /*Firmware loading */
857 .load_firmware = snd_sof_load_firmware_memcpy,
858
859 /* DAI drivers */
860 .drv = byt_dai,
861 /* all 6 SSPs may be available for cherrytrail */
862 .num_drv = ARRAY_SIZE(byt_dai),
863};
864EXPORT_SYMBOL(sof_cht_ops);
865
866const struct sof_intel_dsp_desc cht_chip_info = {
867 .cores_num = 1,
868 .cores_mask = 1,
869};
870EXPORT_SYMBOL(cht_chip_info);
871
872#endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */
873
874MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
new file mode 100644
index 000000000000..08a1a3d3c08d
--- /dev/null
+++ b/sound/soc/sof/intel/cnl.c
@@ -0,0 +1,268 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for audio DSP on Cannonlake.
16 */
17
18#include "../ops.h"
19#include "hda.h"
20
21static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = {
22 {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
23 {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
24 {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
25};
26
27static void cnl_ipc_host_done(struct snd_sof_dev *sdev);
28static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev);
29
30static irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
31{
32 struct snd_sof_dev *sdev = context;
33 u32 hipci;
34 u32 hipcctl;
35 u32 hipcida;
36 u32 hipctdr;
37 u32 hipctdd;
38 u32 msg;
39 u32 msg_ext;
40 irqreturn_t ret = IRQ_NONE;
41
42 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
43 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL);
44 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
45
46 /* reenable IPC interrupt */
47 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
48 HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
49
50 /* reply message from DSP */
51 if (hipcida & CNL_DSP_REG_HIPCIDA_DONE &&
52 hipcctl & CNL_DSP_REG_HIPCCTL_DONE) {
53 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
54 CNL_DSP_REG_HIPCIDR);
55 msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK;
56 msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK;
57
58 dev_vdbg(sdev->dev,
59 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
60 msg, msg_ext);
61
62 /* mask Done interrupt */
63 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
64 CNL_DSP_REG_HIPCCTL,
65 CNL_DSP_REG_HIPCCTL_DONE, 0);
66
67 /* handle immediate reply from DSP core */
68 hda_dsp_ipc_get_reply(sdev);
69 snd_sof_ipc_reply(sdev, msg);
70
71 if (sdev->code_loading) {
72 sdev->code_loading = 0;
73 wake_up(&sdev->waitq);
74 }
75
76 cnl_ipc_dsp_done(sdev);
77
78 ret = IRQ_HANDLED;
79 }
80
81 /* new message from DSP */
82 if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
83 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
84 CNL_DSP_REG_HIPCTDD);
85 msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK;
86 msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK;
87
88 dev_vdbg(sdev->dev,
89 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
90 msg, msg_ext);
91
92 /* handle messages from DSP */
93 if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) ==
94 SOF_IPC_PANIC_MAGIC) {
95 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext));
96 } else {
97 snd_sof_ipc_msgs_rx(sdev);
98 }
99
100 /*
101 * clear busy interrupt to tell dsp controller this
102 * interrupt has been accepted, not trigger it again
103 */
104 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
105 CNL_DSP_REG_HIPCTDR,
106 CNL_DSP_REG_HIPCTDR_BUSY,
107 CNL_DSP_REG_HIPCTDR_BUSY);
108
109 cnl_ipc_host_done(sdev);
110
111 ret = IRQ_HANDLED;
112 }
113
114 return ret;
115}
116
117static void cnl_ipc_host_done(struct snd_sof_dev *sdev)
118{
119 /*
120 * set done bit to ack dsp the msg has been
121 * processed and send reply msg to dsp
122 */
123 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
124 CNL_DSP_REG_HIPCTDA,
125 CNL_DSP_REG_HIPCTDA_DONE,
126 CNL_DSP_REG_HIPCTDA_DONE);
127}
128
129static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev)
130{
131 /*
132 * set DONE bit - tell DSP we have received the reply msg
133 * from DSP, and processed it, don't send more reply to host
134 */
135 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
136 CNL_DSP_REG_HIPCIDA,
137 CNL_DSP_REG_HIPCIDA_DONE,
138 CNL_DSP_REG_HIPCIDA_DONE);
139
140 /* unmask Done interrupt */
141 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
142 CNL_DSP_REG_HIPCCTL,
143 CNL_DSP_REG_HIPCCTL_DONE,
144 CNL_DSP_REG_HIPCCTL_DONE);
145}
146
147static int cnl_ipc_send_msg(struct snd_sof_dev *sdev,
148 struct snd_sof_ipc_msg *msg)
149{
150 u32 cmd = msg->header;
151
152 /* send the message */
153 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
154 msg->msg_size);
155 snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR,
156 cmd | CNL_DSP_REG_HIPCIDR_BUSY);
157
158 return 0;
159}
160
161static void cnl_ipc_dump(struct snd_sof_dev *sdev)
162{
163 u32 hipcctl;
164 u32 hipcida;
165 u32 hipctdr;
166
167 /* read IPC status */
168 hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
169 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL);
170 hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
171
172 /* dump the IPC regs */
173 /* TODO: parse the raw msg */
174 dev_err(sdev->dev,
175 "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
176 hipcida, hipctdr, hipcctl);
177}
178
179/* cannonlake ops */
180const struct snd_sof_dsp_ops sof_cnl_ops = {
181 /* probe and remove */
182 .probe = hda_dsp_probe,
183 .remove = hda_dsp_remove,
184
185 /* Register IO */
186 .write = sof_io_write,
187 .read = sof_io_read,
188 .write64 = sof_io_write64,
189 .read64 = sof_io_read64,
190
191 /* Block IO */
192 .block_read = sof_block_read,
193 .block_write = sof_block_write,
194
195 /* doorbell */
196 .irq_handler = hda_dsp_ipc_irq_handler,
197 .irq_thread = cnl_ipc_irq_thread,
198
199 /* ipc */
200 .send_msg = cnl_ipc_send_msg,
201 .fw_ready = hda_dsp_ipc_fw_ready,
202
203 .ipc_msg_data = hda_ipc_msg_data,
204 .ipc_pcm_params = hda_ipc_pcm_params,
205
206 /* debug */
207 .debug_map = cnl_dsp_debugfs,
208 .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs),
209 .dbg_dump = hda_dsp_dump,
210 .ipc_dump = cnl_ipc_dump,
211
212 /* stream callbacks */
213 .pcm_open = hda_dsp_pcm_open,
214 .pcm_close = hda_dsp_pcm_close,
215 .pcm_hw_params = hda_dsp_pcm_hw_params,
216 .pcm_trigger = hda_dsp_pcm_trigger,
217 .pcm_pointer = hda_dsp_pcm_pointer,
218
219 /* firmware loading */
220 .load_firmware = snd_sof_load_firmware_raw,
221
222 /* pre/post fw run */
223 .pre_fw_run = hda_dsp_pre_fw_run,
224 .post_fw_run = hda_dsp_post_fw_run,
225
226 /* dsp core power up/down */
227 .core_power_up = hda_dsp_enable_core,
228 .core_power_down = hda_dsp_core_reset_power_down,
229
230 /* firmware run */
231 .run = hda_dsp_cl_boot_firmware,
232
233 /* trace callback */
234 .trace_init = hda_dsp_trace_init,
235 .trace_release = hda_dsp_trace_release,
236 .trace_trigger = hda_dsp_trace_trigger,
237
238 /* DAI drivers */
239 .drv = skl_dai,
240 .num_drv = SOF_SKL_NUM_DAIS,
241
242 /* PM */
243 .suspend = hda_dsp_suspend,
244 .resume = hda_dsp_resume,
245 .runtime_suspend = hda_dsp_runtime_suspend,
246 .runtime_resume = hda_dsp_runtime_resume,
247 .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
248};
249EXPORT_SYMBOL(sof_cnl_ops);
250
251const struct sof_intel_dsp_desc cnl_chip_info = {
252 /* Cannonlake */
253 .cores_num = 4,
254 .init_core_mask = 1,
255 .cores_mask = HDA_DSP_CORE_MASK(0) |
256 HDA_DSP_CORE_MASK(1) |
257 HDA_DSP_CORE_MASK(2) |
258 HDA_DSP_CORE_MASK(3),
259 .ipc_req = CNL_DSP_REG_HIPCIDR,
260 .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
261 .ipc_ack = CNL_DSP_REG_HIPCIDA,
262 .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
263 .ipc_ctl = CNL_DSP_REG_HIPCCTL,
264 .rom_init_timeout = 300,
265 .ssp_count = CNL_SSP_COUNT,
266 .ssp_base_offset = CNL_SSP_BASE_OFFSET,
267};
268EXPORT_SYMBOL(cnl_chip_info);
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
new file mode 100644
index 000000000000..a7e6d8227df6
--- /dev/null
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -0,0 +1,111 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Keyon Jie <yang.jie@linux.intel.com>
9
10#include <linux/io.h>
11#include <sound/hdaudio.h>
12#include "../sof-priv.h"
13#include "hda.h"
14
15#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
16
17static const struct hdac_bus_ops bus_ops = {
18 .command = snd_hdac_bus_send_cmd,
19 .get_response = snd_hdac_bus_get_response,
20};
21
22#endif
23
24static void sof_hda_writel(u32 value, u32 __iomem *addr)
25{
26 writel(value, addr);
27}
28
29static u32 sof_hda_readl(u32 __iomem *addr)
30{
31 return readl(addr);
32}
33
34static void sof_hda_writew(u16 value, u16 __iomem *addr)
35{
36 writew(value, addr);
37}
38
39static u16 sof_hda_readw(u16 __iomem *addr)
40{
41 return readw(addr);
42}
43
44static void sof_hda_writeb(u8 value, u8 __iomem *addr)
45{
46 writeb(value, addr);
47}
48
49static u8 sof_hda_readb(u8 __iomem *addr)
50{
51 return readb(addr);
52}
53
54static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type,
55 size_t size, struct snd_dma_buffer *buf)
56{
57 return snd_dma_alloc_pages(type, bus->dev, size, buf);
58}
59
60static void sof_hda_dma_free_pages(struct hdac_bus *bus,
61 struct snd_dma_buffer *buf)
62{
63 snd_dma_free_pages(buf);
64}
65
66static const struct hdac_io_ops io_ops = {
67 .reg_writel = sof_hda_writel,
68 .reg_readl = sof_hda_readl,
69 .reg_writew = sof_hda_writew,
70 .reg_readw = sof_hda_readw,
71 .reg_writeb = sof_hda_writeb,
72 .reg_readb = sof_hda_readb,
73 .dma_alloc_pages = sof_hda_dma_alloc_pages,
74 .dma_free_pages = sof_hda_dma_free_pages,
75};
76
77/*
78 * This can be used for both with/without hda link support.
79 */
80void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev,
81 const struct hdac_ext_bus_ops *ext_ops)
82{
83 memset(bus, 0, sizeof(*bus));
84 bus->dev = dev;
85
86 bus->io_ops = &io_ops;
87 INIT_LIST_HEAD(&bus->stream_list);
88
89 bus->irq = -1;
90 bus->ext_ops = ext_ops;
91
92 /*
93 * There is only one HDA bus atm. keep the index as 0.
94 * Need to fix when there are more than one HDA bus.
95 */
96 bus->idx = 0;
97
98 spin_lock_init(&bus->reg_lock);
99
100#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
101 INIT_LIST_HEAD(&bus->codec_list);
102 INIT_LIST_HEAD(&bus->hlink_list);
103
104 mutex_init(&bus->cmd_mutex);
105 mutex_init(&bus->lock);
106 bus->ops = &bus_ops;
107 INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events);
108 bus->cmd_dma_state = true;
109#endif
110
111}
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
new file mode 100644
index 000000000000..b8b37f082309
--- /dev/null
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -0,0 +1,171 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Keyon Jie <yang.jie@linux.intel.com>
9//
10
11#include <linux/module.h>
12#include <sound/hdaudio_ext.h>
13#include <sound/hda_codec.h>
14#include <sound/hda_i915.h>
15#include <sound/sof.h>
16#include "../ops.h"
17#include "hda.h"
18#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
19#include "../../codecs/hdac_hda.h"
20#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
21
22#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
23#define IDISP_VID_INTEL 0x80860000
24
25/* load the legacy HDA codec driver */
26#ifdef MODULE
27static void hda_codec_load_module(struct hda_codec *codec)
28{
29 char alias[MODULE_NAME_LEN];
30 const char *module = alias;
31
32 snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias));
33 dev_dbg(&codec->core.dev, "loading codec module: %s\n", module);
34 request_module(module);
35}
36#else
37static void hda_codec_load_module(struct hda_codec *codec) {}
38#endif
39
40#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
41
42/* probe individual codec */
43static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
44{
45 struct hda_bus *hbus = sof_to_hbus(sdev);
46 struct hdac_device *hdev;
47#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
48 struct hdac_hda_priv *hda_priv;
49#endif
50 u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
51 (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
52 u32 resp = -1;
53 int ret;
54
55 mutex_lock(&hbus->core.cmd_mutex);
56 snd_hdac_bus_send_cmd(&hbus->core, hda_cmd);
57 snd_hdac_bus_get_response(&hbus->core, address, &resp);
58 mutex_unlock(&hbus->core.cmd_mutex);
59 if (resp == -1)
60 return -EIO;
61 dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
62 address, resp);
63
64#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
65 /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */
66 hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL);
67 if (!hda_priv)
68 return -ENOMEM;
69
70 hda_priv->codec.bus = hbus;
71 hdev = &hda_priv->codec.core;
72
73 ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev);
74 if (ret < 0)
75 return ret;
76
77 /* use legacy bus only for HDA codecs, idisp uses ext bus */
78 if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) {
79 hdev->type = HDA_DEV_LEGACY;
80 hda_codec_load_module(&hda_priv->codec);
81 }
82
83 return 0;
84#else
85 /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */
86 hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
87 if (!hdev)
88 return -ENOMEM;
89
90 ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev);
91
92 return ret;
93#endif
94}
95
96/* Codec initialization */
97int hda_codec_probe_bus(struct snd_sof_dev *sdev)
98{
99 struct hdac_bus *bus = sof_to_bus(sdev);
100 int i, ret;
101
102 /* probe codecs in avail slots */
103 for (i = 0; i < HDA_MAX_CODECS; i++) {
104
105 if (!(bus->codec_mask & (1 << i)))
106 continue;
107
108 ret = hda_codec_probe(sdev, i);
109 if (ret < 0) {
110 dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n",
111 i, ret);
112 return ret;
113 }
114 }
115
116 return 0;
117}
118EXPORT_SYMBOL(hda_codec_probe_bus);
119
120#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)
121
122void hda_codec_i915_get(struct snd_sof_dev *sdev)
123{
124 struct hdac_bus *bus = sof_to_bus(sdev);
125
126 dev_dbg(bus->dev, "Turning i915 HDAC power on\n");
127 snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
128}
129EXPORT_SYMBOL(hda_codec_i915_get);
130
131void hda_codec_i915_put(struct snd_sof_dev *sdev)
132{
133 struct hdac_bus *bus = sof_to_bus(sdev);
134
135 dev_dbg(bus->dev, "Turning i915 HDAC power off\n");
136 snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
137}
138EXPORT_SYMBOL(hda_codec_i915_put);
139
140int hda_codec_i915_init(struct snd_sof_dev *sdev)
141{
142 struct hdac_bus *bus = sof_to_bus(sdev);
143 int ret;
144
145 /* i915 exposes a HDA codec for HDMI audio */
146 ret = snd_hdac_i915_init(bus);
147 if (ret < 0)
148 return ret;
149
150 hda_codec_i915_get(sdev);
151
152 return 0;
153}
154EXPORT_SYMBOL(hda_codec_i915_init);
155
156int hda_codec_i915_exit(struct snd_sof_dev *sdev)
157{
158 struct hdac_bus *bus = sof_to_bus(sdev);
159 int ret;
160
161 hda_codec_i915_put(sdev);
162
163 ret = snd_hdac_i915_exit(bus);
164
165 return ret;
166}
167EXPORT_SYMBOL(hda_codec_i915_exit);
168
169#endif /* CONFIG_SND_SOC_HDAC_HDMI */
170
171MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
new file mode 100644
index 000000000000..2c3645736e1f
--- /dev/null
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -0,0 +1,181 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include <sound/hdaudio_ext.h>
19#include <sound/hda_register.h>
20#include "../ops.h"
21#include "hda.h"
22
23/*
24 * HDA Operations.
25 */
26
27int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset)
28{
29 unsigned long timeout;
30 u32 gctl = 0;
31 u32 val;
32
33 /* 0 to enter reset and 1 to exit reset */
34 val = reset ? 0 : SOF_HDA_GCTL_RESET;
35
36 /* enter/exit HDA controller reset */
37 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL,
38 SOF_HDA_GCTL_RESET, val);
39
40 /* wait to enter/exit reset */
41 timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT);
42 while (time_before(jiffies, timeout)) {
43 gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
44 if ((gctl & SOF_HDA_GCTL_RESET) == val)
45 return 0;
46 usleep_range(500, 1000);
47 }
48
49 /* enter/exit reset failed */
50 dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n",
51 reset ? "reset" : "ready", gctl);
52 return -EIO;
53}
54
55int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev)
56{
57 struct hdac_bus *bus = sof_to_bus(sdev);
58 u32 cap, offset, feature;
59 int count = 0;
60
61 offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH);
62
63 do {
64 cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset);
65
66 dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n",
67 offset & SOF_HDA_CAP_NEXT_MASK);
68
69 feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF;
70
71 switch (feature) {
72 case SOF_HDA_PP_CAP_ID:
73 dev_dbg(sdev->dev, "found DSP capability at 0x%x\n",
74 offset);
75 bus->ppcap = bus->remap_addr + offset;
76 sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap;
77 break;
78 case SOF_HDA_SPIB_CAP_ID:
79 dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n",
80 offset);
81 bus->spbcap = bus->remap_addr + offset;
82 sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap;
83 break;
84 case SOF_HDA_DRSM_CAP_ID:
85 dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n",
86 offset);
87 bus->drsmcap = bus->remap_addr + offset;
88 sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap;
89 break;
90 case SOF_HDA_GTS_CAP_ID:
91 dev_dbg(sdev->dev, "found GTS capability at 0x%x\n",
92 offset);
93 bus->gtscap = bus->remap_addr + offset;
94 break;
95 case SOF_HDA_ML_CAP_ID:
96 dev_dbg(sdev->dev, "found ML capability at 0x%x\n",
97 offset);
98 bus->mlcap = bus->remap_addr + offset;
99 break;
100 default:
101 dev_vdbg(sdev->dev, "found capability %d at 0x%x\n",
102 feature, offset);
103 break;
104 }
105
106 offset = cap & SOF_HDA_CAP_NEXT_MASK;
107 } while (count++ <= SOF_HDA_MAX_CAPS && offset);
108
109 return 0;
110}
111
112void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
113{
114 u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0;
115
116 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
117 SOF_HDA_PPCTL_GPROCEN, val);
118}
119
120void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
121{
122 u32 val = enable ? SOF_HDA_PPCTL_PIE : 0;
123
124 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
125 SOF_HDA_PPCTL_PIE, val);
126}
127
128void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
129{
130 u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0;
131
132 snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val);
133}
134
135/*
136 * enable/disable audio dsp clock gating and power gating bits.
137 * This allows the HW to opportunistically power and clock gate
138 * the audio dsp when it is idle
139 */
140int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
141{
142#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
143 struct hdac_bus *bus = sof_to_bus(sdev);
144#endif
145 u32 val;
146
147 /* enable/disable audio dsp clock gating */
148 val = enable ? PCI_CGCTL_ADSPDCGE : 0;
149 snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);
150
151#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
152 /* enable/disable L1 support */
153 val = enable ? SOF_HDA_VS_EM2_L1SEN : 0;
154 snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val);
155#endif
156
157 /* enable/disable audio dsp power gating */
158 val = enable ? 0 : PCI_PGCTL_ADSPPGD;
159 snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val);
160
161 return 0;
162}
163
164#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
165/*
166 * While performing reset, controller may not come back properly and causing
167 * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
168 * (init chip) and then again set CGCTL.MISCBDCGE to 1
169 */
170int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
171{
172 struct hdac_bus *bus = sof_to_bus(sdev);
173 int ret;
174
175 hda_dsp_ctrl_misc_clock_gating(sdev, false);
176 ret = snd_hdac_bus_init_chip(bus, full_reset);
177 hda_dsp_ctrl_misc_clock_gating(sdev, true);
178
179 return ret;
180}
181#endif
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
new file mode 100644
index 000000000000..e1decf25aeac
--- /dev/null
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -0,0 +1,356 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Keyon Jie <yang.jie@linux.intel.com>
9//
10
11#include <sound/pcm_params.h>
12#include <sound/hdaudio_ext.h>
13#include "../sof-priv.h"
14#include "hda.h"
15
16#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
17
18struct hda_pipe_params {
19 u8 host_dma_id;
20 u8 link_dma_id;
21 u32 ch;
22 u32 s_freq;
23 u32 s_fmt;
24 u8 linktype;
25 snd_pcm_format_t format;
26 int link_index;
27 int stream;
28 unsigned int host_bps;
29 unsigned int link_bps;
30};
31
32/*
33 * Unlike GP dma, there is a set of stream registers in hda controller
34 * to control the link dma channels. Each register controls one link
35 * dma channel and the relation is fixed. To make sure FW uses correct
36 * link dma channels, host allocates stream registers and sends the
37 * corresponding link dma channels to FW to allocate link dma channel
38 *
39 * FIXME: this API is abused in the sense that tx_num and rx_num are
40 * passed as arguments, not returned. We need to find a better way to
41 * retrieve the stream tag allocated for the link DMA
42 */
43static int hda_link_dma_get_channels(struct snd_soc_dai *dai,
44 unsigned int *tx_num,
45 unsigned int *tx_slot,
46 unsigned int *rx_num,
47 unsigned int *rx_slot)
48{
49 struct hdac_bus *bus;
50 struct hdac_ext_stream *stream;
51 struct snd_pcm_substream substream;
52 struct snd_sof_dev *sdev =
53 snd_soc_component_get_drvdata(dai->component);
54
55 bus = sof_to_bus(sdev);
56
57 memset(&substream, 0, sizeof(substream));
58 if (*tx_num == 1) {
59 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
60 stream = snd_hdac_ext_stream_assign(bus, &substream,
61 HDAC_EXT_STREAM_TYPE_LINK);
62 if (!stream) {
63 dev_err(bus->dev, "error: failed to find a free hda ext stream for playback");
64 return -EBUSY;
65 }
66
67 snd_soc_dai_set_dma_data(dai, &substream, stream);
68 *tx_slot = hdac_stream(stream)->stream_tag - 1;
69
70 dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot);
71 }
72
73 if (*rx_num == 1) {
74 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
75 stream = snd_hdac_ext_stream_assign(bus, &substream,
76 HDAC_EXT_STREAM_TYPE_LINK);
77 if (!stream) {
78 dev_err(bus->dev, "error: failed to find a free hda ext stream for capture");
79 return -EBUSY;
80 }
81
82 snd_soc_dai_set_dma_data(dai, &substream, stream);
83 *rx_slot = hdac_stream(stream)->stream_tag - 1;
84
85 dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot);
86 }
87
88 return 0;
89}
90
91static int hda_link_dma_params(struct hdac_ext_stream *stream,
92 struct hda_pipe_params *params)
93{
94 struct hdac_stream *hstream = &stream->hstream;
95 unsigned char stream_tag = hstream->stream_tag;
96 struct hdac_bus *bus = hstream->bus;
97 struct hdac_ext_link *link;
98 unsigned int format_val;
99
100 snd_hdac_ext_stream_decouple(bus, stream, true);
101 snd_hdac_ext_link_stream_reset(stream);
102
103 format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
104 params->format,
105 params->link_bps, 0);
106
107 dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
108 format_val, params->s_freq, params->ch, params->format);
109
110 snd_hdac_ext_link_stream_setup(stream, format_val);
111
112 if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
113 list_for_each_entry(link, &bus->hlink_list, list) {
114 if (link->index == params->link_index)
115 snd_hdac_ext_link_set_stream_id(link,
116 stream_tag);
117 }
118 }
119
120 stream->link_prepared = 1;
121
122 return 0;
123}
124
125static int hda_link_hw_params(struct snd_pcm_substream *substream,
126 struct snd_pcm_hw_params *params,
127 struct snd_soc_dai *dai)
128{
129 struct hdac_stream *hstream = substream->runtime->private_data;
130 struct hdac_bus *bus = hstream->bus;
131 struct hdac_ext_stream *link_dev;
132 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
133 struct snd_soc_dai *codec_dai = rtd->codec_dai;
134 struct sof_intel_hda_stream *hda_stream;
135 struct hda_pipe_params p_params = {0};
136 struct hdac_ext_link *link;
137 int stream_tag;
138
139 link_dev = snd_soc_dai_get_dma_data(dai, substream);
140
141 hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
142 hda_stream);
143 hda_stream->hw_params_upon_resume = 0;
144
145 link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
146 if (!link)
147 return -EINVAL;
148
149 stream_tag = hdac_stream(link_dev)->stream_tag;
150
151 /* set the stream tag in the codec dai dma params */
152 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
153 snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
154 else
155 snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0);
156
157 p_params.s_fmt = snd_pcm_format_width(params_format(params));
158 p_params.ch = params_channels(params);
159 p_params.s_freq = params_rate(params);
160 p_params.stream = substream->stream;
161 p_params.link_dma_id = stream_tag - 1;
162 p_params.link_index = link->index;
163 p_params.format = params_format(params);
164
165 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
166 p_params.link_bps = codec_dai->driver->playback.sig_bits;
167 else
168 p_params.link_bps = codec_dai->driver->capture.sig_bits;
169
170 return hda_link_dma_params(link_dev, &p_params);
171}
172
173static int hda_link_pcm_prepare(struct snd_pcm_substream *substream,
174 struct snd_soc_dai *dai)
175{
176 struct hdac_ext_stream *link_dev =
177 snd_soc_dai_get_dma_data(dai, substream);
178 struct sof_intel_hda_stream *hda_stream;
179 struct snd_sof_dev *sdev =
180 snd_soc_component_get_drvdata(dai->component);
181 struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
182 int stream = substream->stream;
183
184 hda_stream = container_of(link_dev, struct sof_intel_hda_stream,
185 hda_stream);
186
187 /* setup hw_params again only if resuming from system suspend */
188 if (!hda_stream->hw_params_upon_resume)
189 return 0;
190
191 dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
192
193 return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params,
194 dai);
195}
196
197static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
198 int cmd, struct snd_soc_dai *dai)
199{
200 struct hdac_ext_stream *link_dev =
201 snd_soc_dai_get_dma_data(dai, substream);
202 int ret;
203
204 dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
205 switch (cmd) {
206 case SNDRV_PCM_TRIGGER_RESUME:
207 /* set up hw_params */
208 ret = hda_link_pcm_prepare(substream, dai);
209 if (ret < 0) {
210 dev_err(dai->dev,
211 "error: setting up hw_params during resume\n");
212 return ret;
213 }
214
215 /* fallthrough */
216 case SNDRV_PCM_TRIGGER_START:
217 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
218 snd_hdac_ext_link_stream_start(link_dev);
219 break;
220 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
221 case SNDRV_PCM_TRIGGER_SUSPEND:
222 case SNDRV_PCM_TRIGGER_STOP:
223 snd_hdac_ext_link_stream_clear(link_dev);
224 break;
225 default:
226 return -EINVAL;
227 }
228 return 0;
229}
230
231/*
232 * FIXME: This API is also abused since it's used for two purposes.
233 * when the substream argument is NULL this function is used for cleanups
234 * that aren't necessarily required, and called explicitly by handling
235 * ASoC core structures, which is not recommended.
236 * This part will be reworked in follow-up patches.
237 */
238static int hda_link_hw_free(struct snd_pcm_substream *substream,
239 struct snd_soc_dai *dai)
240{
241 const char *name;
242 unsigned int stream_tag;
243 struct hdac_bus *bus;
244 struct hdac_ext_link *link;
245 struct hdac_stream *hstream;
246 struct hdac_ext_stream *stream;
247 struct snd_soc_pcm_runtime *rtd;
248 struct hdac_ext_stream *link_dev;
249 struct snd_pcm_substream pcm_substream;
250
251 memset(&pcm_substream, 0, sizeof(pcm_substream));
252 if (substream) {
253 hstream = substream->runtime->private_data;
254 bus = hstream->bus;
255 rtd = snd_pcm_substream_chip(substream);
256 link_dev = snd_soc_dai_get_dma_data(dai, substream);
257 snd_hdac_ext_stream_decouple(bus, link_dev, false);
258 name = rtd->codec_dai->component->name;
259 link = snd_hdac_ext_bus_get_link(bus, name);
260 if (!link)
261 return -EINVAL;
262
263 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
264 stream_tag = hdac_stream(link_dev)->stream_tag;
265 snd_hdac_ext_link_clear_stream_id(link, stream_tag);
266 }
267
268 link_dev->link_prepared = 0;
269 } else {
270 /* release all hda streams when dai link is unloaded */
271 pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
272 stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
273 if (stream) {
274 snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
275 snd_hdac_ext_stream_release(stream,
276 HDAC_EXT_STREAM_TYPE_LINK);
277 }
278
279 pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE;
280 stream = snd_soc_dai_get_dma_data(dai, &pcm_substream);
281 if (stream) {
282 snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL);
283 snd_hdac_ext_stream_release(stream,
284 HDAC_EXT_STREAM_TYPE_LINK);
285 }
286 }
287
288 return 0;
289}
290
291static const struct snd_soc_dai_ops hda_link_dai_ops = {
292 .hw_params = hda_link_hw_params,
293 .hw_free = hda_link_hw_free,
294 .trigger = hda_link_pcm_trigger,
295 .prepare = hda_link_pcm_prepare,
296 .get_channel_map = hda_link_dma_get_channels,
297};
298#endif
299
300/*
301 * common dai driver for skl+ platforms.
302 * some products who use this DAI array only physically have a subset of
303 * the DAIs, but no harm is done here by adding the whole set.
304 */
305struct snd_soc_dai_driver skl_dai[] = {
306{
307 .name = "SSP0 Pin",
308},
309{
310 .name = "SSP1 Pin",
311},
312{
313 .name = "SSP2 Pin",
314},
315{
316 .name = "SSP3 Pin",
317},
318{
319 .name = "SSP4 Pin",
320},
321{
322 .name = "SSP5 Pin",
323},
324{
325 .name = "DMIC01 Pin",
326},
327{
328 .name = "DMIC16k Pin",
329},
330#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
331{
332 .name = "iDisp1 Pin",
333 .ops = &hda_link_dai_ops,
334},
335{
336 .name = "iDisp2 Pin",
337 .ops = &hda_link_dai_ops,
338},
339{
340 .name = "iDisp3 Pin",
341 .ops = &hda_link_dai_ops,
342},
343{
344 .name = "Analog CPU DAI",
345 .ops = &hda_link_dai_ops,
346},
347{
348 .name = "Digital CPU DAI",
349 .ops = &hda_link_dai_ops,
350},
351{
352 .name = "Alt Analog CPU DAI",
353 .ops = &hda_link_dai_ops,
354},
355#endif
356};
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
new file mode 100644
index 000000000000..5b73115a0b78
--- /dev/null
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -0,0 +1,471 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include <sound/hdaudio_ext.h>
19#include <sound/hda_register.h>
20#include "../ops.h"
21#include "hda.h"
22
23/*
24 * DSP Core control.
25 */
26
27int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask)
28{
29 u32 adspcs;
30 u32 reset;
31 int ret;
32
33 /* set reset bits for cores */
34 reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
35 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
36 HDA_DSP_REG_ADSPCS,
37 reset, reset),
38
39 /* poll with timeout to check if operation successful */
40 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
41 HDA_DSP_REG_ADSPCS, adspcs,
42 ((adspcs & reset) == reset),
43 HDA_DSP_REG_POLL_INTERVAL_US,
44 HDA_DSP_RESET_TIMEOUT_US);
45
46 /* has core entered reset ? */
47 adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
48 HDA_DSP_REG_ADSPCS);
49 if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) !=
50 HDA_DSP_ADSPCS_CRST_MASK(core_mask)) {
51 dev_err(sdev->dev,
52 "error: reset enter failed: core_mask %x adspcs 0x%x\n",
53 core_mask, adspcs);
54 ret = -EIO;
55 }
56
57 return ret;
58}
59
60int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask)
61{
62 unsigned int crst;
63 u32 adspcs;
64 int ret;
65
66 /* clear reset bits for cores */
67 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
68 HDA_DSP_REG_ADSPCS,
69 HDA_DSP_ADSPCS_CRST_MASK(core_mask),
70 0);
71
72 /* poll with timeout to check if operation successful */
73 crst = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
74 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
75 HDA_DSP_REG_ADSPCS, adspcs,
76 !(adspcs & crst),
77 HDA_DSP_REG_POLL_INTERVAL_US,
78 HDA_DSP_RESET_TIMEOUT_US);
79
80 /* has core left reset ? */
81 adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
82 HDA_DSP_REG_ADSPCS);
83 if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != 0) {
84 dev_err(sdev->dev,
85 "error: reset leave failed: core_mask %x adspcs 0x%x\n",
86 core_mask, adspcs);
87 ret = -EIO;
88 }
89
90 return ret;
91}
92
93int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask)
94{
95 /* stall core */
96 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
97 HDA_DSP_REG_ADSPCS,
98 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask),
99 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask));
100
101 /* set reset state */
102 return hda_dsp_core_reset_enter(sdev, core_mask);
103}
104
105int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
106{
107 int ret;
108
109 /* leave reset state */
110 ret = hda_dsp_core_reset_leave(sdev, core_mask);
111 if (ret < 0)
112 return ret;
113
114 /* run core */
115 dev_dbg(sdev->dev, "unstall/run core: core_mask = %x\n", core_mask);
116 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
117 HDA_DSP_REG_ADSPCS,
118 HDA_DSP_ADSPCS_CSTALL_MASK(core_mask),
119 0);
120
121 /* is core now running ? */
122 if (!hda_dsp_core_is_enabled(sdev, core_mask)) {
123 hda_dsp_core_stall_reset(sdev, core_mask);
124 dev_err(sdev->dev, "error: DSP start core failed: core_mask %x\n",
125 core_mask);
126 ret = -EIO;
127 }
128
129 return ret;
130}
131
132/*
133 * Power Management.
134 */
135
136int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
137{
138 unsigned int cpa;
139 u32 adspcs;
140 int ret;
141
142 /* update bits */
143 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS,
144 HDA_DSP_ADSPCS_SPA_MASK(core_mask),
145 HDA_DSP_ADSPCS_SPA_MASK(core_mask));
146
147 /* poll with timeout to check if operation successful */
148 cpa = HDA_DSP_ADSPCS_CPA_MASK(core_mask);
149 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
150 HDA_DSP_REG_ADSPCS, adspcs,
151 (adspcs & cpa) == cpa,
152 HDA_DSP_REG_POLL_INTERVAL_US,
153 HDA_DSP_RESET_TIMEOUT_US);
154 if (ret < 0)
155 dev_err(sdev->dev, "error: timeout on core powerup\n");
156
157 /* did core power up ? */
158 adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
159 HDA_DSP_REG_ADSPCS);
160 if ((adspcs & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) !=
161 HDA_DSP_ADSPCS_CPA_MASK(core_mask)) {
162 dev_err(sdev->dev,
163 "error: power up core failed core_mask %xadspcs 0x%x\n",
164 core_mask, adspcs);
165 ret = -EIO;
166 }
167
168 return ret;
169}
170
171int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask)
172{
173 u32 adspcs;
174
175 /* update bits */
176 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
177 HDA_DSP_REG_ADSPCS,
178 HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0);
179
180 return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
181 HDA_DSP_REG_ADSPCS, adspcs,
182 !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)),
183 HDA_DSP_REG_POLL_INTERVAL_US,
184 HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);
185}
186
187bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev,
188 unsigned int core_mask)
189{
190 int val;
191 bool is_enable;
192
193 val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS);
194
195 is_enable = ((val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) &&
196 (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) &&
197 !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) &&
198 !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)));
199
200 dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n",
201 is_enable, core_mask);
202
203 return is_enable;
204}
205
206int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask)
207{
208 int ret;
209
210 /* return if core is already enabled */
211 if (hda_dsp_core_is_enabled(sdev, core_mask))
212 return 0;
213
214 /* power up */
215 ret = hda_dsp_core_power_up(sdev, core_mask);
216 if (ret < 0) {
217 dev_err(sdev->dev, "error: dsp core power up failed: core_mask %x\n",
218 core_mask);
219 return ret;
220 }
221
222 return hda_dsp_core_run(sdev, core_mask);
223}
224
225int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
226 unsigned int core_mask)
227{
228 int ret;
229
230 /* place core in reset prior to power down */
231 ret = hda_dsp_core_stall_reset(sdev, core_mask);
232 if (ret < 0) {
233 dev_err(sdev->dev, "error: dsp core reset failed: core_mask %x\n",
234 core_mask);
235 return ret;
236 }
237
238 /* power down core */
239 ret = hda_dsp_core_power_down(sdev, core_mask);
240 if (ret < 0) {
241 dev_err(sdev->dev, "error: dsp core power down fail mask %x: %d\n",
242 core_mask, ret);
243 return ret;
244 }
245
246 /* make sure we are in OFF state */
247 if (hda_dsp_core_is_enabled(sdev, core_mask)) {
248 dev_err(sdev->dev, "error: dsp core disable fail mask %x: %d\n",
249 core_mask, ret);
250 ret = -EIO;
251 }
252
253 return ret;
254}
255
256void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
257{
258 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
259 const struct sof_intel_dsp_desc *chip = hda->desc;
260
261 /* enable IPC DONE and BUSY interrupts */
262 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
263 HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY,
264 HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY);
265
266 /* enable IPC interrupt */
267 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
268 HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
269}
270
271void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
272{
273 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
274 const struct sof_intel_dsp_desc *chip = hda->desc;
275
276 /* disable IPC interrupt */
277 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
278 HDA_DSP_ADSPIC_IPC, 0);
279
280 /* disable IPC BUSY and DONE interrupt */
281 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
282 HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0);
283}
284
285static int hda_suspend(struct snd_sof_dev *sdev, int state)
286{
287 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
288 const struct sof_intel_dsp_desc *chip = hda->desc;
289#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
290 struct hdac_bus *bus = sof_to_bus(sdev);
291#endif
292 int ret;
293
294 /* disable IPC interrupts */
295 hda_dsp_ipc_int_disable(sdev);
296
297#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
298 /* power down all hda link */
299 snd_hdac_ext_bus_link_power_down_all(bus);
300#endif
301
302 /* power down DSP */
303 ret = hda_dsp_core_reset_power_down(sdev, chip->cores_mask);
304 if (ret < 0) {
305 dev_err(sdev->dev,
306 "error: failed to power down core during suspend\n");
307 return ret;
308 }
309
310#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
311 /* disable ppcap interrupt */
312 snd_hdac_ext_bus_ppcap_int_enable(bus, false);
313 snd_hdac_ext_bus_ppcap_enable(bus, false);
314
315 /* disable hda bus irq and i/o */
316 snd_hdac_bus_stop_chip(bus);
317#else
318 /* disable ppcap interrupt */
319 hda_dsp_ctrl_ppcap_enable(sdev, false);
320 hda_dsp_ctrl_ppcap_int_enable(sdev, false);
321
322 /* disable hda bus irq */
323 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
324 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
325 0);
326#endif
327
328 /* disable LP retention mode */
329 snd_sof_pci_update_bits(sdev, PCI_PGCTL,
330 PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK);
331
332 /* reset controller */
333 ret = hda_dsp_ctrl_link_reset(sdev, true);
334 if (ret < 0) {
335 dev_err(sdev->dev,
336 "error: failed to reset controller during suspend\n");
337 return ret;
338 }
339
340 return 0;
341}
342
343static int hda_resume(struct snd_sof_dev *sdev)
344{
345#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
346 struct hdac_bus *bus = sof_to_bus(sdev);
347 struct hdac_ext_link *hlink = NULL;
348#endif
349 int ret;
350
351 /*
352 * clear TCSEL to clear playback on some HD Audio
353 * codecs. PCI TCSEL is defined in the Intel manuals.
354 */
355 snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
356
357#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
358 /* reset and start hda controller */
359 ret = hda_dsp_ctrl_init_chip(sdev, true);
360 if (ret < 0) {
361 dev_err(sdev->dev,
362 "error: failed to start controller after resume\n");
363 return ret;
364 }
365
366 hda_dsp_ctrl_misc_clock_gating(sdev, false);
367
368 /* Reset stream-to-link mapping */
369 list_for_each_entry(hlink, &bus->hlink_list, list)
370 bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
371
372 hda_dsp_ctrl_misc_clock_gating(sdev, true);
373
374 /* enable ppcap interrupt */
375 snd_hdac_ext_bus_ppcap_enable(bus, true);
376 snd_hdac_ext_bus_ppcap_int_enable(bus, true);
377#else
378
379 hda_dsp_ctrl_misc_clock_gating(sdev, false);
380
381 /* reset controller */
382 ret = hda_dsp_ctrl_link_reset(sdev, true);
383 if (ret < 0) {
384 dev_err(sdev->dev,
385 "error: failed to reset controller during resume\n");
386 return ret;
387 }
388
389 /* take controller out of reset */
390 ret = hda_dsp_ctrl_link_reset(sdev, false);
391 if (ret < 0) {
392 dev_err(sdev->dev,
393 "error: failed to ready controller during resume\n");
394 return ret;
395 }
396
397 /* enable hda bus irq */
398 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
399 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
400 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
401
402 hda_dsp_ctrl_misc_clock_gating(sdev, true);
403
404 /* enable ppcap interrupt */
405 hda_dsp_ctrl_ppcap_enable(sdev, true);
406 hda_dsp_ctrl_ppcap_int_enable(sdev, true);
407#endif
408
409#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
410 /* turn off the links that were off before suspend */
411 list_for_each_entry(hlink, &bus->hlink_list, list) {
412 if (!hlink->ref_count)
413 snd_hdac_ext_bus_link_power_down(hlink);
414 }
415
416 /* check dma status and clean up CORB/RIRB buffers */
417 if (!bus->cmd_dma_state)
418 snd_hdac_bus_stop_cmd_io(bus);
419#endif
420
421 return 0;
422}
423
424int hda_dsp_resume(struct snd_sof_dev *sdev)
425{
426 /* init hda controller. DSP cores will be powered up during fw boot */
427 return hda_resume(sdev);
428}
429
430int hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
431{
432 /* init hda controller. DSP cores will be powered up during fw boot */
433 return hda_resume(sdev);
434}
435
436int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state)
437{
438 /* stop hda controller and power dsp off */
439 return hda_suspend(sdev, state);
440}
441
442int hda_dsp_suspend(struct snd_sof_dev *sdev, int state)
443{
444 struct hdac_bus *bus = sof_to_bus(sdev);
445 int ret;
446
447 /* stop hda controller and power dsp off */
448 ret = hda_suspend(sdev, state);
449 if (ret < 0) {
450 dev_err(bus->dev, "error: suspending dsp\n");
451 return ret;
452 }
453
454 return 0;
455}
456
457void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
458{
459 struct hdac_bus *bus = sof_to_bus(sdev);
460 struct sof_intel_hda_stream *hda_stream;
461 struct hdac_ext_stream *stream;
462 struct hdac_stream *s;
463
464 /* set internal flag for BE */
465 list_for_each_entry(s, &bus->stream_list, list) {
466 stream = stream_to_hdac_ext_stream(s);
467 hda_stream = container_of(stream, struct sof_intel_hda_stream,
468 hda_stream);
469 hda_stream->hw_params_upon_resume = 1;
470 }
471}
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
new file mode 100644
index 000000000000..73ead7070cde
--- /dev/null
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -0,0 +1,455 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include "../ops.h"
19#include "hda.h"
20
21static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev)
22{
23 /*
24 * tell DSP cmd is done - clear busy
25 * interrupt and send reply msg to dsp
26 */
27 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
28 HDA_DSP_REG_HIPCT,
29 HDA_DSP_REG_HIPCT_BUSY,
30 HDA_DSP_REG_HIPCT_BUSY);
31
32 /* unmask BUSY interrupt */
33 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
34 HDA_DSP_REG_HIPCCTL,
35 HDA_DSP_REG_HIPCCTL_BUSY,
36 HDA_DSP_REG_HIPCCTL_BUSY);
37}
38
39static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev)
40{
41 /*
42 * set DONE bit - tell DSP we have received the reply msg
43 * from DSP, and processed it, don't send more reply to host
44 */
45 snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR,
46 HDA_DSP_REG_HIPCIE,
47 HDA_DSP_REG_HIPCIE_DONE,
48 HDA_DSP_REG_HIPCIE_DONE);
49
50 /* unmask Done interrupt */
51 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
52 HDA_DSP_REG_HIPCCTL,
53 HDA_DSP_REG_HIPCCTL_DONE,
54 HDA_DSP_REG_HIPCCTL_DONE);
55}
56
57int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
58{
59 u32 cmd = msg->header;
60
61 /* send IPC message to DSP */
62 sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
63 msg->msg_size);
64 snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI,
65 cmd | HDA_DSP_REG_HIPCI_BUSY);
66
67 return 0;
68}
69
70void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
71{
72 struct snd_sof_ipc_msg *msg = sdev->msg;
73 struct sof_ipc_reply reply;
74 struct sof_ipc_cmd_hdr *hdr;
75 unsigned long flags;
76 int ret = 0;
77
78 /*
79 * Sometimes, there is unexpected reply ipc arriving. The reply
80 * ipc belongs to none of the ipcs sent from driver.
81 * In this case, the driver must ignore the ipc.
82 */
83 if (!msg) {
84 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
85 return;
86 }
87 spin_lock_irqsave(&sdev->ipc_lock, flags);
88
89 hdr = msg->msg_data;
90 if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) {
91 /*
92 * memory windows are powered off before sending IPC reply,
93 * so we can't read the mailbox for CTX_SAVE reply.
94 */
95 reply.error = 0;
96 reply.hdr.cmd = SOF_IPC_GLB_REPLY;
97 reply.hdr.size = sizeof(reply);
98 memcpy(msg->reply_data, &reply, sizeof(reply));
99 goto out;
100 }
101
102 /* get IPC reply from DSP in the mailbox */
103 sof_mailbox_read(sdev, sdev->host_box.offset, &reply,
104 sizeof(reply));
105
106 if (reply.error < 0) {
107 memcpy(msg->reply_data, &reply, sizeof(reply));
108 ret = reply.error;
109 } else {
110 /* reply correct size ? */
111 if (reply.hdr.size != msg->reply_size) {
112 dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
113 msg->reply_size, reply.hdr.size);
114 ret = -EINVAL;
115 }
116
117 /* read the message */
118 if (msg->reply_size > 0)
119 sof_mailbox_read(sdev, sdev->host_box.offset,
120 msg->reply_data, msg->reply_size);
121 }
122
123out:
124 msg->reply_error = ret;
125
126 spin_unlock_irqrestore(&sdev->ipc_lock, flags);
127}
128
129static bool hda_dsp_ipc_is_sof(uint32_t msg)
130{
131 return (msg & (HDA_DSP_IPC_PURGE_FW | 0xf << 9)) != msg ||
132 (msg & HDA_DSP_IPC_PURGE_FW) != HDA_DSP_IPC_PURGE_FW;
133}
134
135/* IPC handler thread */
136irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
137{
138 struct snd_sof_dev *sdev = context;
139 irqreturn_t ret = IRQ_NONE;
140 u32 hipci;
141 u32 hipcie;
142 u32 hipct;
143 u32 hipcte;
144 u32 hipcctl;
145 u32 msg;
146 u32 msg_ext;
147
148 /* read IPC status */
149 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
150 HDA_DSP_REG_HIPCIE);
151 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
152 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
153
154 /* reenable IPC interrupt */
155 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
156 HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
157
158 /* is this a reply message from the DSP */
159 if (hipcie & HDA_DSP_REG_HIPCIE_DONE &&
160 hipcctl & HDA_DSP_REG_HIPCCTL_DONE) {
161 hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
162 HDA_DSP_REG_HIPCI);
163 msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK;
164 msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK;
165
166 dev_vdbg(sdev->dev,
167 "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n",
168 msg, msg_ext);
169
170 /* mask Done interrupt */
171 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
172 HDA_DSP_REG_HIPCCTL,
173 HDA_DSP_REG_HIPCCTL_DONE, 0);
174
175 /* handle immediate reply from DSP core - ignore ROM messages */
176 if (hda_dsp_ipc_is_sof(msg)) {
177 hda_dsp_ipc_get_reply(sdev);
178 snd_sof_ipc_reply(sdev, msg);
179 }
180
181 /* wake up sleeper if we are loading code */
182 if (sdev->code_loading) {
183 sdev->code_loading = 0;
184 wake_up(&sdev->waitq);
185 }
186
187 /* set the done bit */
188 hda_dsp_ipc_dsp_done(sdev);
189
190 ret = IRQ_HANDLED;
191 }
192
193 /* is this a new message from DSP */
194 if (hipct & HDA_DSP_REG_HIPCT_BUSY &&
195 hipcctl & HDA_DSP_REG_HIPCCTL_BUSY) {
196
197 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
198 HDA_DSP_REG_HIPCTE);
199 msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK;
200 msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK;
201
202 dev_vdbg(sdev->dev,
203 "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n",
204 msg, msg_ext);
205
206 /* mask BUSY interrupt */
207 snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
208 HDA_DSP_REG_HIPCCTL,
209 HDA_DSP_REG_HIPCCTL_BUSY, 0);
210
211 /* handle messages from DSP */
212 if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
213 /* this is a PANIC message !! */
214 snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext));
215 } else {
216 /* normal message - process normally */
217 snd_sof_ipc_msgs_rx(sdev);
218 }
219
220 hda_dsp_ipc_host_done(sdev);
221
222 ret = IRQ_HANDLED;
223 }
224
225 return ret;
226}
227
228/* is this IRQ for ADSP ? - we only care about IPC here */
229irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context)
230{
231 struct snd_sof_dev *sdev = context;
232 int ret = IRQ_NONE;
233 u32 irq_status;
234
235 spin_lock(&sdev->hw_lock);
236
237 /* store status */
238 irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
239 dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status);
240
241 /* invalid message ? */
242 if (irq_status == 0xffffffff)
243 goto out;
244
245 /* IPC message ? */
246 if (irq_status & HDA_DSP_ADSPIS_IPC) {
247 /* disable IPC interrupt */
248 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
249 HDA_DSP_REG_ADSPIC,
250 HDA_DSP_ADSPIC_IPC, 0);
251 ret = IRQ_WAKE_THREAD;
252 }
253
254out:
255 spin_unlock(&sdev->hw_lock);
256 return ret;
257}
258
259/* IPC Firmware ready */
260
261static void ipc_get_windows(struct snd_sof_dev *sdev)
262{
263 struct sof_ipc_window_elem *elem;
264 u32 outbox_offset = 0;
265 u32 stream_offset = 0;
266 u32 inbox_offset = 0;
267 u32 outbox_size = 0;
268 u32 stream_size = 0;
269 u32 inbox_size = 0;
270 int i;
271
272 if (!sdev->info_window) {
273 dev_err(sdev->dev, "error: have no window info\n");
274 return;
275 }
276
277 for (i = 0; i < sdev->info_window->num_windows; i++) {
278 elem = &sdev->info_window->window[i];
279
280 switch (elem->type) {
281 case SOF_IPC_REGION_UPBOX:
282 inbox_offset =
283 elem->offset + SRAM_WINDOW_OFFSET(elem->id);
284 inbox_size = elem->size;
285 snd_sof_debugfs_io_item(sdev,
286 sdev->bar[HDA_DSP_BAR] +
287 inbox_offset,
288 elem->size, "inbox",
289 SOF_DEBUGFS_ACCESS_D0_ONLY);
290 break;
291 case SOF_IPC_REGION_DOWNBOX:
292 outbox_offset =
293 elem->offset + SRAM_WINDOW_OFFSET(elem->id);
294 outbox_size = elem->size;
295 snd_sof_debugfs_io_item(sdev,
296 sdev->bar[HDA_DSP_BAR] +
297 outbox_offset,
298 elem->size, "outbox",
299 SOF_DEBUGFS_ACCESS_D0_ONLY);
300 break;
301 case SOF_IPC_REGION_TRACE:
302 snd_sof_debugfs_io_item(sdev,
303 sdev->bar[HDA_DSP_BAR] +
304 elem->offset +
305 SRAM_WINDOW_OFFSET
306 (elem->id),
307 elem->size, "etrace",
308 SOF_DEBUGFS_ACCESS_D0_ONLY);
309 break;
310 case SOF_IPC_REGION_DEBUG:
311 snd_sof_debugfs_io_item(sdev,
312 sdev->bar[HDA_DSP_BAR] +
313 elem->offset +
314 SRAM_WINDOW_OFFSET
315 (elem->id),
316 elem->size, "debug",
317 SOF_DEBUGFS_ACCESS_D0_ONLY);
318 break;
319 case SOF_IPC_REGION_STREAM:
320 stream_offset =
321 elem->offset + SRAM_WINDOW_OFFSET(elem->id);
322 stream_size = elem->size;
323 snd_sof_debugfs_io_item(sdev,
324 sdev->bar[HDA_DSP_BAR] +
325 elem->offset +
326 SRAM_WINDOW_OFFSET
327 (elem->id),
328 elem->size, "stream",
329 SOF_DEBUGFS_ACCESS_D0_ONLY);
330 break;
331 case SOF_IPC_REGION_REGS:
332 snd_sof_debugfs_io_item(sdev,
333 sdev->bar[HDA_DSP_BAR] +
334 elem->offset +
335 SRAM_WINDOW_OFFSET
336 (elem->id),
337 elem->size, "regs",
338 SOF_DEBUGFS_ACCESS_D0_ONLY);
339 break;
340 case SOF_IPC_REGION_EXCEPTION:
341 sdev->dsp_oops_offset = elem->offset +
342 SRAM_WINDOW_OFFSET(elem->id);
343 snd_sof_debugfs_io_item(sdev,
344 sdev->bar[HDA_DSP_BAR] +
345 elem->offset +
346 SRAM_WINDOW_OFFSET
347 (elem->id),
348 elem->size, "exception",
349 SOF_DEBUGFS_ACCESS_D0_ONLY);
350 break;
351 default:
352 dev_err(sdev->dev, "error: get illegal window info\n");
353 return;
354 }
355 }
356
357 if (outbox_size == 0 || inbox_size == 0) {
358 dev_err(sdev->dev, "error: get illegal mailbox window\n");
359 return;
360 }
361
362 snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
363 outbox_offset, outbox_size);
364 sdev->stream_box.offset = stream_offset;
365 sdev->stream_box.size = stream_size;
366
367 dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
368 inbox_offset, inbox_size);
369 dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
370 outbox_offset, outbox_size);
371 dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
372 stream_offset, stream_size);
373}
374
375/* check for ABI compatibility and create memory windows on first boot */
376int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
377{
378 struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
379 u32 offset;
380 int ret;
381
382 /* mailbox must be on 4k boundary */
383 offset = HDA_DSP_MBOX_UPLINK_OFFSET;
384
385 dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
386 msg_id, offset);
387
388 /* no need to re-check version/ABI for subsequent boots */
389 if (!sdev->first_boot)
390 return 0;
391
392 /* copy data from the DSP FW ready offset */
393 sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready,
394 sizeof(*fw_ready));
395
396 /* make sure ABI version is compatible */
397 ret = snd_sof_ipc_valid(sdev);
398 if (ret < 0)
399 return ret;
400
401 /* now check for extended data */
402 snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar,
403 HDA_DSP_MBOX_UPLINK_OFFSET +
404 sizeof(struct sof_ipc_fw_ready));
405
406 ipc_get_windows(sdev);
407
408 return 0;
409}
410
411void hda_ipc_msg_data(struct snd_sof_dev *sdev,
412 struct snd_pcm_substream *substream,
413 void *p, size_t sz)
414{
415 if (!substream || !sdev->stream_box.size) {
416 sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
417 } else {
418 struct hdac_stream *hstream = substream->runtime->private_data;
419 struct sof_intel_hda_stream *hda_stream;
420
421 hda_stream = container_of(hstream,
422 struct sof_intel_hda_stream,
423 hda_stream.hstream);
424
425 /* The stream might already be closed */
426 if (hstream)
427 sof_mailbox_read(sdev, hda_stream->stream.posn_offset,
428 p, sz);
429 }
430}
431
432int hda_ipc_pcm_params(struct snd_sof_dev *sdev,
433 struct snd_pcm_substream *substream,
434 const struct sof_ipc_pcm_params_reply *reply)
435{
436 struct hdac_stream *hstream = substream->runtime->private_data;
437 struct sof_intel_hda_stream *hda_stream;
438 /* validate offset */
439 size_t posn_offset = reply->posn_offset;
440
441 hda_stream = container_of(hstream, struct sof_intel_hda_stream,
442 hda_stream.hstream);
443
444 /* check for unaligned offset or overflow */
445 if (posn_offset > sdev->stream_box.size ||
446 posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
447 return -EINVAL;
448
449 hda_stream->stream.posn_offset = sdev->stream_box.offset + posn_offset;
450
451 dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
452 substream->stream, hda_stream->stream.posn_offset);
453
454 return 0;
455}
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
new file mode 100644
index 000000000000..6427f0b3a2f1
--- /dev/null
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -0,0 +1,382 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for HDA DSP code loader
16 */
17
18#include <linux/firmware.h>
19#include <sound/hdaudio_ext.h>
20#include <sound/sof.h>
21#include "../ops.h"
22#include "hda.h"
23
24#define HDA_FW_BOOT_ATTEMPTS 3
25
26static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
27 unsigned int size, struct snd_dma_buffer *dmab,
28 int direction)
29{
30 struct hdac_ext_stream *dsp_stream;
31 struct hdac_stream *hstream;
32 struct pci_dev *pci = to_pci_dev(sdev->dev);
33 int ret;
34
35 if (direction != SNDRV_PCM_STREAM_PLAYBACK) {
36 dev_err(sdev->dev, "error: code loading DMA is playback only\n");
37 return -EINVAL;
38 }
39
40 dsp_stream = hda_dsp_stream_get(sdev, direction);
41
42 if (!dsp_stream) {
43 dev_err(sdev->dev, "error: no stream available\n");
44 return -ENODEV;
45 }
46 hstream = &dsp_stream->hstream;
47
48 /* allocate DMA buffer */
49 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
50 if (ret < 0) {
51 dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret);
52 goto error;
53 }
54
55 hstream->period_bytes = 0;/* initialize period_bytes */
56 hstream->format_val = format;
57 hstream->bufsize = size;
58
59 ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL);
60 if (ret < 0) {
61 dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
62 goto error;
63 }
64
65 hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size);
66
67 return hstream->stream_tag;
68
69error:
70 hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
71 snd_dma_free_pages(dmab);
72 return ret;
73}
74
75/*
76 * first boot sequence has some extra steps. core 0 waits for power
77 * status on core 1, so power up core 1 also momentarily, keep it in
78 * reset/stall and then turn it off
79 */
80static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata,
81 u32 fwsize, int stream_tag)
82{
83 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
84 const struct sof_intel_dsp_desc *chip = hda->desc;
85 unsigned int status;
86 int ret;
87 int i;
88
89 /* step 1: power up corex */
90 ret = hda_dsp_core_power_up(sdev, chip->cores_mask);
91 if (ret < 0) {
92 dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
93 goto err;
94 }
95
96 /* DSP is powered up, set all SSPs to slave mode */
97 for (i = 0; i < chip->ssp_count; i++) {
98 snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
99 chip->ssp_base_offset
100 + i * SSP_DEV_MEM_SIZE
101 + SSP_SSC1_OFFSET,
102 SSP_SET_SLAVE,
103 SSP_SET_SLAVE);
104 }
105
106 /* step 2: purge FW request */
107 snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req,
108 chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW |
109 ((stream_tag - 1) << 9)));
110
111 /* step 3: unset core 0 reset state & unstall/run core 0 */
112 ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0));
113 if (ret < 0) {
114 dev_err(sdev->dev, "error: dsp core start failed %d\n", ret);
115 ret = -EIO;
116 goto err;
117 }
118
119 /* step 4: wait for IPC DONE bit from ROM */
120 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
121 chip->ipc_ack, status,
122 ((status & chip->ipc_ack_mask)
123 == chip->ipc_ack_mask),
124 HDA_DSP_REG_POLL_INTERVAL_US,
125 HDA_DSP_INIT_TIMEOUT_US);
126
127 if (ret < 0) {
128 dev_err(sdev->dev, "error: waiting for HIPCIE done\n");
129 goto err;
130 }
131
132 /* step 5: power down corex */
133 ret = hda_dsp_core_power_down(sdev,
134 chip->cores_mask & ~(HDA_DSP_CORE_MASK(0)));
135 if (ret < 0) {
136 dev_err(sdev->dev, "error: dsp core x power down failed\n");
137 goto err;
138 }
139
140 /* step 6: enable IPC interrupts */
141 hda_dsp_ipc_int_enable(sdev);
142
143 /* step 7: wait for ROM init */
144 ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
145 HDA_DSP_SRAM_REG_ROM_STATUS, status,
146 ((status & HDA_DSP_ROM_STS_MASK)
147 == HDA_DSP_ROM_INIT),
148 HDA_DSP_REG_POLL_INTERVAL_US,
149 chip->rom_init_timeout *
150 USEC_PER_MSEC);
151 if (!ret)
152 return 0;
153
154err:
155 hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
156 hda_dsp_core_reset_power_down(sdev, chip->cores_mask);
157
158 return ret;
159}
160
161static int cl_trigger(struct snd_sof_dev *sdev,
162 struct hdac_ext_stream *stream, int cmd)
163{
164 struct hdac_stream *hstream = &stream->hstream;
165 int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
166
167 /* code loader is special case that reuses stream ops */
168 switch (cmd) {
169 case SNDRV_PCM_TRIGGER_START:
170 wait_event_timeout(sdev->waitq, !sdev->code_loading,
171 HDA_DSP_CL_TRIGGER_TIMEOUT);
172
173 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
174 1 << hstream->index,
175 1 << hstream->index);
176
177 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
178 sd_offset,
179 SOF_HDA_SD_CTL_DMA_START |
180 SOF_HDA_CL_DMA_SD_INT_MASK,
181 SOF_HDA_SD_CTL_DMA_START |
182 SOF_HDA_CL_DMA_SD_INT_MASK);
183
184 hstream->running = true;
185 return 0;
186 default:
187 return hda_dsp_stream_trigger(sdev, stream, cmd);
188 }
189}
190
191static struct hdac_ext_stream *get_stream_with_tag(struct snd_sof_dev *sdev,
192 int tag)
193{
194 struct hdac_bus *bus = sof_to_bus(sdev);
195 struct hdac_stream *s;
196
197 /* get stream with tag */
198 list_for_each_entry(s, &bus->stream_list, list) {
199 if (s->direction == SNDRV_PCM_STREAM_PLAYBACK &&
200 s->stream_tag == tag) {
201 return stream_to_hdac_ext_stream(s);
202 }
203 }
204
205 return NULL;
206}
207
208static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
209 struct hdac_ext_stream *stream)
210{
211 struct hdac_stream *hstream = &stream->hstream;
212 int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
213 int ret;
214
215 ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0);
216
217 hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_PLAYBACK,
218 hstream->stream_tag);
219 hstream->running = 0;
220 hstream->substream = NULL;
221
222 /* reset BDL address */
223 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
224 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0);
225 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
226 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0);
227
228 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
229 snd_dma_free_pages(dmab);
230 dmab->area = NULL;
231 hstream->bufsize = 0;
232 hstream->format_val = 0;
233
234 return ret;
235}
236
237static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream)
238{
239 unsigned int reg;
240 int ret, status;
241
242 ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START);
243 if (ret < 0) {
244 dev_err(sdev->dev, "error: DMA trigger start failed\n");
245 return ret;
246 }
247
248 status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
249 HDA_DSP_SRAM_REG_ROM_STATUS, reg,
250 ((reg & HDA_DSP_ROM_STS_MASK)
251 == HDA_DSP_ROM_FW_ENTERED),
252 HDA_DSP_REG_POLL_INTERVAL_US,
253 HDA_DSP_BASEFW_TIMEOUT_US);
254
255 ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP);
256 if (ret < 0) {
257 dev_err(sdev->dev, "error: DMA trigger stop failed\n");
258 return ret;
259 }
260
261 return status;
262}
263
264int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
265{
266 struct snd_sof_pdata *plat_data = sdev->pdata;
267 const struct sof_dev_desc *desc = plat_data->desc;
268 const struct sof_intel_dsp_desc *chip_info;
269 struct hdac_ext_stream *stream;
270 struct firmware stripped_firmware;
271 int ret, ret1, tag, i;
272
273 chip_info = desc->chip_info;
274
275 stripped_firmware.data = plat_data->fw->data;
276 stripped_firmware.size = plat_data->fw->size;
277
278 /* init for booting wait */
279 init_waitqueue_head(&sdev->boot_wait);
280 sdev->boot_complete = false;
281
282 /* prepare DMA for code loader stream */
283 tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size,
284 &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK);
285
286 if (tag < 0) {
287 dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n",
288 tag);
289 return tag;
290 }
291
292 /* get stream with tag */
293 stream = get_stream_with_tag(sdev, tag);
294 if (!stream) {
295 dev_err(sdev->dev,
296 "error: could not get stream with stream tag %d\n",
297 tag);
298 ret = -ENODEV;
299 goto err;
300 }
301
302 memcpy(sdev->dmab.area, stripped_firmware.data,
303 stripped_firmware.size);
304
305 /* try ROM init a few times before giving up */
306 for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) {
307 ret = cl_dsp_init(sdev, stripped_firmware.data,
308 stripped_firmware.size, tag);
309
310 /* don't retry anymore if successful */
311 if (!ret)
312 break;
313
314 dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n",
315 snd_sof_dsp_read(sdev, HDA_DSP_BAR,
316 HDA_DSP_SRAM_REG_ROM_ERROR),
317 snd_sof_dsp_read(sdev, HDA_DSP_BAR,
318 HDA_DSP_SRAM_REG_ROM_STATUS));
319 dev_err(sdev->dev, "error: iteration %d of Core En/ROM load failed: %d\n",
320 i, ret);
321 }
322
323 if (i == HDA_FW_BOOT_ATTEMPTS) {
324 dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n",
325 i, ret);
326 goto cleanup;
327 }
328
329 /*
330 * at this point DSP ROM has been initialized and
331 * should be ready for code loading and firmware boot
332 */
333 ret = cl_copy_fw(sdev, stream);
334 if (!ret)
335 dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
336 else
337 dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret);
338
339cleanup:
340 /*
341 * Perform codeloader stream cleanup.
342 * This should be done even if firmware loading fails.
343 */
344 ret1 = cl_cleanup(sdev, &sdev->dmab, stream);
345 if (ret1 < 0) {
346 dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
347
348 /* set return value to indicate cleanup failure */
349 ret = ret1;
350 }
351
352 /*
353 * return master core id if both fw copy
354 * and stream clean up are successful
355 */
356 if (!ret)
357 return chip_info->init_core_mask;
358
359 /* dump dsp registers and disable DSP upon error */
360err:
361 hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX);
362
363 /* disable DSP */
364 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
365 SOF_HDA_REG_PP_PPCTL,
366 SOF_HDA_PPCTL_GPROCEN, 0);
367 return ret;
368}
369
370/* pre fw run operations */
371int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
372{
373 /* disable clock gating and power gating */
374 return hda_dsp_ctrl_clock_power_gating(sdev, false);
375}
376
377/* post fw run operations */
378int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
379{
380 /* re-enable clock gating and power gating */
381 return hda_dsp_ctrl_clock_power_gating(sdev, true);
382}
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
new file mode 100644
index 000000000000..9b730f183529
--- /dev/null
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -0,0 +1,239 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include <sound/hda_register.h>
19#include <sound/pcm_params.h>
20#include "../ops.h"
21#include "hda.h"
22
23#define SDnFMT_BASE(x) ((x) << 14)
24#define SDnFMT_MULT(x) (((x) - 1) << 11)
25#define SDnFMT_DIV(x) (((x) - 1) << 8)
26#define SDnFMT_BITS(x) ((x) << 4)
27#define SDnFMT_CHAN(x) ((x) << 0)
28
29static inline u32 get_mult_div(struct snd_sof_dev *sdev, int rate)
30{
31 switch (rate) {
32 case 8000:
33 return SDnFMT_DIV(6);
34 case 9600:
35 return SDnFMT_DIV(5);
36 case 11025:
37 return SDnFMT_BASE(1) | SDnFMT_DIV(4);
38 case 16000:
39 return SDnFMT_DIV(3);
40 case 22050:
41 return SDnFMT_BASE(1) | SDnFMT_DIV(2);
42 case 32000:
43 return SDnFMT_DIV(3) | SDnFMT_MULT(2);
44 case 44100:
45 return SDnFMT_BASE(1);
46 case 48000:
47 return 0;
48 case 88200:
49 return SDnFMT_BASE(1) | SDnFMT_MULT(2);
50 case 96000:
51 return SDnFMT_MULT(2);
52 case 176400:
53 return SDnFMT_BASE(1) | SDnFMT_MULT(4);
54 case 192000:
55 return SDnFMT_MULT(4);
56 default:
57 dev_warn(sdev->dev, "can't find div rate %d using 48kHz\n",
58 rate);
59 return 0; /* use 48KHz if not found */
60 }
61};
62
63static inline u32 get_bits(struct snd_sof_dev *sdev, int sample_bits)
64{
65 switch (sample_bits) {
66 case 8:
67 return SDnFMT_BITS(0);
68 case 16:
69 return SDnFMT_BITS(1);
70 case 20:
71 return SDnFMT_BITS(2);
72 case 24:
73 return SDnFMT_BITS(3);
74 case 32:
75 return SDnFMT_BITS(4);
76 default:
77 dev_warn(sdev->dev, "can't find %d bits using 16bit\n",
78 sample_bits);
79 return SDnFMT_BITS(1); /* use 16bits format if not found */
80 }
81};
82
83int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
84 struct snd_pcm_substream *substream,
85 struct snd_pcm_hw_params *params,
86 struct sof_ipc_stream_params *ipc_params)
87{
88 struct hdac_stream *hstream = substream->runtime->private_data;
89 struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream);
90 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
91 struct snd_dma_buffer *dmab;
92 int ret;
93 u32 size, rate, bits;
94
95 size = params_buffer_bytes(params);
96 rate = get_mult_div(sdev, params_rate(params));
97 bits = get_bits(sdev, params_width(params));
98
99 hstream->substream = substream;
100
101 dmab = substream->runtime->dma_buffer_p;
102
103 hstream->format_val = rate | bits | (params_channels(params) - 1);
104 hstream->bufsize = size;
105 hstream->period_bytes = params_period_bytes(params);
106 hstream->no_period_wakeup =
107 (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
108 (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
109
110 ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params);
111 if (ret < 0) {
112 dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
113 return ret;
114 }
115
116 /* disable SPIB, to enable buffer wrap for stream */
117 hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0);
118
119 /* set host_period_bytes to 0 if no IPC position */
120 if (hda && hda->no_ipc_position)
121 ipc_params->host_period_bytes = 0;
122
123 ipc_params->stream_tag = hstream->stream_tag;
124
125 return 0;
126}
127
128int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
129 struct snd_pcm_substream *substream, int cmd)
130{
131 struct hdac_stream *hstream = substream->runtime->private_data;
132 struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream);
133
134 return hda_dsp_stream_trigger(sdev, stream, cmd);
135}
136
137snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
138 struct snd_pcm_substream *substream)
139{
140 struct snd_soc_pcm_runtime *rtd = substream->private_data;
141 struct hdac_stream *hstream = substream->runtime->private_data;
142 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
143 struct snd_sof_pcm *spcm;
144 snd_pcm_uframes_t pos;
145
146 spcm = snd_sof_find_spcm_dai(sdev, rtd);
147 if (!spcm) {
148 dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
149 rtd->dai_link->id);
150 return 0;
151 }
152
153 if (hda && !hda->no_ipc_position) {
154 /* read position from IPC position */
155 pos = spcm->stream[substream->stream].posn.host_posn;
156 goto found;
157 }
158
159 /*
160 * DPIB/posbuf position mode:
161 * For Playback, Use DPIB register from HDA space which
162 * reflects the actual data transferred.
163 * For Capture, Use the position buffer for pointer, as DPIB
164 * is not accurate enough, its update may be completed
165 * earlier than the data written to DDR.
166 */
167 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
168 pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
169 AZX_REG_VS_SDXDPIB_XBASE +
170 (AZX_REG_VS_SDXDPIB_XINTERVAL *
171 hstream->index));
172 } else {
173 /*
174 * For capture stream, we need more workaround to fix the
175 * position incorrect issue:
176 *
177 * 1. Wait at least 20us before reading position buffer after
178 * the interrupt generated(IOC), to make sure position update
179 * happens on frame boundary i.e. 20.833uSec for 48KHz.
180 * 2. Perform a dummy Read to DPIB register to flush DMA
181 * position value.
182 * 3. Read the DMA Position from posbuf. Now the readback
183 * value should be >= period boundary.
184 */
185 usleep_range(20, 21);
186 snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
187 AZX_REG_VS_SDXDPIB_XBASE +
188 (AZX_REG_VS_SDXDPIB_XINTERVAL *
189 hstream->index));
190 pos = snd_hdac_stream_get_pos_posbuf(hstream);
191 }
192
193 if (pos >= hstream->bufsize)
194 pos = 0;
195
196found:
197 pos = bytes_to_frames(substream->runtime, pos);
198
199 dev_vdbg(sdev->dev, "PCM: stream %d dir %d position %lu\n",
200 hstream->index, substream->stream, pos);
201 return pos;
202}
203
204int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
205 struct snd_pcm_substream *substream)
206{
207 struct hdac_ext_stream *dsp_stream;
208 int direction = substream->stream;
209
210 dsp_stream = hda_dsp_stream_get(sdev, direction);
211
212 if (!dsp_stream) {
213 dev_err(sdev->dev, "error: no stream available\n");
214 return -ENODEV;
215 }
216
217 /* binding pcm substream to hda stream */
218 substream->runtime->private_data = &dsp_stream->hstream;
219 return 0;
220}
221
222int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
223 struct snd_pcm_substream *substream)
224{
225 struct hdac_stream *hstream = substream->runtime->private_data;
226 int direction = substream->stream;
227 int ret;
228
229 ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
230
231 if (ret) {
232 dev_dbg(sdev->dev, "stream %s not opened!\n", substream->name);
233 return -ENODEV;
234 }
235
236 /* unbinding pcm substream to hda stream */
237 substream->runtime->private_data = NULL;
238 return 0;
239}
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
new file mode 100644
index 000000000000..c92006f89499
--- /dev/null
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -0,0 +1,701 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include <linux/pm_runtime.h>
19#include <sound/hdaudio_ext.h>
20#include <sound/hda_register.h>
21#include <sound/sof.h>
22#include "../ops.h"
23#include "hda.h"
24
25/*
26 * set up one of BDL entries for a stream
27 */
28static int hda_setup_bdle(struct snd_sof_dev *sdev,
29 struct snd_dma_buffer *dmab,
30 struct hdac_stream *stream,
31 struct sof_intel_dsp_bdl **bdlp,
32 int offset, int size, int ioc)
33{
34 struct hdac_bus *bus = sof_to_bus(sdev);
35 struct sof_intel_dsp_bdl *bdl = *bdlp;
36
37 while (size > 0) {
38 dma_addr_t addr;
39 int chunk;
40
41 if (stream->frags >= HDA_DSP_MAX_BDL_ENTRIES) {
42 dev_err(sdev->dev, "error: stream frags exceeded\n");
43 return -EINVAL;
44 }
45
46 addr = snd_sgbuf_get_addr(dmab, offset);
47 /* program BDL addr */
48 bdl->addr_l = cpu_to_le32(lower_32_bits(addr));
49 bdl->addr_h = cpu_to_le32(upper_32_bits(addr));
50 /* program BDL size */
51 chunk = snd_sgbuf_get_chunk_size(dmab, offset, size);
52 /* one BDLE should not cross 4K boundary */
53 if (bus->align_bdle_4k) {
54 u32 remain = 0x1000 - (offset & 0xfff);
55
56 if (chunk > remain)
57 chunk = remain;
58 }
59 bdl->size = cpu_to_le32(chunk);
60 /* only program IOC when the whole segment is processed */
61 size -= chunk;
62 bdl->ioc = (size || !ioc) ? 0 : cpu_to_le32(0x01);
63 bdl++;
64 stream->frags++;
65 offset += chunk;
66
67 dev_vdbg(sdev->dev, "bdl, frags:%d, chunk size:0x%x;\n",
68 stream->frags, chunk);
69 }
70
71 *bdlp = bdl;
72 return offset;
73}
74
75/*
76 * set up Buffer Descriptor List (BDL) for host memory transfer
77 * BDL describes the location of the individual buffers and is little endian.
78 */
79int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
80 struct snd_dma_buffer *dmab,
81 struct hdac_stream *stream)
82{
83 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
84 struct sof_intel_dsp_bdl *bdl;
85 int i, offset, period_bytes, periods;
86 int remain, ioc;
87
88 period_bytes = stream->period_bytes;
89 dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes);
90 if (!period_bytes)
91 period_bytes = stream->bufsize;
92
93 periods = stream->bufsize / period_bytes;
94
95 dev_dbg(sdev->dev, "periods:%d\n", periods);
96
97 remain = stream->bufsize % period_bytes;
98 if (remain)
99 periods++;
100
101 /* program the initial BDL entries */
102 bdl = (struct sof_intel_dsp_bdl *)stream->bdl.area;
103 offset = 0;
104 stream->frags = 0;
105
106 /*
107 * set IOC if don't use position IPC
108 * and period_wakeup needed.
109 */
110 ioc = hda->no_ipc_position ?
111 !stream->no_period_wakeup : 0;
112
113 for (i = 0; i < periods; i++) {
114 if (i == (periods - 1) && remain)
115 /* set the last small entry */
116 offset = hda_setup_bdle(sdev, dmab,
117 stream, &bdl, offset,
118 remain, 0);
119 else
120 offset = hda_setup_bdle(sdev, dmab,
121 stream, &bdl, offset,
122 period_bytes, ioc);
123 }
124
125 return offset;
126}
127
128int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
129 struct hdac_ext_stream *stream,
130 int enable, u32 size)
131{
132 struct hdac_stream *hstream = &stream->hstream;
133 u32 mask;
134
135 if (!sdev->bar[HDA_DSP_SPIB_BAR]) {
136 dev_err(sdev->dev, "error: address of spib capability is NULL\n");
137 return -EINVAL;
138 }
139
140 mask = (1 << hstream->index);
141
142 /* enable/disable SPIB for the stream */
143 snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR,
144 SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask,
145 enable << hstream->index);
146
147 /* set the SPIB value */
148 sof_io_write(sdev, stream->spib_addr, size);
149
150 return 0;
151}
152
153/* get next unused stream */
154struct hdac_ext_stream *
155hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
156{
157 struct hdac_bus *bus = sof_to_bus(sdev);
158 struct hdac_ext_stream *stream = NULL;
159 struct hdac_stream *s;
160
161 spin_lock_irq(&bus->reg_lock);
162
163 /* get an unused stream */
164 list_for_each_entry(s, &bus->stream_list, list) {
165 if (s->direction == direction && !s->opened) {
166 s->opened = true;
167 stream = stream_to_hdac_ext_stream(s);
168 break;
169 }
170 }
171
172 spin_unlock_irq(&bus->reg_lock);
173
174 /* stream found ? */
175 if (!stream)
176 dev_err(sdev->dev, "error: no free %s streams\n",
177 direction == SNDRV_PCM_STREAM_PLAYBACK ?
178 "playback" : "capture");
179
180 return stream;
181}
182
183/* free a stream */
184int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
185{
186 struct hdac_bus *bus = sof_to_bus(sdev);
187 struct hdac_stream *s;
188
189 spin_lock_irq(&bus->reg_lock);
190
191 /* find used stream */
192 list_for_each_entry(s, &bus->stream_list, list) {
193 if (s->direction == direction &&
194 s->opened && s->stream_tag == stream_tag) {
195 s->opened = false;
196 spin_unlock_irq(&bus->reg_lock);
197 return 0;
198 }
199 }
200
201 spin_unlock_irq(&bus->reg_lock);
202
203 dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
204 return -ENODEV;
205}
206
207int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
208 struct hdac_ext_stream *stream, int cmd)
209{
210 struct hdac_stream *hstream = &stream->hstream;
211 int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
212
213 /* cmd must be for audio stream */
214 switch (cmd) {
215 case SNDRV_PCM_TRIGGER_RESUME:
216 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
217 case SNDRV_PCM_TRIGGER_START:
218 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
219 1 << hstream->index,
220 1 << hstream->index);
221
222 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
223 sd_offset,
224 SOF_HDA_SD_CTL_DMA_START |
225 SOF_HDA_CL_DMA_SD_INT_MASK,
226 SOF_HDA_SD_CTL_DMA_START |
227 SOF_HDA_CL_DMA_SD_INT_MASK);
228
229 hstream->running = true;
230 break;
231 case SNDRV_PCM_TRIGGER_SUSPEND:
232 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
233 case SNDRV_PCM_TRIGGER_STOP:
234 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
235 sd_offset,
236 SOF_HDA_SD_CTL_DMA_START |
237 SOF_HDA_CL_DMA_SD_INT_MASK, 0x0);
238
239 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset +
240 SOF_HDA_ADSP_REG_CL_SD_STS,
241 SOF_HDA_CL_DMA_SD_INT_MASK);
242
243 hstream->running = false;
244 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
245 1 << hstream->index, 0x0);
246 break;
247 default:
248 dev_err(sdev->dev, "error: unknown command: %d\n", cmd);
249 return -EINVAL;
250 }
251
252 return 0;
253}
254
255/*
256 * prepare for common hdac registers settings, for both code loader
257 * and normal stream.
258 */
259int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
260 struct hdac_ext_stream *stream,
261 struct snd_dma_buffer *dmab,
262 struct snd_pcm_hw_params *params)
263{
264 struct hdac_bus *bus = sof_to_bus(sdev);
265 struct hdac_stream *hstream = &stream->hstream;
266 int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
267 int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT;
268 u32 val, mask;
269
270 if (!stream) {
271 dev_err(sdev->dev, "error: no stream available\n");
272 return -ENODEV;
273 }
274
275 /* decouple host and link DMA */
276 mask = 0x1 << hstream->index;
277 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
278 mask, mask);
279
280 if (!dmab) {
281 dev_err(sdev->dev, "error: no dma buffer allocated!\n");
282 return -ENODEV;
283 }
284
285 /* clear stream status */
286 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
287 SOF_HDA_CL_DMA_SD_INT_MASK |
288 SOF_HDA_SD_CTL_DMA_START, 0);
289 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
290 sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
291 SOF_HDA_CL_DMA_SD_INT_MASK,
292 SOF_HDA_CL_DMA_SD_INT_MASK);
293
294 /* stream reset */
295 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1,
296 0x1);
297 udelay(3);
298 do {
299 val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
300 sd_offset);
301 if (val & 0x1)
302 break;
303 } while (--timeout);
304 if (timeout == 0) {
305 dev_err(sdev->dev, "error: stream reset failed\n");
306 return -ETIMEDOUT;
307 }
308
309 timeout = HDA_DSP_STREAM_RESET_TIMEOUT;
310 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1,
311 0x0);
312
313 /* wait for hardware to report that stream is out of reset */
314 udelay(3);
315 do {
316 val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
317 sd_offset);
318 if ((val & 0x1) == 0)
319 break;
320 } while (--timeout);
321 if (timeout == 0) {
322 dev_err(sdev->dev, "error: timeout waiting for stream reset\n");
323 return -ETIMEDOUT;
324 }
325
326 if (hstream->posbuf)
327 *hstream->posbuf = 0;
328
329 /* reset BDL address */
330 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
331 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
332 0x0);
333 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
334 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
335 0x0);
336
337 /* clear stream status */
338 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
339 SOF_HDA_CL_DMA_SD_INT_MASK |
340 SOF_HDA_SD_CTL_DMA_START, 0);
341 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
342 sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS,
343 SOF_HDA_CL_DMA_SD_INT_MASK,
344 SOF_HDA_CL_DMA_SD_INT_MASK);
345
346 hstream->frags = 0;
347
348 ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream);
349 if (ret < 0) {
350 dev_err(sdev->dev, "error: set up of BDL failed\n");
351 return ret;
352 }
353
354 /* program stream tag to set up stream descriptor for DMA */
355 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
356 SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK,
357 hstream->stream_tag <<
358 SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT);
359
360 /* program cyclic buffer length */
361 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
362 sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL,
363 hstream->bufsize);
364
365 /*
366 * Recommended hardware programming sequence for HDAudio DMA format
367 *
368 * 1. Put DMA into coupled mode by clearing PPCTL.PROCEN bit
369 * for corresponding stream index before the time of writing
370 * format to SDxFMT register.
371 * 2. Write SDxFMT
372 * 3. Set PPCTL.PROCEN bit for corresponding stream index to
373 * enable decoupled mode
374 */
375
376 /* couple host and link DMA, disable DSP features */
377 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
378 mask, 0);
379
380 /* program stream format */
381 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
382 sd_offset +
383 SOF_HDA_ADSP_REG_CL_SD_FORMAT,
384 0xffff, hstream->format_val);
385
386 /* decouple host and link DMA, enable DSP features */
387 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
388 mask, mask);
389
390 /* program last valid index */
391 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
392 sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI,
393 0xffff, (hstream->frags - 1));
394
395 /* program BDL address */
396 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
397 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL,
398 (u32)hstream->bdl.addr);
399 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
400 sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU,
401 upper_32_bits(hstream->bdl.addr));
402
403 /* enable position buffer */
404 if (!(snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE)
405 & SOF_HDA_ADSP_DPLBASE_ENABLE)) {
406 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE,
407 upper_32_bits(bus->posbuf.addr));
408 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE,
409 (u32)bus->posbuf.addr |
410 SOF_HDA_ADSP_DPLBASE_ENABLE);
411 }
412
413 /* set interrupt enable bits */
414 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
415 SOF_HDA_CL_DMA_SD_INT_MASK,
416 SOF_HDA_CL_DMA_SD_INT_MASK);
417
418 /* read FIFO size */
419 if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) {
420 hstream->fifo_size =
421 snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
422 sd_offset +
423 SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE);
424 hstream->fifo_size &= 0xffff;
425 hstream->fifo_size += 1;
426 } else {
427 hstream->fifo_size = 0;
428 }
429
430 return ret;
431}
432
433irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
434{
435 struct hdac_bus *bus = context;
436 struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
437 u32 stream_mask;
438 u32 status;
439
440 if (!pm_runtime_active(bus->dev))
441 return IRQ_NONE;
442
443 spin_lock(&bus->reg_lock);
444
445 status = snd_hdac_chip_readl(bus, INTSTS);
446 stream_mask = GENMASK(sof_hda->stream_max - 1, 0) | AZX_INT_CTRL_EN;
447
448 /* Not stream interrupt or register inaccessible, ignore it.*/
449 if (!(status & stream_mask) || status == 0xffffffff) {
450 spin_unlock(&bus->reg_lock);
451 return IRQ_NONE;
452 }
453
454#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
455 /* clear rirb int */
456 status = snd_hdac_chip_readb(bus, RIRBSTS);
457 if (status & RIRB_INT_MASK) {
458 if (status & RIRB_INT_RESPONSE)
459 snd_hdac_bus_update_rirb(bus);
460 snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
461 }
462#endif
463
464 spin_unlock(&bus->reg_lock);
465
466 return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
467}
468
469irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
470{
471 struct hdac_bus *bus = context;
472 struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
473 u32 status = snd_hdac_chip_readl(bus, INTSTS);
474 struct hdac_stream *s;
475 u32 sd_status;
476
477 /* check streams */
478 list_for_each_entry(s, &bus->stream_list, list) {
479 if (status & (1 << s->index) && s->opened) {
480 sd_status = snd_hdac_stream_readb(s, SD_STS);
481
482 dev_vdbg(bus->dev, "stream %d status 0x%x\n",
483 s->index, sd_status);
484
485 snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK);
486
487 if (!s->substream ||
488 !s->running ||
489 (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0)
490 continue;
491
492 /* Inform ALSA only in case not do that with IPC */
493 if (sof_hda->no_ipc_position)
494 snd_sof_pcm_period_elapsed(s->substream);
495
496 }
497 }
498
499 return IRQ_HANDLED;
500}
501
502int hda_dsp_stream_init(struct snd_sof_dev *sdev)
503{
504 struct hdac_bus *bus = sof_to_bus(sdev);
505 struct hdac_ext_stream *stream;
506 struct hdac_stream *hstream;
507 struct pci_dev *pci = to_pci_dev(sdev->dev);
508 struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
509 int sd_offset;
510 int i, num_playback, num_capture, num_total, ret;
511 u32 gcap;
512
513 gcap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCAP);
514 dev_dbg(sdev->dev, "hda global caps = 0x%x\n", gcap);
515
516 /* get stream count from GCAP */
517 num_capture = (gcap >> 8) & 0x0f;
518 num_playback = (gcap >> 12) & 0x0f;
519 num_total = num_playback + num_capture;
520
521 dev_dbg(sdev->dev, "detected %d playback and %d capture streams\n",
522 num_playback, num_capture);
523
524 if (num_playback >= SOF_HDA_PLAYBACK_STREAMS) {
525 dev_err(sdev->dev, "error: too many playback streams %d\n",
526 num_playback);
527 return -EINVAL;
528 }
529
530 if (num_capture >= SOF_HDA_CAPTURE_STREAMS) {
531 dev_err(sdev->dev, "error: too many capture streams %d\n",
532 num_playback);
533 return -EINVAL;
534 }
535
536 /*
537 * mem alloc for the position buffer
538 * TODO: check position buffer update
539 */
540 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
541 SOF_HDA_DPIB_ENTRY_SIZE * num_total,
542 &bus->posbuf);
543 if (ret < 0) {
544 dev_err(sdev->dev, "error: posbuffer dma alloc failed\n");
545 return -ENOMEM;
546 }
547
548#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
549 /* mem alloc for the CORB/RIRB ringbuffers */
550 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
551 PAGE_SIZE, &bus->rb);
552 if (ret < 0) {
553 dev_err(sdev->dev, "error: RB alloc failed\n");
554 return -ENOMEM;
555 }
556#endif
557
558 /* create capture streams */
559 for (i = 0; i < num_capture; i++) {
560 struct sof_intel_hda_stream *hda_stream;
561
562 hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
563 GFP_KERNEL);
564 if (!hda_stream)
565 return -ENOMEM;
566
567 stream = &hda_stream->hda_stream;
568
569 stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
570 SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
571
572 stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
573 SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
574 SOF_HDA_PPLC_INTERVAL * i;
575
576 /* do we support SPIB */
577 if (sdev->bar[HDA_DSP_SPIB_BAR]) {
578 stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
579 SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
580 SOF_HDA_SPIB_SPIB;
581
582 stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
583 SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
584 SOF_HDA_SPIB_MAXFIFO;
585 }
586
587 hstream = &stream->hstream;
588 hstream->bus = bus;
589 hstream->sd_int_sta_mask = 1 << i;
590 hstream->index = i;
591 sd_offset = SOF_STREAM_SD_OFFSET(hstream);
592 hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
593 hstream->stream_tag = i + 1;
594 hstream->opened = false;
595 hstream->running = false;
596 hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
597
598 /* memory alloc for stream BDL */
599 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
600 HDA_DSP_BDL_SIZE, &hstream->bdl);
601 if (ret < 0) {
602 dev_err(sdev->dev, "error: stream bdl dma alloc failed\n");
603 return -ENOMEM;
604 }
605 hstream->posbuf = (__le32 *)(bus->posbuf.area +
606 (hstream->index) * 8);
607
608 list_add_tail(&hstream->list, &bus->stream_list);
609 }
610
611 /* create playback streams */
612 for (i = num_capture; i < num_total; i++) {
613 struct sof_intel_hda_stream *hda_stream;
614
615 hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
616 GFP_KERNEL);
617 if (!hda_stream)
618 return -ENOMEM;
619
620 stream = &hda_stream->hda_stream;
621
622 /* we always have DSP support */
623 stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
624 SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
625
626 stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
627 SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
628 SOF_HDA_PPLC_INTERVAL * i;
629
630 /* do we support SPIB */
631 if (sdev->bar[HDA_DSP_SPIB_BAR]) {
632 stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
633 SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
634 SOF_HDA_SPIB_SPIB;
635
636 stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
637 SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
638 SOF_HDA_SPIB_MAXFIFO;
639 }
640
641 hstream = &stream->hstream;
642 hstream->bus = bus;
643 hstream->sd_int_sta_mask = 1 << i;
644 hstream->index = i;
645 sd_offset = SOF_STREAM_SD_OFFSET(hstream);
646 hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
647 hstream->stream_tag = i - num_capture + 1;
648 hstream->opened = false;
649 hstream->running = false;
650 hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
651
652 /* mem alloc for stream BDL */
653 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
654 HDA_DSP_BDL_SIZE, &hstream->bdl);
655 if (ret < 0) {
656 dev_err(sdev->dev, "error: stream bdl dma alloc failed\n");
657 return -ENOMEM;
658 }
659
660 hstream->posbuf = (__le32 *)(bus->posbuf.area +
661 (hstream->index) * 8);
662
663 list_add_tail(&hstream->list, &bus->stream_list);
664 }
665
666 /* store total stream count (playback + capture) from GCAP */
667 sof_hda->stream_max = num_total;
668
669 return 0;
670}
671
672void hda_dsp_stream_free(struct snd_sof_dev *sdev)
673{
674 struct hdac_bus *bus = sof_to_bus(sdev);
675 struct hdac_stream *s, *_s;
676 struct hdac_ext_stream *stream;
677 struct sof_intel_hda_stream *hda_stream;
678
679 /* free position buffer */
680 if (bus->posbuf.area)
681 snd_dma_free_pages(&bus->posbuf);
682
683#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
684 /* free position buffer */
685 if (bus->rb.area)
686 snd_dma_free_pages(&bus->rb);
687#endif
688
689 list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
690 /* TODO: decouple */
691
692 /* free bdl buffer */
693 if (s->bdl.area)
694 snd_dma_free_pages(&s->bdl);
695 list_del(&s->list);
696 stream = stream_to_hdac_ext_stream(s);
697 hda_stream = container_of(stream, struct sof_intel_hda_stream,
698 hda_stream);
699 devm_kfree(sdev->dev, hda_stream);
700 }
701}
diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c
new file mode 100644
index 000000000000..33b23bd6a01e
--- /dev/null
+++ b/sound/soc/sof/intel/hda-trace.c
@@ -0,0 +1,94 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include <sound/hdaudio_ext.h>
19#include "../ops.h"
20#include "hda.h"
21
22static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev)
23{
24 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
25 struct hdac_ext_stream *stream = hda->dtrace_stream;
26 struct hdac_stream *hstream = &stream->hstream;
27 struct snd_dma_buffer *dmab = &sdev->dmatb;
28 int ret;
29
30 hstream->period_bytes = 0;/* initialize period_bytes */
31 hstream->bufsize = sdev->dmatb.bytes;
32
33 ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
34 if (ret < 0)
35 dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
36
37 return ret;
38}
39
40int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
41{
42 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
43 int ret;
44
45 hda->dtrace_stream = hda_dsp_stream_get(sdev,
46 SNDRV_PCM_STREAM_CAPTURE);
47
48 if (!hda->dtrace_stream) {
49 dev_err(sdev->dev,
50 "error: no available capture stream for DMA trace\n");
51 return -ENODEV;
52 }
53
54 *stream_tag = hda->dtrace_stream->hstream.stream_tag;
55
56 /*
57 * initialize capture stream, set BDL address and return corresponding
58 * stream tag which will be sent to the firmware by IPC message.
59 */
60 ret = hda_dsp_trace_prepare(sdev);
61 if (ret < 0) {
62 dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret);
63 hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag);
64 hda->dtrace_stream = NULL;
65 *stream_tag = 0;
66 }
67
68 return ret;
69}
70
71int hda_dsp_trace_release(struct snd_sof_dev *sdev)
72{
73 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
74 struct hdac_stream *hstream;
75
76 if (hda->dtrace_stream) {
77 hstream = &hda->dtrace_stream->hstream;
78 hda_dsp_stream_put(sdev,
79 SNDRV_PCM_STREAM_CAPTURE,
80 hstream->stream_tag);
81 hda->dtrace_stream = NULL;
82 return 0;
83 }
84
85 dev_dbg(sdev->dev, "DMA trace stream is not opened!\n");
86 return -ENODEV;
87}
88
89int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd)
90{
91 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
92
93 return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd);
94}
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
new file mode 100644
index 000000000000..7e3980a2f7ba
--- /dev/null
+++ b/sound/soc/sof/intel/hda.c
@@ -0,0 +1,689 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
18#include <linux/module.h>
19#include <sound/hdaudio_ext.h>
20#include <sound/sof.h>
21#include <sound/sof/xtensa.h>
22#include "../ops.h"
23#include "hda.h"
24#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
25#include "../../codecs/hdac_hda.h"
26#endif
27
28#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
29#include <sound/soc-acpi-intel-match.h>
30#endif
31
32/* platform specific devices */
33#include "shim.h"
34
35/*
36 * Debug
37 */
38
39struct hda_dsp_msg_code {
40 u32 code;
41 const char *msg;
42};
43
44static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
45 {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"},
46 {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"},
47 {HDA_DSP_ROM_FW_ENTERED, "status: fw entered"},
48 {HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
49 {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
50 {HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"},
51 {HDA_DSP_ROM_BASE_FW_NOT_FOUND, "error: base fw not found"},
52 {HDA_DSP_ROM_CSE_VALIDATION_FAILED, "error: signature verification failed"},
53 {HDA_DSP_ROM_IPC_FATAL_ERROR, "error: ipc fatal error"},
54 {HDA_DSP_ROM_L2_CACHE_ERROR, "error: L2 cache error"},
55 {HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL, "error: load offset too small"},
56 {HDA_DSP_ROM_API_PTR_INVALID, "error: API ptr invalid"},
57 {HDA_DSP_ROM_BASEFW_INCOMPAT, "error: base fw incompatible"},
58 {HDA_DSP_ROM_UNHANDLED_INTERRUPT, "error: unhandled interrupt"},
59 {HDA_DSP_ROM_MEMORY_HOLE_ECC, "error: ECC memory hole"},
60 {HDA_DSP_ROM_KERNEL_EXCEPTION, "error: kernel exception"},
61 {HDA_DSP_ROM_USER_EXCEPTION, "error: user exception"},
62 {HDA_DSP_ROM_UNEXPECTED_RESET, "error: unexpected reset"},
63 {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"},
64};
65
66static void hda_dsp_get_status_skl(struct snd_sof_dev *sdev)
67{
68 u32 status;
69 int i;
70
71 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
72 HDA_ADSP_FW_STATUS_SKL);
73
74 for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
75 if (status == hda_dsp_rom_msg[i].code) {
76 dev_err(sdev->dev, "%s - code %8.8x\n",
77 hda_dsp_rom_msg[i].msg, status);
78 return;
79 }
80 }
81
82 /* not for us, must be generic sof message */
83 dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
84}
85
86static void hda_dsp_get_status(struct snd_sof_dev *sdev)
87{
88 u32 status;
89 int i;
90
91 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
92 HDA_DSP_SRAM_REG_ROM_STATUS);
93
94 for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
95 if (status == hda_dsp_rom_msg[i].code) {
96 dev_err(sdev->dev, "%s - code %8.8x\n",
97 hda_dsp_rom_msg[i].msg, status);
98 return;
99 }
100 }
101
102 /* not for us, must be generic sof message */
103 dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
104}
105
106static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
107 struct sof_ipc_dsp_oops_xtensa *xoops,
108 struct sof_ipc_panic_info *panic_info,
109 u32 *stack, size_t stack_words)
110{
111 /* first read registers */
112 sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops,
113 sizeof(*xoops));
114
115 /* then get panic info */
116 sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset +
117 sizeof(*xoops), panic_info, sizeof(*panic_info));
118
119 /* then get the stack */
120 sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset +
121 sizeof(*xoops) + sizeof(*panic_info), stack,
122 stack_words * sizeof(u32));
123}
124
125void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
126{
127 struct sof_ipc_dsp_oops_xtensa xoops;
128 struct sof_ipc_panic_info panic_info;
129 u32 stack[HDA_DSP_STACK_DUMP_SIZE];
130 u32 status, panic;
131
132 /* try APL specific status message types first */
133 hda_dsp_get_status_skl(sdev);
134
135 /* now try generic SOF status messages */
136 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
137 HDA_ADSP_ERROR_CODE_SKL);
138
139 /*TODO: Check: there is no define in spec, but it is used in the code*/
140 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
141 HDA_ADSP_ERROR_CODE_SKL + 0x4);
142
143 if (sdev->boot_complete) {
144 hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
145 HDA_DSP_STACK_DUMP_SIZE);
146 snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
147 stack, HDA_DSP_STACK_DUMP_SIZE);
148 } else {
149 dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n",
150 status, panic);
151 hda_dsp_get_status_skl(sdev);
152 }
153}
154
155void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
156{
157 struct sof_ipc_dsp_oops_xtensa xoops;
158 struct sof_ipc_panic_info panic_info;
159 u32 stack[HDA_DSP_STACK_DUMP_SIZE];
160 u32 status, panic;
161
162 /* try APL specific status message types first */
163 hda_dsp_get_status(sdev);
164
165 /* now try generic SOF status messages */
166 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
167 HDA_DSP_SRAM_REG_FW_STATUS);
168 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP);
169
170 if (sdev->boot_complete) {
171 hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
172 HDA_DSP_STACK_DUMP_SIZE);
173 snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
174 stack, HDA_DSP_STACK_DUMP_SIZE);
175 } else {
176 dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n",
177 status, panic);
178 hda_dsp_get_status(sdev);
179 }
180}
181
182void hda_ipc_dump(struct snd_sof_dev *sdev)
183{
184 u32 hipcie;
185 u32 hipct;
186 u32 hipcctl;
187
188 /* read IPC status */
189 hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
190 hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
191 hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
192
193 /* dump the IPC regs */
194 /* TODO: parse the raw msg */
195 dev_err(sdev->dev,
196 "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
197 hipcie, hipct, hipcctl);
198}
199
200static int hda_init(struct snd_sof_dev *sdev)
201{
202 struct hda_bus *hbus;
203 struct hdac_bus *bus;
204 struct hdac_ext_bus_ops *ext_ops = NULL;
205 struct pci_dev *pci = to_pci_dev(sdev->dev);
206 int ret;
207
208 hbus = sof_to_hbus(sdev);
209 bus = sof_to_bus(sdev);
210
211 /* HDA bus init */
212#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
213 ext_ops = snd_soc_hdac_hda_get_ops();
214#endif
215 sof_hda_bus_init(bus, &pci->dev, ext_ops);
216 bus->use_posbuf = 1;
217 bus->bdl_pos_adj = 0;
218
219 mutex_init(&hbus->prepare_mutex);
220 hbus->pci = pci;
221 hbus->mixer_assigned = -1;
222 hbus->modelname = "sofbus";
223
224 /* initialise hdac bus */
225 bus->addr = pci_resource_start(pci, 0);
226 bus->remap_addr = pci_ioremap_bar(pci, 0);
227 if (!bus->remap_addr) {
228 dev_err(bus->dev, "error: ioremap error\n");
229 return -ENXIO;
230 }
231
232 /* HDA base */
233 sdev->bar[HDA_DSP_HDA_BAR] = bus->remap_addr;
234
235 /* get controller capabilities */
236 ret = hda_dsp_ctrl_get_caps(sdev);
237 if (ret < 0)
238 dev_err(sdev->dev, "error: get caps error\n");
239
240 return ret;
241}
242
243#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
244
245static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
246 const char *sof_tplg_filename)
247{
248 const char *tplg_filename = NULL;
249 char *filename;
250 char *split_ext;
251
252 filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
253 if (!filename)
254 return NULL;
255
256 /* this assumes a .tplg extension */
257 split_ext = strsep(&filename, ".");
258 if (split_ext) {
259 tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
260 "%s-idisp.tplg", split_ext);
261 if (!tplg_filename)
262 return NULL;
263 }
264 return tplg_filename;
265}
266
267static int hda_init_caps(struct snd_sof_dev *sdev)
268{
269 struct hdac_bus *bus = sof_to_bus(sdev);
270 struct hdac_ext_link *hlink;
271 struct snd_soc_acpi_mach_params *mach_params;
272 struct snd_soc_acpi_mach *hda_mach;
273 struct snd_sof_pdata *pdata = sdev->pdata;
274 struct snd_soc_acpi_mach *mach;
275 const char *tplg_filename;
276 int codec_num = 0;
277 int ret = 0;
278 int i;
279
280 device_disable_async_suspend(bus->dev);
281
282 /* check if dsp is there */
283 if (bus->ppcap)
284 dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
285
286 if (bus->mlcap)
287 snd_hdac_ext_bus_get_ml_capabilities(bus);
288
289 /* init i915 and HDMI codecs */
290 ret = hda_codec_i915_init(sdev);
291 if (ret < 0) {
292 dev_err(sdev->dev, "error: no HDMI audio devices found\n");
293 return ret;
294 }
295
296 ret = hda_dsp_ctrl_init_chip(sdev, true);
297 if (ret < 0) {
298 dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret);
299 goto out;
300 }
301
302 /* codec detection */
303 if (!bus->codec_mask) {
304 dev_info(bus->dev, "no hda codecs found!\n");
305 } else {
306 dev_info(bus->dev, "hda codecs found, mask %lx\n",
307 bus->codec_mask);
308
309 for (i = 0; i < HDA_MAX_CODECS; i++) {
310 if (bus->codec_mask & (1 << i))
311 codec_num++;
312 }
313
314 /*
315 * If no machine driver is found, then:
316 *
317 * hda machine driver is used if :
318 * 1. there is one HDMI codec and one external HDAudio codec
319 * 2. only HDMI codec
320 */
321 if (!pdata->machine && codec_num <= 2 &&
322 HDA_IDISP_CODEC(bus->codec_mask)) {
323 hda_mach = snd_soc_acpi_intel_hda_machines;
324 pdata->machine = hda_mach;
325
326 /* topology: use the info from hda_machines */
327 pdata->tplg_filename =
328 hda_mach->sof_tplg_filename;
329
330 /* firmware: pick the first in machine list */
331 mach = pdata->desc->machines;
332 pdata->fw_filename = mach->sof_fw_filename;
333
334 dev_info(bus->dev, "using HDA machine driver %s now\n",
335 hda_mach->drv_name);
336
337 /* fixup topology file for HDMI only platforms */
338 if (codec_num == 1) {
339 /* use local variable for readability */
340 tplg_filename = pdata->tplg_filename;
341 tplg_filename = fixup_tplg_name(sdev, tplg_filename);
342 if (!tplg_filename)
343 goto out;
344 pdata->tplg_filename = tplg_filename;
345 }
346 }
347 }
348
349 /* used by hda machine driver to create dai links */
350 if (pdata->machine) {
351 mach_params = (struct snd_soc_acpi_mach_params *)
352 &pdata->machine->mach_params;
353 mach_params->codec_mask = bus->codec_mask;
354 mach_params->platform = dev_name(sdev->dev);
355 }
356
357 /* create codec instances */
358 hda_codec_probe_bus(sdev);
359
360 hda_codec_i915_put(sdev);
361
362 /*
363 * we are done probing so decrement link counts
364 */
365 list_for_each_entry(hlink, &bus->hlink_list, list)
366 snd_hdac_ext_bus_link_put(bus, hlink);
367
368 return 0;
369
370out:
371 hda_codec_i915_exit(sdev);
372 return ret;
373}
374
375#else
376
377static int hda_init_caps(struct snd_sof_dev *sdev)
378{
379 /*
380 * set CGCTL.MISCBDCGE to 0 during reset and set back to 1
381 * when reset finished.
382 * TODO: maybe no need for init_caps?
383 */
384 hda_dsp_ctrl_misc_clock_gating(sdev, 0);
385
386 /* clear WAKESTS */
387 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
388 SOF_HDA_WAKESTS_INT_MASK,
389 SOF_HDA_WAKESTS_INT_MASK);
390
391 return 0;
392}
393
394#endif
395
396static const struct sof_intel_dsp_desc
397 *get_chip_info(struct snd_sof_pdata *pdata)
398{
399 const struct sof_dev_desc *desc = pdata->desc;
400 const struct sof_intel_dsp_desc *chip_info;
401
402 chip_info = desc->chip_info;
403
404 return chip_info;
405}
406
407int hda_dsp_probe(struct snd_sof_dev *sdev)
408{
409 struct pci_dev *pci = to_pci_dev(sdev->dev);
410 struct sof_intel_hda_dev *hdev;
411 struct hdac_bus *bus;
412 struct hdac_stream *stream;
413 const struct sof_intel_dsp_desc *chip;
414 int sd_offset, ret = 0;
415
416 /*
417 * detect DSP by checking class/subclass/prog-id information
418 * class=04 subclass 03 prog-if 00: no DSP, legacy driver is required
419 * class=04 subclass 01 prog-if 00: DSP is present
420 * (and may be required e.g. for DMIC or SSP support)
421 * class=04 subclass 03 prog-if 80: either of DSP or legacy mode works
422 */
423 if (pci->class == 0x040300) {
424 dev_err(sdev->dev, "error: the DSP is not enabled on this platform, aborting probe\n");
425 return -ENODEV;
426 } else if (pci->class != 0x040100 && pci->class != 0x040380) {
427 dev_err(sdev->dev, "error: unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class);
428 return -ENODEV;
429 }
430 dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class);
431
432 chip = get_chip_info(sdev->pdata);
433 if (!chip) {
434 dev_err(sdev->dev, "error: no such device supported, chip id:%x\n",
435 pci->device);
436 ret = -EIO;
437 goto err;
438 }
439
440 hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
441 if (!hdev)
442 return -ENOMEM;
443 sdev->pdata->hw_pdata = hdev;
444 hdev->desc = chip;
445
446 hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
447 PLATFORM_DEVID_NONE,
448 NULL, 0);
449 if (IS_ERR(hdev->dmic_dev)) {
450 dev_err(sdev->dev, "error: failed to create DMIC device\n");
451 return PTR_ERR(hdev->dmic_dev);
452 }
453
454 /*
455 * use position update IPC if either it is forced
456 * or we don't have other choice
457 */
458#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION)
459 hdev->no_ipc_position = 0;
460#else
461 hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0;
462#endif
463
464 /* set up HDA base */
465 bus = sof_to_bus(sdev);
466 ret = hda_init(sdev);
467 if (ret < 0)
468 goto hdac_bus_unmap;
469
470 /* DSP base */
471 sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR);
472 if (!sdev->bar[HDA_DSP_BAR]) {
473 dev_err(sdev->dev, "error: ioremap error\n");
474 ret = -ENXIO;
475 goto hdac_bus_unmap;
476 }
477
478 sdev->mmio_bar = HDA_DSP_BAR;
479 sdev->mailbox_bar = HDA_DSP_BAR;
480
481 /* allow 64bit DMA address if supported by H/W */
482 if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) {
483 dev_dbg(sdev->dev, "DMA mask is 64 bit\n");
484 dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64));
485 } else {
486 dev_dbg(sdev->dev, "DMA mask is 32 bit\n");
487 dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
488 dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
489 }
490
491 /* init streams */
492 ret = hda_dsp_stream_init(sdev);
493 if (ret < 0) {
494 dev_err(sdev->dev, "error: failed to init streams\n");
495 /*
496 * not all errors are due to memory issues, but trying
497 * to free everything does not harm
498 */
499 goto free_streams;
500 }
501
502 /*
503 * register our IRQ
504 * let's try to enable msi firstly
505 * if it fails, use legacy interrupt mode
506 * TODO: support interrupt mode selection with kernel parameter
507 * support msi multiple vectors
508 */
509 ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI);
510 if (ret < 0) {
511 dev_info(sdev->dev, "use legacy interrupt mode\n");
512 /*
513 * in IO-APIC mode, hda->irq and ipc_irq are using the same
514 * irq number of pci->irq
515 */
516 hdev->irq = pci->irq;
517 sdev->ipc_irq = pci->irq;
518 sdev->msi_enabled = 0;
519 } else {
520 dev_info(sdev->dev, "use msi interrupt mode\n");
521 hdev->irq = pci_irq_vector(pci, 0);
522 /* ipc irq number is the same of hda irq */
523 sdev->ipc_irq = hdev->irq;
524 sdev->msi_enabled = 1;
525 }
526
527 dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq);
528 ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt,
529 hda_dsp_stream_threaded_handler,
530 IRQF_SHARED, "AudioHDA", bus);
531 if (ret < 0) {
532 dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n",
533 hdev->irq);
534 goto free_irq_vector;
535 }
536
537 dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq);
538 ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler,
539 sof_ops(sdev)->irq_thread, IRQF_SHARED,
540 "AudioDSP", sdev);
541 if (ret < 0) {
542 dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n",
543 sdev->ipc_irq);
544 goto free_hda_irq;
545 }
546
547 pci_set_master(pci);
548 synchronize_irq(pci->irq);
549
550 /*
551 * clear TCSEL to clear playback on some HD Audio
552 * codecs. PCI TCSEL is defined in the Intel manuals.
553 */
554 snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
555
556 /* init HDA capabilities */
557 ret = hda_init_caps(sdev);
558 if (ret < 0)
559 goto free_ipc_irq;
560
561 /* reset HDA controller */
562 ret = hda_dsp_ctrl_link_reset(sdev, true);
563 if (ret < 0) {
564 dev_err(sdev->dev, "error: failed to reset HDA controller\n");
565 goto free_ipc_irq;
566 }
567
568 /* exit HDA controller reset */
569 ret = hda_dsp_ctrl_link_reset(sdev, false);
570 if (ret < 0) {
571 dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
572 goto free_ipc_irq;
573 }
574
575 /* clear stream status */
576 list_for_each_entry(stream, &bus->stream_list, list) {
577 sd_offset = SOF_STREAM_SD_OFFSET(stream);
578 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
579 sd_offset +
580 SOF_HDA_ADSP_REG_CL_SD_STS,
581 SOF_HDA_CL_DMA_SD_INT_MASK,
582 SOF_HDA_CL_DMA_SD_INT_MASK);
583 }
584
585 /* clear WAKESTS */
586 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
587 SOF_HDA_WAKESTS_INT_MASK,
588 SOF_HDA_WAKESTS_INT_MASK);
589
590 /* clear interrupt status register */
591 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
592 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
593
594 /* enable CIE and GIE interrupts */
595 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
596 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
597 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
598
599 /* re-enable CGCTL.MISCBDCGE after reset */
600 hda_dsp_ctrl_misc_clock_gating(sdev, true);
601
602 device_disable_async_suspend(&pci->dev);
603
604 /* enable DSP features */
605 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
606 SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN);
607
608 /* enable DSP IRQ */
609 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
610 SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE);
611
612 /* initialize waitq for code loading */
613 init_waitqueue_head(&sdev->waitq);
614
615 /* set default mailbox offset for FW ready message */
616 sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET;
617
618 return 0;
619
620free_ipc_irq:
621 free_irq(sdev->ipc_irq, sdev);
622free_hda_irq:
623 free_irq(hdev->irq, bus);
624free_irq_vector:
625 if (sdev->msi_enabled)
626 pci_free_irq_vectors(pci);
627free_streams:
628 hda_dsp_stream_free(sdev);
629/* dsp_unmap: not currently used */
630 iounmap(sdev->bar[HDA_DSP_BAR]);
631hdac_bus_unmap:
632 iounmap(bus->remap_addr);
633err:
634 return ret;
635}
636
637int hda_dsp_remove(struct snd_sof_dev *sdev)
638{
639 struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
640 struct hdac_bus *bus = sof_to_bus(sdev);
641 struct pci_dev *pci = to_pci_dev(sdev->dev);
642 const struct sof_intel_dsp_desc *chip = hda->desc;
643
644#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
645 /* codec removal, invoke bus_device_remove */
646 snd_hdac_ext_bus_device_remove(bus);
647#endif
648
649 if (!IS_ERR_OR_NULL(hda->dmic_dev))
650 platform_device_unregister(hda->dmic_dev);
651
652 /* disable DSP IRQ */
653 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
654 SOF_HDA_PPCTL_PIE, 0);
655
656 /* disable CIE and GIE interrupts */
657 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
658 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0);
659
660 /* disable cores */
661 if (chip)
662 hda_dsp_core_reset_power_down(sdev, chip->cores_mask);
663
664 /* disable DSP */
665 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
666 SOF_HDA_PPCTL_GPROCEN, 0);
667
668 free_irq(sdev->ipc_irq, sdev);
669 free_irq(hda->irq, bus);
670 if (sdev->msi_enabled)
671 pci_free_irq_vectors(pci);
672
673 hda_dsp_stream_free(sdev);
674#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
675 snd_hdac_link_free_all(bus);
676#endif
677
678 iounmap(sdev->bar[HDA_DSP_BAR]);
679 iounmap(bus->remap_addr);
680
681#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
682 snd_hdac_ext_bus_exit(bus);
683#endif
684 hda_codec_i915_exit(sdev);
685
686 return 0;
687}
688
689MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
new file mode 100644
index 000000000000..92d45c43b4b1
--- /dev/null
+++ b/sound/soc/sof/intel/hda.h
@@ -0,0 +1,583 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2017 Intel Corporation. All rights reserved.
7 *
8 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 */
10
11#ifndef __SOF_INTEL_HDA_H
12#define __SOF_INTEL_HDA_H
13
14#include <sound/hda_codec.h>
15#include <sound/hdaudio_ext.h>
16#include "shim.h"
17
18/* PCI registers */
19#define PCI_TCSEL 0x44
20#define PCI_PGCTL PCI_TCSEL
21#define PCI_CGCTL 0x48
22
23/* PCI_PGCTL bits */
24#define PCI_PGCTL_ADSPPGD BIT(2)
25#define PCI_PGCTL_LSRMD_MASK BIT(4)
26
27/* PCI_CGCTL bits */
28#define PCI_CGCTL_MISCBDCGE_MASK BIT(6)
29#define PCI_CGCTL_ADSPDCGE BIT(1)
30
31/* Legacy HDA registers and bits used - widths are variable */
32#define SOF_HDA_GCAP 0x0
33#define SOF_HDA_GCTL 0x8
34/* accept unsol. response enable */
35#define SOF_HDA_GCTL_UNSOL BIT(8)
36#define SOF_HDA_LLCH 0x14
37#define SOF_HDA_INTCTL 0x20
38#define SOF_HDA_INTSTS 0x24
39#define SOF_HDA_WAKESTS 0x0E
40#define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1)
41#define SOF_HDA_RIRBSTS 0x5d
42#define SOF_HDA_VS_EM2_L1SEN BIT(13)
43
44/* SOF_HDA_GCTL register bist */
45#define SOF_HDA_GCTL_RESET BIT(0)
46
47/* SOF_HDA_INCTL and SOF_HDA_INTSTS regs */
48#define SOF_HDA_INT_GLOBAL_EN BIT(31)
49#define SOF_HDA_INT_CTRL_EN BIT(30)
50#define SOF_HDA_INT_ALL_STREAM 0xff
51
52#define SOF_HDA_MAX_CAPS 10
53#define SOF_HDA_CAP_ID_OFF 16
54#define SOF_HDA_CAP_ID_MASK GENMASK(SOF_HDA_CAP_ID_OFF + 11,\
55 SOF_HDA_CAP_ID_OFF)
56#define SOF_HDA_CAP_NEXT_MASK 0xFFFF
57
58#define SOF_HDA_GTS_CAP_ID 0x1
59#define SOF_HDA_ML_CAP_ID 0x2
60
61#define SOF_HDA_PP_CAP_ID 0x3
62#define SOF_HDA_REG_PP_PPCH 0x10
63#define SOF_HDA_REG_PP_PPCTL 0x04
64#define SOF_HDA_PPCTL_PIE BIT(31)
65#define SOF_HDA_PPCTL_GPROCEN BIT(30)
66
67/* DPIB entry size: 8 Bytes = 2 DWords */
68#define SOF_HDA_DPIB_ENTRY_SIZE 0x8
69
70#define SOF_HDA_SPIB_CAP_ID 0x4
71#define SOF_HDA_DRSM_CAP_ID 0x5
72
73#define SOF_HDA_SPIB_BASE 0x08
74#define SOF_HDA_SPIB_INTERVAL 0x08
75#define SOF_HDA_SPIB_SPIB 0x00
76#define SOF_HDA_SPIB_MAXFIFO 0x04
77
78#define SOF_HDA_PPHC_BASE 0x10
79#define SOF_HDA_PPHC_INTERVAL 0x10
80
81#define SOF_HDA_PPLC_BASE 0x10
82#define SOF_HDA_PPLC_MULTI 0x10
83#define SOF_HDA_PPLC_INTERVAL 0x10
84
85#define SOF_HDA_DRSM_BASE 0x08
86#define SOF_HDA_DRSM_INTERVAL 0x08
87
88/* Descriptor error interrupt */
89#define SOF_HDA_CL_DMA_SD_INT_DESC_ERR 0x10
90
91/* FIFO error interrupt */
92#define SOF_HDA_CL_DMA_SD_INT_FIFO_ERR 0x08
93
94/* Buffer completion interrupt */
95#define SOF_HDA_CL_DMA_SD_INT_COMPLETE 0x04
96
97#define SOF_HDA_CL_DMA_SD_INT_MASK \
98 (SOF_HDA_CL_DMA_SD_INT_DESC_ERR | \
99 SOF_HDA_CL_DMA_SD_INT_FIFO_ERR | \
100 SOF_HDA_CL_DMA_SD_INT_COMPLETE)
101#define SOF_HDA_SD_CTL_DMA_START 0x02 /* Stream DMA start bit */
102
103/* Intel HD Audio Code Loader DMA Registers */
104#define SOF_HDA_ADSP_LOADER_BASE 0x80
105#define SOF_HDA_ADSP_DPLBASE 0x70
106#define SOF_HDA_ADSP_DPUBASE 0x74
107#define SOF_HDA_ADSP_DPLBASE_ENABLE 0x01
108
109/* Stream Registers */
110#define SOF_HDA_ADSP_REG_CL_SD_CTL 0x00
111#define SOF_HDA_ADSP_REG_CL_SD_STS 0x03
112#define SOF_HDA_ADSP_REG_CL_SD_LPIB 0x04
113#define SOF_HDA_ADSP_REG_CL_SD_CBL 0x08
114#define SOF_HDA_ADSP_REG_CL_SD_LVI 0x0C
115#define SOF_HDA_ADSP_REG_CL_SD_FIFOW 0x0E
116#define SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE 0x10
117#define SOF_HDA_ADSP_REG_CL_SD_FORMAT 0x12
118#define SOF_HDA_ADSP_REG_CL_SD_FIFOL 0x14
119#define SOF_HDA_ADSP_REG_CL_SD_BDLPL 0x18
120#define SOF_HDA_ADSP_REG_CL_SD_BDLPU 0x1C
121#define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20
122
123/* CL: Software Position Based FIFO Capability Registers */
124#define SOF_DSP_REG_CL_SPBFIFO \
125 (SOF_HDA_ADSP_LOADER_BASE + 0x20)
126#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCH 0x0
127#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL 0x4
128#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB 0x8
129#define SOF_HDA_ADSP_REG_CL_SPBFIFO_MAXFIFOS 0xc
130
131/* Stream Number */
132#define SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT 20
133#define SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK \
134 GENMASK(SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT + 3,\
135 SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT)
136
137#define HDA_DSP_HDA_BAR 0
138#define HDA_DSP_PP_BAR 1
139#define HDA_DSP_SPIB_BAR 2
140#define HDA_DSP_DRSM_BAR 3
141#define HDA_DSP_BAR 4
142
143#define SRAM_WINDOW_OFFSET(x) (0x80000 + (x) * 0x20000)
144
145#define HDA_DSP_MBOX_OFFSET SRAM_WINDOW_OFFSET(0)
146
147#define HDA_DSP_PANIC_OFFSET(x) \
148 (((x) & 0xFFFFFF) + HDA_DSP_MBOX_OFFSET)
149
150/* SRAM window 0 FW "registers" */
151#define HDA_DSP_SRAM_REG_ROM_STATUS (HDA_DSP_MBOX_OFFSET + 0x0)
152#define HDA_DSP_SRAM_REG_ROM_ERROR (HDA_DSP_MBOX_OFFSET + 0x4)
153/* FW and ROM share offset 4 */
154#define HDA_DSP_SRAM_REG_FW_STATUS (HDA_DSP_MBOX_OFFSET + 0x4)
155#define HDA_DSP_SRAM_REG_FW_TRACEP (HDA_DSP_MBOX_OFFSET + 0x8)
156#define HDA_DSP_SRAM_REG_FW_END (HDA_DSP_MBOX_OFFSET + 0xc)
157
158#define HDA_DSP_MBOX_UPLINK_OFFSET 0x81000
159
160#define HDA_DSP_STREAM_RESET_TIMEOUT 300
161#define HDA_DSP_CL_TRIGGER_TIMEOUT 300
162
163#define HDA_DSP_SPIB_ENABLE 1
164#define HDA_DSP_SPIB_DISABLE 0
165
166#define SOF_HDA_MAX_BUFFER_SIZE (32 * PAGE_SIZE)
167
168#define HDA_DSP_STACK_DUMP_SIZE 32
169
170/* ROM status/error values */
171#define HDA_DSP_ROM_STS_MASK 0xf
172#define HDA_DSP_ROM_INIT 0x1
173#define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3
174#define HDA_DSP_ROM_FW_FW_LOADED 0x4
175#define HDA_DSP_ROM_FW_ENTERED 0x5
176#define HDA_DSP_ROM_RFW_START 0xf
177#define HDA_DSP_ROM_CSE_ERROR 40
178#define HDA_DSP_ROM_CSE_WRONG_RESPONSE 41
179#define HDA_DSP_ROM_IMR_TO_SMALL 42
180#define HDA_DSP_ROM_BASE_FW_NOT_FOUND 43
181#define HDA_DSP_ROM_CSE_VALIDATION_FAILED 44
182#define HDA_DSP_ROM_IPC_FATAL_ERROR 45
183#define HDA_DSP_ROM_L2_CACHE_ERROR 46
184#define HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL 47
185#define HDA_DSP_ROM_API_PTR_INVALID 50
186#define HDA_DSP_ROM_BASEFW_INCOMPAT 51
187#define HDA_DSP_ROM_UNHANDLED_INTERRUPT 0xBEE00000
188#define HDA_DSP_ROM_MEMORY_HOLE_ECC 0xECC00000
189#define HDA_DSP_ROM_KERNEL_EXCEPTION 0xCAFE0000
190#define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000
191#define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000
192#define HDA_DSP_ROM_NULL_FW_ENTRY 0x4c4c4e55
193#define HDA_DSP_IPC_PURGE_FW 0x01004000
194
195/* various timeout values */
196#define HDA_DSP_PU_TIMEOUT 50
197#define HDA_DSP_PD_TIMEOUT 50
198#define HDA_DSP_RESET_TIMEOUT_US 50000
199#define HDA_DSP_BASEFW_TIMEOUT_US 3000000
200#define HDA_DSP_INIT_TIMEOUT_US 500000
201#define HDA_DSP_CTRL_RESET_TIMEOUT 100
202#define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */
203#define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */
204
205#define HDA_DSP_ADSPIC_IPC 1
206#define HDA_DSP_ADSPIS_IPC 1
207
208/* Intel HD Audio General DSP Registers */
209#define HDA_DSP_GEN_BASE 0x0
210#define HDA_DSP_REG_ADSPCS (HDA_DSP_GEN_BASE + 0x04)
211#define HDA_DSP_REG_ADSPIC (HDA_DSP_GEN_BASE + 0x08)
212#define HDA_DSP_REG_ADSPIS (HDA_DSP_GEN_BASE + 0x0C)
213#define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10)
214#define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14)
215
216/* Intel HD Audio Inter-Processor Communication Registers */
217#define HDA_DSP_IPC_BASE 0x40
218#define HDA_DSP_REG_HIPCT (HDA_DSP_IPC_BASE + 0x00)
219#define HDA_DSP_REG_HIPCTE (HDA_DSP_IPC_BASE + 0x04)
220#define HDA_DSP_REG_HIPCI (HDA_DSP_IPC_BASE + 0x08)
221#define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C)
222#define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10)
223
224/* HIPCI */
225#define HDA_DSP_REG_HIPCI_BUSY BIT(31)
226#define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF
227
228/* HIPCIE */
229#define HDA_DSP_REG_HIPCIE_DONE BIT(30)
230#define HDA_DSP_REG_HIPCIE_MSG_MASK 0x3FFFFFFF
231
232/* HIPCCTL */
233#define HDA_DSP_REG_HIPCCTL_DONE BIT(1)
234#define HDA_DSP_REG_HIPCCTL_BUSY BIT(0)
235
236/* HIPCT */
237#define HDA_DSP_REG_HIPCT_BUSY BIT(31)
238#define HDA_DSP_REG_HIPCT_MSG_MASK 0x7FFFFFFF
239
240/* HIPCTE */
241#define HDA_DSP_REG_HIPCTE_MSG_MASK 0x3FFFFFFF
242
243#define HDA_DSP_ADSPIC_CL_DMA 0x2
244#define HDA_DSP_ADSPIS_CL_DMA 0x2
245
246/* Delay before scheduling D0i3 entry */
247#define BXT_D0I3_DELAY 5000
248
249#define FW_CL_STREAM_NUMBER 0x1
250
251/* ADSPCS - Audio DSP Control & Status */
252
253/*
254 * Core Reset - asserted high
255 * CRST Mask for a given core mask pattern, cm
256 */
257#define HDA_DSP_ADSPCS_CRST_SHIFT 0
258#define HDA_DSP_ADSPCS_CRST_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CRST_SHIFT)
259
260/*
261 * Core run/stall - when set to '1' core is stalled
262 * CSTALL Mask for a given core mask pattern, cm
263 */
264#define HDA_DSP_ADSPCS_CSTALL_SHIFT 8
265#define HDA_DSP_ADSPCS_CSTALL_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CSTALL_SHIFT)
266
267/*
268 * Set Power Active - when set to '1' turn cores on
269 * SPA Mask for a given core mask pattern, cm
270 */
271#define HDA_DSP_ADSPCS_SPA_SHIFT 16
272#define HDA_DSP_ADSPCS_SPA_MASK(cm) ((cm) << HDA_DSP_ADSPCS_SPA_SHIFT)
273
274/*
275 * Current Power Active - power status of cores, set by hardware
276 * CPA Mask for a given core mask pattern, cm
277 */
278#define HDA_DSP_ADSPCS_CPA_SHIFT 24
279#define HDA_DSP_ADSPCS_CPA_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CPA_SHIFT)
280
281/* Mask for a given core index, c = 0.. number of supported cores - 1 */
282#define HDA_DSP_CORE_MASK(c) BIT(c)
283
284/*
285 * Mask for a given number of cores
286 * nc = number of supported cores
287 */
288#define SOF_DSP_CORES_MASK(nc) GENMASK(((nc) - 1), 0)
289
290/* Intel HD Audio Inter-Processor Communication Registers for Cannonlake*/
291#define CNL_DSP_IPC_BASE 0xc0
292#define CNL_DSP_REG_HIPCTDR (CNL_DSP_IPC_BASE + 0x00)
293#define CNL_DSP_REG_HIPCTDA (CNL_DSP_IPC_BASE + 0x04)
294#define CNL_DSP_REG_HIPCTDD (CNL_DSP_IPC_BASE + 0x08)
295#define CNL_DSP_REG_HIPCIDR (CNL_DSP_IPC_BASE + 0x10)
296#define CNL_DSP_REG_HIPCIDA (CNL_DSP_IPC_BASE + 0x14)
297#define CNL_DSP_REG_HIPCCTL (CNL_DSP_IPC_BASE + 0x28)
298
299/* HIPCI */
300#define CNL_DSP_REG_HIPCIDR_BUSY BIT(31)
301#define CNL_DSP_REG_HIPCIDR_MSG_MASK 0x7FFFFFFF
302
303/* HIPCIE */
304#define CNL_DSP_REG_HIPCIDA_DONE BIT(31)
305#define CNL_DSP_REG_HIPCIDA_MSG_MASK 0x7FFFFFFF
306
307/* HIPCCTL */
308#define CNL_DSP_REG_HIPCCTL_DONE BIT(1)
309#define CNL_DSP_REG_HIPCCTL_BUSY BIT(0)
310
311/* HIPCT */
312#define CNL_DSP_REG_HIPCTDR_BUSY BIT(31)
313#define CNL_DSP_REG_HIPCTDR_MSG_MASK 0x7FFFFFFF
314
315/* HIPCTDA */
316#define CNL_DSP_REG_HIPCTDA_DONE BIT(31)
317#define CNL_DSP_REG_HIPCTDA_MSG_MASK 0x7FFFFFFF
318
319/* HIPCTDD */
320#define CNL_DSP_REG_HIPCTDD_MSG_MASK 0x7FFFFFFF
321
322/* BDL */
323#define HDA_DSP_BDL_SIZE 4096
324#define HDA_DSP_MAX_BDL_ENTRIES \
325 (HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl))
326
327/* Number of DAIs */
328#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
329#define SOF_SKL_NUM_DAIS 14
330#else
331#define SOF_SKL_NUM_DAIS 8
332#endif
333
334/* Intel HD Audio SRAM Window 0*/
335#define HDA_ADSP_SRAM0_BASE_SKL 0x8000
336
337/* Firmware status window */
338#define HDA_ADSP_FW_STATUS_SKL HDA_ADSP_SRAM0_BASE_SKL
339#define HDA_ADSP_ERROR_CODE_SKL (HDA_ADSP_FW_STATUS_SKL + 0x4)
340
341/* Host Device Memory Space */
342#define APL_SSP_BASE_OFFSET 0x2000
343#define CNL_SSP_BASE_OFFSET 0x10000
344
345/* Host Device Memory Size of a Single SSP */
346#define SSP_DEV_MEM_SIZE 0x1000
347
348/* SSP Count of the Platform */
349#define APL_SSP_COUNT 6
350#define CNL_SSP_COUNT 3
351
352/* SSP Registers */
353#define SSP_SSC1_OFFSET 0x4
354#define SSP_SET_SCLK_SLAVE BIT(25)
355#define SSP_SET_SFRM_SLAVE BIT(24)
356#define SSP_SET_SLAVE (SSP_SET_SCLK_SLAVE | SSP_SET_SFRM_SLAVE)
357
358#define HDA_IDISP_CODEC(x) ((x) & BIT(2))
359
360struct sof_intel_dsp_bdl {
361 __le32 addr_l;
362 __le32 addr_h;
363 __le32 size;
364 __le32 ioc;
365} __attribute((packed));
366
367#define SOF_HDA_PLAYBACK_STREAMS 16
368#define SOF_HDA_CAPTURE_STREAMS 16
369#define SOF_HDA_PLAYBACK 0
370#define SOF_HDA_CAPTURE 1
371
372/* represents DSP HDA controller frontend - i.e. host facing control */
373struct sof_intel_hda_dev {
374
375 struct hda_bus hbus;
376
377 /* hw config */
378 const struct sof_intel_dsp_desc *desc;
379
380 /* trace */
381 struct hdac_ext_stream *dtrace_stream;
382
383 /* if position update IPC needed */
384 u32 no_ipc_position;
385
386 /* the maximum number of streams (playback + capture) supported */
387 u32 stream_max;
388
389 int irq;
390
391 /* DMIC device */
392 struct platform_device *dmic_dev;
393};
394
395static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
396{
397 struct sof_intel_hda_dev *hda = s->pdata->hw_pdata;
398
399 return &hda->hbus.core;
400}
401
402static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s)
403{
404 struct sof_intel_hda_dev *hda = s->pdata->hw_pdata;
405
406 return &hda->hbus;
407}
408
409struct sof_intel_hda_stream {
410 struct hdac_ext_stream hda_stream;
411 struct sof_intel_stream stream;
412 int hw_params_upon_resume; /* set up hw_params upon resume */
413};
414
415#define bus_to_sof_hda(bus) \
416 container_of(bus, struct sof_intel_hda_dev, hbus.core)
417
418#define SOF_STREAM_SD_OFFSET(s) \
419 (SOF_HDA_ADSP_SD_ENTRY_SIZE * ((s)->index) \
420 + SOF_HDA_ADSP_LOADER_BASE)
421
422/*
423 * DSP Core services.
424 */
425int hda_dsp_probe(struct snd_sof_dev *sdev);
426int hda_dsp_remove(struct snd_sof_dev *sdev);
427int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev,
428 unsigned int core_mask);
429int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev,
430 unsigned int core_mask);
431int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask);
432int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
433int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
434int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
435int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask);
436bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev,
437 unsigned int core_mask);
438int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
439 unsigned int core_mask);
440void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev);
441void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev);
442
443int hda_dsp_suspend(struct snd_sof_dev *sdev, int state);
444int hda_dsp_resume(struct snd_sof_dev *sdev);
445int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
446int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
447void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
448void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
449void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
450void hda_ipc_dump(struct snd_sof_dev *sdev);
451
452/*
453 * DSP PCM Operations.
454 */
455int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
456 struct snd_pcm_substream *substream);
457int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
458 struct snd_pcm_substream *substream);
459int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
460 struct snd_pcm_substream *substream,
461 struct snd_pcm_hw_params *params,
462 struct sof_ipc_stream_params *ipc_params);
463int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
464 struct snd_pcm_substream *substream, int cmd);
465snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
466 struct snd_pcm_substream *substream);
467
468/*
469 * DSP Stream Operations.
470 */
471
472int hda_dsp_stream_init(struct snd_sof_dev *sdev);
473void hda_dsp_stream_free(struct snd_sof_dev *sdev);
474int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
475 struct hdac_ext_stream *stream,
476 struct snd_dma_buffer *dmab,
477 struct snd_pcm_hw_params *params);
478int hda_dsp_stream_trigger(struct snd_sof_dev *sdev,
479 struct hdac_ext_stream *stream, int cmd);
480irqreturn_t hda_dsp_stream_interrupt(int irq, void *context);
481irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context);
482int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
483 struct snd_dma_buffer *dmab,
484 struct hdac_stream *stream);
485
486struct hdac_ext_stream *
487 hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);
488int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
489int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
490 struct hdac_ext_stream *stream,
491 int enable, u32 size);
492
493void hda_ipc_msg_data(struct snd_sof_dev *sdev,
494 struct snd_pcm_substream *substream,
495 void *p, size_t sz);
496int hda_ipc_pcm_params(struct snd_sof_dev *sdev,
497 struct snd_pcm_substream *substream,
498 const struct sof_ipc_pcm_params_reply *reply);
499
500/*
501 * DSP IPC Operations.
502 */
503int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev,
504 struct snd_sof_ipc_msg *msg);
505void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev);
506int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id);
507irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context);
508irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context);
509int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
510
511/*
512 * DSP Code loader.
513 */
514int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
515int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev);
516
517/* pre and post fw run ops */
518int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev);
519int hda_dsp_post_fw_run(struct snd_sof_dev *sdev);
520
521/*
522 * HDA Controller Operations.
523 */
524int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev);
525void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable);
526void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable);
527int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
528void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
529int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
530int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset);
531
532/*
533 * HDA bus operations.
534 */
535void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev,
536 const struct hdac_ext_bus_ops *ext_ops);
537
538#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
539/*
540 * HDA Codec operations.
541 */
542int hda_codec_probe_bus(struct snd_sof_dev *sdev);
543
544#endif /* CONFIG_SND_SOC_SOF_HDA */
545
546#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)
547
548void hda_codec_i915_get(struct snd_sof_dev *sdev);
549void hda_codec_i915_put(struct snd_sof_dev *sdev);
550int hda_codec_i915_init(struct snd_sof_dev *sdev);
551int hda_codec_i915_exit(struct snd_sof_dev *sdev);
552
553#else
554
555static inline void hda_codec_i915_get(struct snd_sof_dev *sdev) { }
556static inline void hda_codec_i915_put(struct snd_sof_dev *sdev) { }
557static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; }
558static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; }
559
560#endif /* CONFIG_SND_SOC_SOF_HDA && CONFIG_SND_SOC_HDAC_HDMI */
561
562/*
563 * Trace Control.
564 */
565int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag);
566int hda_dsp_trace_release(struct snd_sof_dev *sdev);
567int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
568
569/* common dai driver */
570extern struct snd_soc_dai_driver skl_dai[];
571
572/*
573 * Platform Specific HW abstraction Ops.
574 */
575extern const struct snd_sof_dsp_ops sof_apl_ops;
576extern const struct snd_sof_dsp_ops sof_cnl_ops;
577extern const struct snd_sof_dsp_ops sof_skl_ops;
578
579extern const struct sof_intel_dsp_desc apl_chip_info;
580extern const struct sof_intel_dsp_desc cnl_chip_info;
581extern const struct sof_intel_dsp_desc skl_chip_info;
582
583#endif
diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c
new file mode 100644
index 000000000000..4edd92151fd5
--- /dev/null
+++ b/sound/soc/sof/intel/intel-ipc.c
@@ -0,0 +1,92 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2019 Intel Corporation. All rights reserved.
7//
8// Authors: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
9
10/* Intel-specific SOF IPC code */
11
12#include <linux/device.h>
13#include <linux/export.h>
14#include <linux/module.h>
15#include <linux/types.h>
16
17#include <sound/pcm.h>
18#include <sound/sof/stream.h>
19
20#include "../ops.h"
21#include "../sof-priv.h"
22
23struct intel_stream {
24 size_t posn_offset;
25};
26
27/* Mailbox-based Intel IPC implementation */
28void intel_ipc_msg_data(struct snd_sof_dev *sdev,
29 struct snd_pcm_substream *substream,
30 void *p, size_t sz)
31{
32 if (!substream || !sdev->stream_box.size) {
33 sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
34 } else {
35 struct intel_stream *stream = substream->runtime->private_data;
36
37 /* The stream might already be closed */
38 if (stream)
39 sof_mailbox_read(sdev, stream->posn_offset, p, sz);
40 }
41}
42EXPORT_SYMBOL(intel_ipc_msg_data);
43
44int intel_ipc_pcm_params(struct snd_sof_dev *sdev,
45 struct snd_pcm_substream *substream,
46 const struct sof_ipc_pcm_params_reply *reply)
47{
48 struct intel_stream *stream = substream->runtime->private_data;
49 size_t posn_offset = reply->posn_offset;
50
51 /* check if offset is overflow or it is not aligned */
52 if (posn_offset > sdev->stream_box.size ||
53 posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
54 return -EINVAL;
55
56 stream->posn_offset = sdev->stream_box.offset + posn_offset;
57
58 dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
59 substream->stream, stream->posn_offset);
60
61 return 0;
62}
63EXPORT_SYMBOL(intel_ipc_pcm_params);
64
65int intel_pcm_open(struct snd_sof_dev *sdev,
66 struct snd_pcm_substream *substream)
67{
68 struct intel_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
69
70 if (!stream)
71 return -ENOMEM;
72
73 /* binding pcm substream to hda stream */
74 substream->runtime->private_data = stream;
75
76 return 0;
77}
78EXPORT_SYMBOL(intel_pcm_open);
79
80int intel_pcm_close(struct snd_sof_dev *sdev,
81 struct snd_pcm_substream *substream)
82{
83 struct intel_stream *stream = substream->runtime->private_data;
84
85 substream->runtime->private_data = NULL;
86 kfree(stream);
87
88 return 0;
89}
90EXPORT_SYMBOL(intel_pcm_close);
91
92MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
new file mode 100644
index 000000000000..f7a3f62e45d4
--- /dev/null
+++ b/sound/soc/sof/intel/shim.h
@@ -0,0 +1,185 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2017 Intel Corporation. All rights reserved.
7 *
8 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 */
10
11#ifndef __SOF_INTEL_SHIM_H
12#define __SOF_INTEL_SHIM_H
13
14/*
15 * SHIM registers for BYT, BSW, CHT, HSW, BDW
16 */
17
18#define SHIM_CSR (SHIM_OFFSET + 0x00)
19#define SHIM_PISR (SHIM_OFFSET + 0x08)
20#define SHIM_PIMR (SHIM_OFFSET + 0x10)
21#define SHIM_ISRX (SHIM_OFFSET + 0x18)
22#define SHIM_ISRD (SHIM_OFFSET + 0x20)
23#define SHIM_IMRX (SHIM_OFFSET + 0x28)
24#define SHIM_IMRD (SHIM_OFFSET + 0x30)
25#define SHIM_IPCX (SHIM_OFFSET + 0x38)
26#define SHIM_IPCD (SHIM_OFFSET + 0x40)
27#define SHIM_ISRSC (SHIM_OFFSET + 0x48)
28#define SHIM_ISRLPESC (SHIM_OFFSET + 0x50)
29#define SHIM_IMRSC (SHIM_OFFSET + 0x58)
30#define SHIM_IMRLPESC (SHIM_OFFSET + 0x60)
31#define SHIM_IPCSC (SHIM_OFFSET + 0x68)
32#define SHIM_IPCLPESC (SHIM_OFFSET + 0x70)
33#define SHIM_CLKCTL (SHIM_OFFSET + 0x78)
34#define SHIM_CSR2 (SHIM_OFFSET + 0x80)
35#define SHIM_LTRC (SHIM_OFFSET + 0xE0)
36#define SHIM_HMDC (SHIM_OFFSET + 0xE8)
37
38#define SHIM_PWMCTRL 0x1000
39
40/*
41 * SST SHIM register bits for BYT, BSW, CHT HSW, BDW
42 * Register bit naming and functionaility can differ between devices.
43 */
44
45/* CSR / CS */
46#define SHIM_CSR_RST BIT(1)
47#define SHIM_CSR_SBCS0 BIT(2)
48#define SHIM_CSR_SBCS1 BIT(3)
49#define SHIM_CSR_DCS(x) ((x) << 4)
50#define SHIM_CSR_DCS_MASK (0x7 << 4)
51#define SHIM_CSR_STALL BIT(10)
52#define SHIM_CSR_S0IOCS BIT(21)
53#define SHIM_CSR_S1IOCS BIT(23)
54#define SHIM_CSR_LPCS BIT(31)
55#define SHIM_CSR_24MHZ_LPCS \
56 (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1 | SHIM_CSR_LPCS)
57#define SHIM_CSR_24MHZ_NO_LPCS (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1)
58#define SHIM_BYT_CSR_RST BIT(0)
59#define SHIM_BYT_CSR_VECTOR_SEL BIT(1)
60#define SHIM_BYT_CSR_STALL BIT(2)
61#define SHIM_BYT_CSR_PWAITMODE BIT(3)
62
63/* ISRX / ISC */
64#define SHIM_ISRX_BUSY BIT(1)
65#define SHIM_ISRX_DONE BIT(0)
66#define SHIM_BYT_ISRX_REQUEST BIT(1)
67
68/* ISRD / ISD */
69#define SHIM_ISRD_BUSY BIT(1)
70#define SHIM_ISRD_DONE BIT(0)
71
72/* IMRX / IMC */
73#define SHIM_IMRX_BUSY BIT(1)
74#define SHIM_IMRX_DONE BIT(0)
75#define SHIM_BYT_IMRX_REQUEST BIT(1)
76
77/* IMRD / IMD */
78#define SHIM_IMRD_DONE BIT(0)
79#define SHIM_IMRD_BUSY BIT(1)
80#define SHIM_IMRD_SSP0 BIT(16)
81#define SHIM_IMRD_DMAC0 BIT(21)
82#define SHIM_IMRD_DMAC1 BIT(22)
83#define SHIM_IMRD_DMAC (SHIM_IMRD_DMAC0 | SHIM_IMRD_DMAC1)
84
85/* IPCX / IPCC */
86#define SHIM_IPCX_DONE BIT(30)
87#define SHIM_IPCX_BUSY BIT(31)
88#define SHIM_BYT_IPCX_DONE BIT_ULL(62)
89#define SHIM_BYT_IPCX_BUSY BIT_ULL(63)
90
91/* IPCD */
92#define SHIM_IPCD_DONE BIT(30)
93#define SHIM_IPCD_BUSY BIT(31)
94#define SHIM_BYT_IPCD_DONE BIT_ULL(62)
95#define SHIM_BYT_IPCD_BUSY BIT_ULL(63)
96
97/* CLKCTL */
98#define SHIM_CLKCTL_SMOS(x) ((x) << 24)
99#define SHIM_CLKCTL_MASK (3 << 24)
100#define SHIM_CLKCTL_DCPLCG BIT(18)
101#define SHIM_CLKCTL_SCOE1 BIT(17)
102#define SHIM_CLKCTL_SCOE0 BIT(16)
103
104/* CSR2 / CS2 */
105#define SHIM_CSR2_SDFD_SSP0 BIT(1)
106#define SHIM_CSR2_SDFD_SSP1 BIT(2)
107
108/* LTRC */
109#define SHIM_LTRC_VAL(x) ((x) << 0)
110
111/* HMDC */
112#define SHIM_HMDC_HDDA0(x) ((x) << 0)
113#define SHIM_HMDC_HDDA1(x) ((x) << 7)
114#define SHIM_HMDC_HDDA_E0_CH0 1
115#define SHIM_HMDC_HDDA_E0_CH1 2
116#define SHIM_HMDC_HDDA_E0_CH2 4
117#define SHIM_HMDC_HDDA_E0_CH3 8
118#define SHIM_HMDC_HDDA_E1_CH0 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH0)
119#define SHIM_HMDC_HDDA_E1_CH1 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH1)
120#define SHIM_HMDC_HDDA_E1_CH2 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH2)
121#define SHIM_HMDC_HDDA_E1_CH3 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH3)
122#define SHIM_HMDC_HDDA_E0_ALLCH \
123 (SHIM_HMDC_HDDA_E0_CH0 | SHIM_HMDC_HDDA_E0_CH1 | \
124 SHIM_HMDC_HDDA_E0_CH2 | SHIM_HMDC_HDDA_E0_CH3)
125#define SHIM_HMDC_HDDA_E1_ALLCH \
126 (SHIM_HMDC_HDDA_E1_CH0 | SHIM_HMDC_HDDA_E1_CH1 | \
127 SHIM_HMDC_HDDA_E1_CH2 | SHIM_HMDC_HDDA_E1_CH3)
128
129/* Audio DSP PCI registers */
130#define PCI_VDRTCTL0 0xa0
131#define PCI_VDRTCTL1 0xa4
132#define PCI_VDRTCTL2 0xa8
133#define PCI_VDRTCTL3 0xaC
134
135/* VDRTCTL0 */
136#define PCI_VDRTCL0_D3PGD BIT(0)
137#define PCI_VDRTCL0_D3SRAMPGD BIT(1)
138#define PCI_VDRTCL0_DSRAMPGE_SHIFT 12
139#define PCI_VDRTCL0_DSRAMPGE_MASK GENMASK(PCI_VDRTCL0_DSRAMPGE_SHIFT + 19,\
140 PCI_VDRTCL0_DSRAMPGE_SHIFT)
141#define PCI_VDRTCL0_ISRAMPGE_SHIFT 2
142#define PCI_VDRTCL0_ISRAMPGE_MASK GENMASK(PCI_VDRTCL0_ISRAMPGE_SHIFT + 9,\
143 PCI_VDRTCL0_ISRAMPGE_SHIFT)
144
145/* VDRTCTL2 */
146#define PCI_VDRTCL2_DCLCGE BIT(1)
147#define PCI_VDRTCL2_DTCGE BIT(10)
148#define PCI_VDRTCL2_APLLSE_MASK BIT(31)
149
150/* PMCS */
151#define PCI_PMCS 0x84
152#define PCI_PMCS_PS_MASK 0x3
153
154/* DSP hardware descriptor */
155struct sof_intel_dsp_desc {
156 int cores_num;
157 int cores_mask;
158 int init_core_mask; /* cores available after fw boot */
159 int ipc_req;
160 int ipc_req_mask;
161 int ipc_ack;
162 int ipc_ack_mask;
163 int ipc_ctl;
164 int rom_init_timeout;
165 int ssp_count; /* ssp count of the platform */
166 int ssp_base_offset; /* base address of the SSPs */
167};
168
169extern const struct snd_sof_dsp_ops sof_tng_ops;
170extern const struct snd_sof_dsp_ops sof_byt_ops;
171extern const struct snd_sof_dsp_ops sof_cht_ops;
172extern const struct snd_sof_dsp_ops sof_hsw_ops;
173extern const struct snd_sof_dsp_ops sof_bdw_ops;
174
175extern const struct sof_intel_dsp_desc byt_chip_info;
176extern const struct sof_intel_dsp_desc cht_chip_info;
177extern const struct sof_intel_dsp_desc bdw_chip_info;
178extern const struct sof_intel_dsp_desc hsw_chip_info;
179extern const struct sof_intel_dsp_desc tng_chip_info;
180
181struct sof_intel_stream {
182 size_t posn_offset;
183};
184
185#endif
diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c
new file mode 100644
index 000000000000..f0b9d3c53f6f
--- /dev/null
+++ b/sound/soc/sof/ipc.c
@@ -0,0 +1,846 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10// Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided
11// by platform driver code.
12//
13
14#include <linux/mutex.h>
15#include <linux/types.h>
16
17#include "sof-priv.h"
18#include "ops.h"
19
20/*
21 * IPC message default size and timeout (ms).
22 * TODO: allow platforms to set size and timeout.
23 */
24#define IPC_TIMEOUT_MS 300
25
26static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id);
27static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd);
28
29/*
30 * IPC message Tx/Rx message handling.
31 */
32
33/* SOF generic IPC data */
34struct snd_sof_ipc {
35 struct snd_sof_dev *sdev;
36
37 /* protects messages and the disable flag */
38 struct mutex tx_mutex;
39 /* disables further sending of ipc's */
40 bool disable_ipc_tx;
41
42 struct snd_sof_ipc_msg msg;
43};
44
45struct sof_ipc_ctrl_data_params {
46 size_t msg_bytes;
47 size_t hdr_bytes;
48 size_t pl_size;
49 size_t elems;
50 u32 num_msg;
51 u8 *src;
52 u8 *dst;
53};
54
55#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
56static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
57{
58 u8 *str;
59 u8 *str2 = NULL;
60 u32 glb;
61 u32 type;
62
63 glb = cmd & SOF_GLB_TYPE_MASK;
64 type = cmd & SOF_CMD_TYPE_MASK;
65
66 switch (glb) {
67 case SOF_IPC_GLB_REPLY:
68 str = "GLB_REPLY"; break;
69 case SOF_IPC_GLB_COMPOUND:
70 str = "GLB_COMPOUND"; break;
71 case SOF_IPC_GLB_TPLG_MSG:
72 str = "GLB_TPLG_MSG";
73 switch (type) {
74 case SOF_IPC_TPLG_COMP_NEW:
75 str2 = "COMP_NEW"; break;
76 case SOF_IPC_TPLG_COMP_FREE:
77 str2 = "COMP_FREE"; break;
78 case SOF_IPC_TPLG_COMP_CONNECT:
79 str2 = "COMP_CONNECT"; break;
80 case SOF_IPC_TPLG_PIPE_NEW:
81 str2 = "PIPE_NEW"; break;
82 case SOF_IPC_TPLG_PIPE_FREE:
83 str2 = "PIPE_FREE"; break;
84 case SOF_IPC_TPLG_PIPE_CONNECT:
85 str2 = "PIPE_CONNECT"; break;
86 case SOF_IPC_TPLG_PIPE_COMPLETE:
87 str2 = "PIPE_COMPLETE"; break;
88 case SOF_IPC_TPLG_BUFFER_NEW:
89 str2 = "BUFFER_NEW"; break;
90 case SOF_IPC_TPLG_BUFFER_FREE:
91 str2 = "BUFFER_FREE"; break;
92 default:
93 str2 = "unknown type"; break;
94 }
95 break;
96 case SOF_IPC_GLB_PM_MSG:
97 str = "GLB_PM_MSG";
98 switch (type) {
99 case SOF_IPC_PM_CTX_SAVE:
100 str2 = "CTX_SAVE"; break;
101 case SOF_IPC_PM_CTX_RESTORE:
102 str2 = "CTX_RESTORE"; break;
103 case SOF_IPC_PM_CTX_SIZE:
104 str2 = "CTX_SIZE"; break;
105 case SOF_IPC_PM_CLK_SET:
106 str2 = "CLK_SET"; break;
107 case SOF_IPC_PM_CLK_GET:
108 str2 = "CLK_GET"; break;
109 case SOF_IPC_PM_CLK_REQ:
110 str2 = "CLK_REQ"; break;
111 case SOF_IPC_PM_CORE_ENABLE:
112 str2 = "CORE_ENABLE"; break;
113 default:
114 str2 = "unknown type"; break;
115 }
116 break;
117 case SOF_IPC_GLB_COMP_MSG:
118 str = "GLB_COMP_MSG: SET_VALUE";
119 switch (type) {
120 case SOF_IPC_COMP_SET_VALUE:
121 str2 = "SET_VALUE"; break;
122 case SOF_IPC_COMP_GET_VALUE:
123 str2 = "GET_VALUE"; break;
124 case SOF_IPC_COMP_SET_DATA:
125 str2 = "SET_DATA"; break;
126 case SOF_IPC_COMP_GET_DATA:
127 str2 = "GET_DATA"; break;
128 default:
129 str2 = "unknown type"; break;
130 }
131 break;
132 case SOF_IPC_GLB_STREAM_MSG:
133 str = "GLB_STREAM_MSG";
134 switch (type) {
135 case SOF_IPC_STREAM_PCM_PARAMS:
136 str2 = "PCM_PARAMS"; break;
137 case SOF_IPC_STREAM_PCM_PARAMS_REPLY:
138 str2 = "PCM_REPLY"; break;
139 case SOF_IPC_STREAM_PCM_FREE:
140 str2 = "PCM_FREE"; break;
141 case SOF_IPC_STREAM_TRIG_START:
142 str2 = "TRIG_START"; break;
143 case SOF_IPC_STREAM_TRIG_STOP:
144 str2 = "TRIG_STOP"; break;
145 case SOF_IPC_STREAM_TRIG_PAUSE:
146 str2 = "TRIG_PAUSE"; break;
147 case SOF_IPC_STREAM_TRIG_RELEASE:
148 str2 = "TRIG_RELEASE"; break;
149 case SOF_IPC_STREAM_TRIG_DRAIN:
150 str2 = "TRIG_DRAIN"; break;
151 case SOF_IPC_STREAM_TRIG_XRUN:
152 str2 = "TRIG_XRUN"; break;
153 case SOF_IPC_STREAM_POSITION:
154 str2 = "POSITION"; break;
155 case SOF_IPC_STREAM_VORBIS_PARAMS:
156 str2 = "VORBIS_PARAMS"; break;
157 case SOF_IPC_STREAM_VORBIS_FREE:
158 str2 = "VORBIS_FREE"; break;
159 default:
160 str2 = "unknown type"; break;
161 }
162 break;
163 case SOF_IPC_FW_READY:
164 str = "FW_READY"; break;
165 case SOF_IPC_GLB_DAI_MSG:
166 str = "GLB_DAI_MSG";
167 switch (type) {
168 case SOF_IPC_DAI_CONFIG:
169 str2 = "CONFIG"; break;
170 case SOF_IPC_DAI_LOOPBACK:
171 str2 = "LOOPBACK"; break;
172 default:
173 str2 = "unknown type"; break;
174 }
175 break;
176 case SOF_IPC_GLB_TRACE_MSG:
177 str = "GLB_TRACE_MSG"; break;
178 default:
179 str = "unknown GLB command"; break;
180 }
181
182 if (str2)
183 dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
184 else
185 dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str);
186}
187#else
188static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
189{
190 dev_dbg(dev, "%s: 0x%x\n", text, cmd);
191}
192#endif
193
194/* wait for IPC message reply */
195static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg,
196 void *reply_data)
197{
198 struct snd_sof_dev *sdev = ipc->sdev;
199 struct sof_ipc_cmd_hdr *hdr = msg->msg_data;
200 int ret;
201
202 /* wait for DSP IPC completion */
203 ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
204 msecs_to_jiffies(IPC_TIMEOUT_MS));
205
206 if (ret == 0) {
207 dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n",
208 hdr->cmd, hdr->size);
209 snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
210 snd_sof_ipc_dump(ipc->sdev);
211 snd_sof_trace_notify_for_error(ipc->sdev);
212 ret = -ETIMEDOUT;
213 } else {
214 /* copy the data returned from DSP */
215 ret = msg->reply_error;
216 if (msg->reply_size)
217 memcpy(reply_data, msg->reply_data, msg->reply_size);
218 if (ret < 0)
219 dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n",
220 hdr->cmd, msg->reply_size);
221 else
222 ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
223 }
224
225 return ret;
226}
227
228/* send IPC message from host to DSP */
229static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header,
230 void *msg_data, size_t msg_bytes,
231 void *reply_data, size_t reply_bytes)
232{
233 struct snd_sof_dev *sdev = ipc->sdev;
234 struct snd_sof_ipc_msg *msg;
235 int ret;
236
237 if (ipc->disable_ipc_tx)
238 return -ENODEV;
239
240 /*
241 * The spin-lock is also still needed to protect message objects against
242 * other atomic contexts.
243 */
244 spin_lock_irq(&sdev->ipc_lock);
245
246 /* initialise the message */
247 msg = &ipc->msg;
248
249 msg->header = header;
250 msg->msg_size = msg_bytes;
251 msg->reply_size = reply_bytes;
252 msg->reply_error = 0;
253
254 /* attach any data */
255 if (msg_bytes)
256 memcpy(msg->msg_data, msg_data, msg_bytes);
257
258 sdev->msg = msg;
259
260 ret = snd_sof_dsp_send_msg(sdev, msg);
261 /* Next reply that we receive will be related to this message */
262 if (!ret)
263 msg->ipc_complete = false;
264
265 spin_unlock_irq(&sdev->ipc_lock);
266
267 if (ret < 0) {
268 /* So far IPC TX never fails, consider making the above void */
269 dev_err_ratelimited(sdev->dev,
270 "error: ipc tx failed with error %d\n",
271 ret);
272 return ret;
273 }
274
275 ipc_log_header(sdev->dev, "ipc tx", msg->header);
276
277 /* now wait for completion */
278 if (!ret)
279 ret = tx_wait_done(ipc, msg, reply_data);
280
281 return ret;
282}
283
284/* send IPC message from host to DSP */
285int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
286 void *msg_data, size_t msg_bytes, void *reply_data,
287 size_t reply_bytes)
288{
289 int ret;
290
291 if (msg_bytes > SOF_IPC_MSG_MAX_SIZE ||
292 reply_bytes > SOF_IPC_MSG_MAX_SIZE)
293 return -ENOBUFS;
294
295 /* Serialise IPC TX */
296 mutex_lock(&ipc->tx_mutex);
297
298 ret = sof_ipc_tx_message_unlocked(ipc, header, msg_data, msg_bytes,
299 reply_data, reply_bytes);
300
301 mutex_unlock(&ipc->tx_mutex);
302
303 return ret;
304}
305EXPORT_SYMBOL(sof_ipc_tx_message);
306
307/* handle reply message from DSP */
308int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
309{
310 struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
311 unsigned long flags;
312
313 /*
314 * Protect against a theoretical race with sof_ipc_tx_message(): if the
315 * DSP is fast enough to receive an IPC message, reply to it, and the
316 * host interrupt processing calls this function on a different core
317 * from the one, where the sending is taking place, the message might
318 * not yet be marked as expecting a reply.
319 */
320 spin_lock_irqsave(&sdev->ipc_lock, flags);
321
322 if (msg->ipc_complete) {
323 spin_unlock_irqrestore(&sdev->ipc_lock, flags);
324 dev_err(sdev->dev, "error: no reply expected, received 0x%x",
325 msg_id);
326 return -EINVAL;
327 }
328
329 /* wake up and return the error if we have waiters on this message ? */
330 msg->ipc_complete = true;
331 wake_up(&msg->waitq);
332
333 spin_unlock_irqrestore(&sdev->ipc_lock, flags);
334
335 return 0;
336}
337EXPORT_SYMBOL(snd_sof_ipc_reply);
338
339/* DSP firmware has sent host a message */
340void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
341{
342 struct sof_ipc_cmd_hdr hdr;
343 u32 cmd, type;
344 int err = 0;
345
346 /* read back header */
347 snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr));
348 ipc_log_header(sdev->dev, "ipc rx", hdr.cmd);
349
350 cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
351 type = hdr.cmd & SOF_CMD_TYPE_MASK;
352
353 /* check message type */
354 switch (cmd) {
355 case SOF_IPC_GLB_REPLY:
356 dev_err(sdev->dev, "error: ipc reply unknown\n");
357 break;
358 case SOF_IPC_FW_READY:
359 /* check for FW boot completion */
360 if (!sdev->boot_complete) {
361 err = sof_ops(sdev)->fw_ready(sdev, cmd);
362 if (err < 0) {
363 /*
364 * this indicates a mismatch in ABI
365 * between the driver and fw
366 */
367 dev_err(sdev->dev, "error: ABI mismatch %d\n",
368 err);
369 } else {
370 /* firmware boot completed OK */
371 sdev->boot_complete = true;
372 }
373
374 /* wake up firmware loader */
375 wake_up(&sdev->boot_wait);
376 }
377 break;
378 case SOF_IPC_GLB_COMPOUND:
379 case SOF_IPC_GLB_TPLG_MSG:
380 case SOF_IPC_GLB_PM_MSG:
381 case SOF_IPC_GLB_COMP_MSG:
382 break;
383 case SOF_IPC_GLB_STREAM_MSG:
384 /* need to pass msg id into the function */
385 ipc_stream_message(sdev, hdr.cmd);
386 break;
387 case SOF_IPC_GLB_TRACE_MSG:
388 ipc_trace_message(sdev, type);
389 break;
390 default:
391 dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd);
392 break;
393 }
394
395 ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd);
396}
397EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);
398
399/*
400 * IPC trace mechanism.
401 */
402
403static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
404{
405 struct sof_ipc_dma_trace_posn posn;
406
407 switch (msg_id) {
408 case SOF_IPC_TRACE_DMA_POSITION:
409 /* read back full message */
410 snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn));
411 snd_sof_trace_update_pos(sdev, &posn);
412 break;
413 default:
414 dev_err(sdev->dev, "error: unhandled trace message %x\n",
415 msg_id);
416 break;
417 }
418}
419
420/*
421 * IPC stream position.
422 */
423
424static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
425{
426 struct snd_sof_pcm_stream *stream;
427 struct sof_ipc_stream_posn posn;
428 struct snd_sof_pcm *spcm;
429 int direction;
430
431 spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
432 if (!spcm) {
433 dev_err(sdev->dev,
434 "error: period elapsed for unknown stream, msg_id %d\n",
435 msg_id);
436 return;
437 }
438
439 stream = &spcm->stream[direction];
440 snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
441
442 dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n",
443 posn.host_posn, posn.dai_posn, posn.wallclock);
444
445 memcpy(&stream->posn, &posn, sizeof(posn));
446
447 /* only inform ALSA for period_wakeup mode */
448 if (!stream->substream->runtime->no_period_wakeup)
449 snd_sof_pcm_period_elapsed(stream->substream);
450}
451
452/* DSP notifies host of an XRUN within FW */
453static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
454{
455 struct snd_sof_pcm_stream *stream;
456 struct sof_ipc_stream_posn posn;
457 struct snd_sof_pcm *spcm;
458 int direction;
459
460 spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
461 if (!spcm) {
462 dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n",
463 msg_id);
464 return;
465 }
466
467 stream = &spcm->stream[direction];
468 snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
469
470 dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n",
471 posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
472
473#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP)
474 /* stop PCM on XRUN - used for pipeline debug */
475 memcpy(&stream->posn, &posn, sizeof(posn));
476 snd_pcm_stop_xrun(stream->substream);
477#endif
478}
479
480/* stream notifications from DSP FW */
481static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
482{
483 /* get msg cmd type and msd id */
484 u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK;
485 u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd);
486
487 switch (msg_type) {
488 case SOF_IPC_STREAM_POSITION:
489 ipc_period_elapsed(sdev, msg_id);
490 break;
491 case SOF_IPC_STREAM_TRIG_XRUN:
492 ipc_xrun(sdev, msg_id);
493 break;
494 default:
495 dev_err(sdev->dev, "error: unhandled stream message %x\n",
496 msg_id);
497 break;
498 }
499}
500
501/* get stream position IPC - use faster MMIO method if available on platform */
502int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
503 struct snd_sof_pcm *spcm, int direction,
504 struct sof_ipc_stream_posn *posn)
505{
506 struct sof_ipc_stream stream;
507 int err;
508
509 /* read position via slower IPC */
510 stream.hdr.size = sizeof(stream);
511 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION;
512 stream.comp_id = spcm->stream[direction].comp_id;
513
514 /* send IPC to the DSP */
515 err = sof_ipc_tx_message(sdev->ipc,
516 stream.hdr.cmd, &stream, sizeof(stream), &posn,
517 sizeof(*posn));
518 if (err < 0) {
519 dev_err(sdev->dev, "error: failed to get stream %d position\n",
520 stream.comp_id);
521 return err;
522 }
523
524 return 0;
525}
526EXPORT_SYMBOL(snd_sof_ipc_stream_posn);
527
528static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type,
529 struct sof_ipc_ctrl_data *src,
530 struct sof_ipc_ctrl_data *dst,
531 struct sof_ipc_ctrl_data_params *sparams)
532{
533 switch (ctrl_type) {
534 case SOF_CTRL_TYPE_VALUE_CHAN_GET:
535 case SOF_CTRL_TYPE_VALUE_CHAN_SET:
536 sparams->src = (u8 *)src->chanv;
537 sparams->dst = (u8 *)dst->chanv;
538 break;
539 case SOF_CTRL_TYPE_VALUE_COMP_GET:
540 case SOF_CTRL_TYPE_VALUE_COMP_SET:
541 sparams->src = (u8 *)src->compv;
542 sparams->dst = (u8 *)dst->compv;
543 break;
544 case SOF_CTRL_TYPE_DATA_GET:
545 case SOF_CTRL_TYPE_DATA_SET:
546 sparams->src = (u8 *)src->data->data;
547 sparams->dst = (u8 *)dst->data->data;
548 break;
549 default:
550 return -EINVAL;
551 }
552
553 /* calculate payload size and number of messages */
554 sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes;
555 sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size);
556
557 return 0;
558}
559
560static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
561 struct sof_ipc_ctrl_data *cdata,
562 struct sof_ipc_ctrl_data_params *sparams,
563 bool send)
564{
565 struct sof_ipc_ctrl_data *partdata;
566 size_t send_bytes;
567 size_t offset = 0;
568 size_t msg_bytes;
569 size_t pl_size;
570 int err;
571 int i;
572
573 /* allocate max ipc size because we have at least one */
574 partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
575 if (!partdata)
576 return -ENOMEM;
577
578 if (send)
579 err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata,
580 sparams);
581 else
582 err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata,
583 sparams);
584 if (err < 0)
585 return err;
586
587 msg_bytes = sparams->msg_bytes;
588 pl_size = sparams->pl_size;
589
590 /* copy the header data */
591 memcpy(partdata, cdata, sparams->hdr_bytes);
592
593 /* Serialise IPC TX */
594 mutex_lock(&sdev->ipc->tx_mutex);
595
596 /* copy the payload data in a loop */
597 for (i = 0; i < sparams->num_msg; i++) {
598 send_bytes = min(msg_bytes, pl_size);
599 partdata->num_elems = send_bytes;
600 partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes;
601 partdata->msg_index = i;
602 msg_bytes -= send_bytes;
603 partdata->elems_remaining = msg_bytes;
604
605 if (send)
606 memcpy(sparams->dst, sparams->src + offset, send_bytes);
607
608 err = sof_ipc_tx_message_unlocked(sdev->ipc,
609 partdata->rhdr.hdr.cmd,
610 partdata,
611 partdata->rhdr.hdr.size,
612 partdata,
613 partdata->rhdr.hdr.size);
614 if (err < 0)
615 break;
616
617 if (!send)
618 memcpy(sparams->dst + offset, sparams->src, send_bytes);
619
620 offset += pl_size;
621 }
622
623 mutex_unlock(&sdev->ipc->tx_mutex);
624
625 kfree(partdata);
626 return err;
627}
628
629/*
630 * IPC get()/set() for kcontrols.
631 */
632int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
633 struct snd_sof_control *scontrol,
634 u32 ipc_cmd,
635 enum sof_ipc_ctrl_type ctrl_type,
636 enum sof_ipc_ctrl_cmd ctrl_cmd,
637 bool send)
638{
639 struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
640 struct snd_sof_dev *sdev = ipc->sdev;
641 struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
642 struct sof_ipc_fw_version *v = &ready->version;
643 struct sof_ipc_ctrl_data_params sparams;
644 size_t send_bytes;
645 int err;
646
647 /* read or write firmware volume */
648 if (scontrol->readback_offset != 0) {
649 /* write/read value header via mmaped region */
650 send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) *
651 cdata->num_elems;
652 if (send)
653 snd_sof_dsp_block_write(sdev, sdev->mmio_bar,
654 scontrol->readback_offset,
655 cdata->chanv, send_bytes);
656
657 else
658 snd_sof_dsp_block_read(sdev, sdev->mmio_bar,
659 scontrol->readback_offset,
660 cdata->chanv, send_bytes);
661 return 0;
662 }
663
664 cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
665 cdata->cmd = ctrl_cmd;
666 cdata->type = ctrl_type;
667 cdata->comp_id = scontrol->comp_id;
668 cdata->msg_index = 0;
669
670 /* calculate header and data size */
671 switch (cdata->type) {
672 case SOF_CTRL_TYPE_VALUE_CHAN_GET:
673 case SOF_CTRL_TYPE_VALUE_CHAN_SET:
674 sparams.msg_bytes = scontrol->num_channels *
675 sizeof(struct sof_ipc_ctrl_value_chan);
676 sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
677 sparams.elems = scontrol->num_channels;
678 break;
679 case SOF_CTRL_TYPE_VALUE_COMP_GET:
680 case SOF_CTRL_TYPE_VALUE_COMP_SET:
681 sparams.msg_bytes = scontrol->num_channels *
682 sizeof(struct sof_ipc_ctrl_value_comp);
683 sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
684 sparams.elems = scontrol->num_channels;
685 break;
686 case SOF_CTRL_TYPE_DATA_GET:
687 case SOF_CTRL_TYPE_DATA_SET:
688 sparams.msg_bytes = cdata->data->size;
689 sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data) +
690 sizeof(struct sof_abi_hdr);
691 sparams.elems = cdata->data->size;
692 break;
693 default:
694 return -EINVAL;
695 }
696
697 cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes;
698 cdata->num_elems = sparams.elems;
699 cdata->elems_remaining = 0;
700
701 /* send normal size ipc in one part */
702 if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) {
703 err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata,
704 cdata->rhdr.hdr.size, cdata,
705 cdata->rhdr.hdr.size);
706
707 if (err < 0)
708 dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n",
709 cdata->comp_id);
710
711 return err;
712 }
713
714 /* data is bigger than max ipc size, chop into smaller pieces */
715 dev_dbg(sdev->dev, "large ipc size %u, control size %u\n",
716 cdata->rhdr.hdr.size, scontrol->size);
717
718 /* large messages is only supported from ABI 3.3.0 onwards */
719 if (v->abi_version < SOF_ABI_VER(3, 3, 0)) {
720 dev_err(sdev->dev, "error: incompatible FW ABI version\n");
721 return -EINVAL;
722 }
723
724 err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send);
725
726 if (err < 0)
727 dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n",
728 cdata->comp_id);
729
730 return err;
731}
732EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data);
733
734/*
735 * IPC layer enumeration.
736 */
737
738int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox,
739 size_t dspbox_size, u32 hostbox,
740 size_t hostbox_size)
741{
742 sdev->dsp_box.offset = dspbox;
743 sdev->dsp_box.size = dspbox_size;
744 sdev->host_box.offset = hostbox;
745 sdev->host_box.size = hostbox_size;
746 return 0;
747}
748EXPORT_SYMBOL(snd_sof_dsp_mailbox_init);
749
750int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
751{
752 struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
753 struct sof_ipc_fw_version *v = &ready->version;
754
755 dev_info(sdev->dev,
756 "Firmware info: version %d:%d:%d-%s\n", v->major, v->minor,
757 v->micro, v->tag);
758 dev_info(sdev->dev,
759 "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
760 SOF_ABI_VERSION_MAJOR(v->abi_version),
761 SOF_ABI_VERSION_MINOR(v->abi_version),
762 SOF_ABI_VERSION_PATCH(v->abi_version),
763 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
764
765 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
766 dev_err(sdev->dev, "error: incompatible FW ABI version\n");
767 return -EINVAL;
768 }
769
770 if (v->abi_version > SOF_ABI_VERSION) {
771 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
772 dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n");
773 } else {
774 dev_err(sdev->dev, "error: FW ABI is more recent than kernel\n");
775 return -EINVAL;
776 }
777 }
778
779 if (ready->debug.bits.build) {
780 dev_info(sdev->dev,
781 "Firmware debug build %d on %s-%s - options:\n"
782 " GDB: %s\n"
783 " lock debug: %s\n"
784 " lock vdebug: %s\n",
785 v->build, v->date, v->time,
786 ready->debug.bits.gdb ? "enabled" : "disabled",
787 ready->debug.bits.locks ? "enabled" : "disabled",
788 ready->debug.bits.locks_verbose ? "enabled" : "disabled");
789 }
790
791 /* copy the fw_version into debugfs at first boot */
792 memcpy(&sdev->fw_version, v, sizeof(*v));
793
794 return 0;
795}
796EXPORT_SYMBOL(snd_sof_ipc_valid);
797
798struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
799{
800 struct snd_sof_ipc *ipc;
801 struct snd_sof_ipc_msg *msg;
802
803 /* check if mandatory ops required for ipc are defined */
804 if (!sof_ops(sdev)->fw_ready) {
805 dev_err(sdev->dev, "error: ipc mandatory ops not defined\n");
806 return NULL;
807 }
808
809 ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
810 if (!ipc)
811 return NULL;
812
813 mutex_init(&ipc->tx_mutex);
814 ipc->sdev = sdev;
815 msg = &ipc->msg;
816
817 /* indicate that we aren't sending a message ATM */
818 msg->ipc_complete = true;
819
820 /* pre-allocate message data */
821 msg->msg_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE,
822 GFP_KERNEL);
823 if (!msg->msg_data)
824 return NULL;
825
826 msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE,
827 GFP_KERNEL);
828 if (!msg->reply_data)
829 return NULL;
830
831 init_waitqueue_head(&msg->waitq);
832
833 return ipc;
834}
835EXPORT_SYMBOL(snd_sof_ipc_init);
836
837void snd_sof_ipc_free(struct snd_sof_dev *sdev)
838{
839 struct snd_sof_ipc *ipc = sdev->ipc;
840
841 /* disable sending of ipc's */
842 mutex_lock(&ipc->tx_mutex);
843 ipc->disable_ipc_tx = true;
844 mutex_unlock(&ipc->tx_mutex);
845}
846EXPORT_SYMBOL(snd_sof_ipc_free);
diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c
new file mode 100644
index 000000000000..81c7452aae17
--- /dev/null
+++ b/sound/soc/sof/loader.c
@@ -0,0 +1,400 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10// Generic firmware loader.
11//
12
13#include <linux/firmware.h>
14#include <sound/sof.h>
15#include "ops.h"
16
17static int get_ext_windows(struct snd_sof_dev *sdev,
18 struct sof_ipc_ext_data_hdr *ext_hdr)
19{
20 struct sof_ipc_window *w =
21 container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
22 size_t size;
23
24 if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
25 return -EINVAL;
26
27 size = sizeof(*w) + sizeof(struct sof_ipc_window_elem) * w->num_windows;
28
29 /* keep a local copy of the data */
30 sdev->info_window = kmemdup(w, size, GFP_KERNEL);
31 if (!sdev->info_window)
32 return -ENOMEM;
33
34 return 0;
35}
36
37/* parse the extended FW boot data structures from FW boot message */
38int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
39{
40 struct sof_ipc_ext_data_hdr *ext_hdr;
41 void *ext_data;
42 int ret = 0;
43
44 ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
45 if (!ext_data)
46 return -ENOMEM;
47
48 /* get first header */
49 snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
50 sizeof(*ext_hdr));
51 ext_hdr = ext_data;
52
53 while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
54 /* read in ext structure */
55 offset += sizeof(*ext_hdr);
56 snd_sof_dsp_block_read(sdev, bar, offset,
57 (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
58 ext_hdr->hdr.size - sizeof(*ext_hdr));
59
60 dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
61 ext_hdr->type, ext_hdr->hdr.size);
62
63 /* process structure data */
64 switch (ext_hdr->type) {
65 case SOF_IPC_EXT_DMA_BUFFER:
66 break;
67 case SOF_IPC_EXT_WINDOW:
68 ret = get_ext_windows(sdev, ext_hdr);
69 break;
70 default:
71 break;
72 }
73
74 if (ret < 0) {
75 dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
76 ext_hdr->type);
77 break;
78 }
79
80 /* move to next header */
81 offset += ext_hdr->hdr.size;
82 snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
83 sizeof(*ext_hdr));
84 ext_hdr = ext_data;
85 }
86
87 kfree(ext_data);
88 return ret;
89}
90EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
91
92/* generic module parser for mmaped DSPs */
93int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
94 struct snd_sof_mod_hdr *module)
95{
96 struct snd_sof_blk_hdr *block;
97 int count;
98 u32 offset;
99 size_t remaining;
100
101 dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
102 module->size, module->num_blocks, module->type);
103
104 block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
105
106 /* module->size doesn't include header size */
107 remaining = module->size;
108 for (count = 0; count < module->num_blocks; count++) {
109 /* check for wrap */
110 if (remaining < sizeof(*block)) {
111 dev_err(sdev->dev, "error: not enough data remaining\n");
112 return -EINVAL;
113 }
114
115 /* minus header size of block */
116 remaining -= sizeof(*block);
117
118 if (block->size == 0) {
119 dev_warn(sdev->dev,
120 "warning: block %d size zero\n", count);
121 dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
122 block->type, block->offset);
123 continue;
124 }
125
126 switch (block->type) {
127 case SOF_FW_BLK_TYPE_RSRVD0:
128 case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14:
129 continue; /* not handled atm */
130 case SOF_FW_BLK_TYPE_IRAM:
131 case SOF_FW_BLK_TYPE_DRAM:
132 offset = block->offset;
133 break;
134 default:
135 dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
136 block->type, count);
137 return -EINVAL;
138 }
139
140 dev_dbg(sdev->dev,
141 "block %d type 0x%x size 0x%x ==> offset 0x%x\n",
142 count, block->type, block->size, offset);
143
144 /* checking block->size to avoid unaligned access */
145 if (block->size % sizeof(u32)) {
146 dev_err(sdev->dev, "error: invalid block size 0x%x\n",
147 block->size);
148 return -EINVAL;
149 }
150 snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset,
151 block + 1, block->size);
152
153 if (remaining < block->size) {
154 dev_err(sdev->dev, "error: not enough data remaining\n");
155 return -EINVAL;
156 }
157
158 /* minus body size of block */
159 remaining -= block->size;
160 /* next block */
161 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
162 + block->size);
163 }
164
165 return 0;
166}
167EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
168
169static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
170{
171 struct snd_sof_fw_header *header;
172
173 /* Read the header information from the data pointer */
174 header = (struct snd_sof_fw_header *)fw->data;
175
176 /* verify FW sig */
177 if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
178 dev_err(sdev->dev, "error: invalid firmware signature\n");
179 return -EINVAL;
180 }
181
182 /* check size is valid */
183 if (fw->size != header->file_size + sizeof(*header)) {
184 dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
185 fw->size, header->file_size + sizeof(*header));
186 return -EINVAL;
187 }
188
189 dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
190 header->file_size, header->num_modules,
191 header->abi, sizeof(*header));
192
193 return 0;
194}
195
196static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
197{
198 struct snd_sof_fw_header *header;
199 struct snd_sof_mod_hdr *module;
200 int (*load_module)(struct snd_sof_dev *sof_dev,
201 struct snd_sof_mod_hdr *hdr);
202 int ret, count;
203 size_t remaining;
204
205 header = (struct snd_sof_fw_header *)fw->data;
206 load_module = sof_ops(sdev)->load_module;
207 if (!load_module)
208 return -EINVAL;
209
210 /* parse each module */
211 module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header));
212 remaining = fw->size - sizeof(*header);
213 /* check for wrap */
214 if (remaining > fw->size) {
215 dev_err(sdev->dev, "error: fw size smaller than header size\n");
216 return -EINVAL;
217 }
218
219 for (count = 0; count < header->num_modules; count++) {
220 /* check for wrap */
221 if (remaining < sizeof(*module)) {
222 dev_err(sdev->dev, "error: not enough data remaining\n");
223 return -EINVAL;
224 }
225
226 /* minus header size of module */
227 remaining -= sizeof(*module);
228
229 /* module */
230 ret = load_module(sdev, module);
231 if (ret < 0) {
232 dev_err(sdev->dev, "error: invalid module %d\n", count);
233 return ret;
234 }
235
236 if (remaining < module->size) {
237 dev_err(sdev->dev, "error: not enough data remaining\n");
238 return -EINVAL;
239 }
240
241 /* minus body size of module */
242 remaining -= module->size;
243 module = (struct snd_sof_mod_hdr *)((u8 *)module
244 + sizeof(*module) + module->size);
245 }
246
247 return 0;
248}
249
250int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
251{
252 struct snd_sof_pdata *plat_data = sdev->pdata;
253 const char *fw_filename;
254 int ret;
255
256 /* set code loading condition to true */
257 sdev->code_loading = 1;
258
259 /* Don't request firmware again if firmware is already requested */
260 if (plat_data->fw)
261 return 0;
262
263 fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
264 plat_data->fw_filename_prefix,
265 plat_data->fw_filename);
266 if (!fw_filename)
267 return -ENOMEM;
268
269 ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
270
271 if (ret < 0) {
272 dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
273 fw_filename, ret);
274 }
275
276 kfree(fw_filename);
277
278 return ret;
279}
280EXPORT_SYMBOL(snd_sof_load_firmware_raw);
281
282int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
283{
284 struct snd_sof_pdata *plat_data = sdev->pdata;
285 int ret;
286
287 ret = snd_sof_load_firmware_raw(sdev);
288 if (ret < 0)
289 return ret;
290
291 /* make sure the FW header and file is valid */
292 ret = check_header(sdev, plat_data->fw);
293 if (ret < 0) {
294 dev_err(sdev->dev, "error: invalid FW header\n");
295 goto error;
296 }
297
298 /* prepare the DSP for FW loading */
299 ret = snd_sof_dsp_reset(sdev);
300 if (ret < 0) {
301 dev_err(sdev->dev, "error: failed to reset DSP\n");
302 goto error;
303 }
304
305 /* parse and load firmware modules to DSP */
306 ret = load_modules(sdev, plat_data->fw);
307 if (ret < 0) {
308 dev_err(sdev->dev, "error: invalid FW modules\n");
309 goto error;
310 }
311
312 return 0;
313
314error:
315 release_firmware(plat_data->fw);
316 plat_data->fw = NULL;
317 return ret;
318
319}
320EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
321
322int snd_sof_load_firmware(struct snd_sof_dev *sdev)
323{
324 dev_dbg(sdev->dev, "loading firmware\n");
325
326 if (sof_ops(sdev)->load_firmware)
327 return sof_ops(sdev)->load_firmware(sdev);
328 return 0;
329}
330EXPORT_SYMBOL(snd_sof_load_firmware);
331
332int snd_sof_run_firmware(struct snd_sof_dev *sdev)
333{
334 int ret;
335 int init_core_mask;
336
337 init_waitqueue_head(&sdev->boot_wait);
338 sdev->boot_complete = false;
339
340 /* create fw_version debugfs to store boot version info */
341 if (sdev->first_boot) {
342 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
343 sizeof(sdev->fw_version),
344 "fw_version");
345 /* errors are only due to memory allocation, not debugfs */
346 if (ret < 0) {
347 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
348 return ret;
349 }
350 }
351
352 /* perform pre fw run operations */
353 ret = snd_sof_dsp_pre_fw_run(sdev);
354 if (ret < 0) {
355 dev_err(sdev->dev, "error: failed pre fw run op\n");
356 return ret;
357 }
358
359 dev_dbg(sdev->dev, "booting DSP firmware\n");
360
361 /* boot the firmware on the DSP */
362 ret = snd_sof_dsp_run(sdev);
363 if (ret < 0) {
364 dev_err(sdev->dev, "error: failed to reset DSP\n");
365 return ret;
366 }
367
368 init_core_mask = ret;
369
370 /* now wait for the DSP to boot */
371 ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete,
372 msecs_to_jiffies(sdev->boot_timeout));
373 if (ret == 0) {
374 dev_err(sdev->dev, "error: firmware boot failure\n");
375 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
376 SOF_DBG_TEXT | SOF_DBG_PCI);
377 return -EIO;
378 }
379
380 dev_info(sdev->dev, "firmware boot complete\n");
381
382 /* perform post fw run operations */
383 ret = snd_sof_dsp_post_fw_run(sdev);
384 if (ret < 0) {
385 dev_err(sdev->dev, "error: failed post fw run op\n");
386 return ret;
387 }
388
389 /* fw boot is complete. Update the active cores mask */
390 sdev->enabled_cores_mask = init_core_mask;
391
392 return 0;
393}
394EXPORT_SYMBOL(snd_sof_run_firmware);
395
396void snd_sof_fw_unload(struct snd_sof_dev *sdev)
397{
398 /* TODO: support module unloading at runtime */
399}
400EXPORT_SYMBOL(snd_sof_fw_unload);
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
new file mode 100644
index 000000000000..f84b4344dcc3
--- /dev/null
+++ b/sound/soc/sof/nocodec.c
@@ -0,0 +1,109 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/module.h>
12#include <sound/sof.h>
13#include "sof-priv.h"
14
15static struct snd_soc_card sof_nocodec_card = {
16 .name = "nocodec", /* the sof- prefix is added by the core */
17};
18
19static int sof_nocodec_bes_setup(struct device *dev,
20 const struct snd_sof_dsp_ops *ops,
21 struct snd_soc_dai_link *links,
22 int link_num, struct snd_soc_card *card)
23{
24 int i;
25
26 if (!ops || !links || !card)
27 return -EINVAL;
28
29 /* set up BE dai_links */
30 for (i = 0; i < link_num; i++) {
31 links[i].name = devm_kasprintf(dev, GFP_KERNEL,
32 "NoCodec-%d", i);
33 if (!links[i].name)
34 return -ENOMEM;
35
36 links[i].id = i;
37 links[i].no_pcm = 1;
38 links[i].cpu_dai_name = ops->drv[i].name;
39 links[i].platform_name = dev_name(dev);
40 links[i].codec_dai_name = "snd-soc-dummy-dai";
41 links[i].codec_name = "snd-soc-dummy";
42 links[i].dpcm_playback = 1;
43 links[i].dpcm_capture = 1;
44 }
45
46 card->dai_link = links;
47 card->num_links = link_num;
48
49 return 0;
50}
51
52int sof_nocodec_setup(struct device *dev,
53 struct snd_sof_pdata *sof_pdata,
54 struct snd_soc_acpi_mach *mach,
55 const struct sof_dev_desc *desc,
56 const struct snd_sof_dsp_ops *ops)
57{
58 struct snd_soc_dai_link *links;
59 int ret;
60
61 if (!mach)
62 return -EINVAL;
63
64 sof_pdata->drv_name = "sof-nocodec";
65
66 mach->drv_name = "sof-nocodec";
67 sof_pdata->fw_filename = desc->nocodec_fw_filename;
68 sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
69
70 /* create dummy BE dai_links */
71 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
72 ops->num_drv, GFP_KERNEL);
73 if (!links)
74 return -ENOMEM;
75
76 ret = sof_nocodec_bes_setup(dev, ops, links, ops->num_drv,
77 &sof_nocodec_card);
78 return ret;
79}
80EXPORT_SYMBOL(sof_nocodec_setup);
81
82static int sof_nocodec_probe(struct platform_device *pdev)
83{
84 struct snd_soc_card *card = &sof_nocodec_card;
85
86 card->dev = &pdev->dev;
87
88 return devm_snd_soc_register_card(&pdev->dev, card);
89}
90
91static int sof_nocodec_remove(struct platform_device *pdev)
92{
93 return 0;
94}
95
96static struct platform_driver sof_nocodec_audio = {
97 .probe = sof_nocodec_probe,
98 .remove = sof_nocodec_remove,
99 .driver = {
100 .name = "sof-nocodec",
101 .pm = &snd_soc_pm_ops,
102 },
103};
104module_platform_driver(sof_nocodec_audio)
105
106MODULE_DESCRIPTION("ASoC sof nocodec");
107MODULE_AUTHOR("Liam Girdwood");
108MODULE_LICENSE("Dual BSD/GPL");
109MODULE_ALIAS("platform:sof-nocodec");
diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c
new file mode 100644
index 000000000000..7a27c3b719e7
--- /dev/null
+++ b/sound/soc/sof/ops.c
@@ -0,0 +1,163 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/pci.h>
12#include "ops.h"
13
14static
15bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset,
16 u32 mask, u32 value)
17{
18 struct pci_dev *pci = to_pci_dev(sdev->dev);
19 unsigned int old, new;
20 u32 ret = 0;
21
22 pci_read_config_dword(pci, offset, &ret);
23 old = ret;
24 dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset);
25
26 new = (old & ~mask) | (value & mask);
27
28 if (old == new)
29 return false;
30
31 pci_write_config_dword(pci, offset, new);
32 dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value,
33 offset);
34
35 return true;
36}
37
38bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
39 u32 mask, u32 value)
40{
41 unsigned long flags;
42 bool change;
43
44 spin_lock_irqsave(&sdev->hw_lock, flags);
45 change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value);
46 spin_unlock_irqrestore(&sdev->hw_lock, flags);
47 return change;
48}
49EXPORT_SYMBOL(snd_sof_pci_update_bits);
50
51bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
52 u32 offset, u32 mask, u32 value)
53{
54 unsigned int old, new;
55 u32 ret;
56
57 ret = snd_sof_dsp_read(sdev, bar, offset);
58
59 old = ret;
60 new = (old & ~mask) | (value & mask);
61
62 if (old == new)
63 return false;
64
65 snd_sof_dsp_write(sdev, bar, offset, new);
66
67 return true;
68}
69EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked);
70
71bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
72 u32 offset, u64 mask, u64 value)
73{
74 u64 old, new;
75
76 old = snd_sof_dsp_read64(sdev, bar, offset);
77
78 new = (old & ~mask) | (value & mask);
79
80 if (old == new)
81 return false;
82
83 snd_sof_dsp_write64(sdev, bar, offset, new);
84
85 return true;
86}
87EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked);
88
89/* This is for registers bits with attribute RWC */
90bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
91 u32 mask, u32 value)
92{
93 unsigned long flags;
94 bool change;
95
96 spin_lock_irqsave(&sdev->hw_lock, flags);
97 change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask,
98 value);
99 spin_unlock_irqrestore(&sdev->hw_lock, flags);
100 return change;
101}
102EXPORT_SYMBOL(snd_sof_dsp_update_bits);
103
104bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset,
105 u64 mask, u64 value)
106{
107 unsigned long flags;
108 bool change;
109
110 spin_lock_irqsave(&sdev->hw_lock, flags);
111 change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask,
112 value);
113 spin_unlock_irqrestore(&sdev->hw_lock, flags);
114 return change;
115}
116EXPORT_SYMBOL(snd_sof_dsp_update_bits64);
117
118static
119void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar,
120 u32 offset, u32 mask, u32 value)
121{
122 unsigned int old, new;
123 u32 ret;
124
125 ret = snd_sof_dsp_read(sdev, bar, offset);
126
127 old = ret;
128 new = (old & ~mask) | (value & mask);
129
130 snd_sof_dsp_write(sdev, bar, offset, new);
131}
132
133/* This is for registers bits with attribute RWC */
134void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
135 u32 offset, u32 mask, u32 value)
136{
137 unsigned long flags;
138
139 spin_lock_irqsave(&sdev->hw_lock, flags);
140 snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value);
141 spin_unlock_irqrestore(&sdev->hw_lock, flags);
142}
143EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);
144
145void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
146{
147 dev_err(sdev->dev, "error : DSP panic!\n");
148
149 /*
150 * check if DSP is not ready and did not set the dsp_oops_offset.
151 * if the dsp_oops_offset is not set, set it from the panic message.
152 * Also add a check to memory window setting with panic message.
153 */
154 if (!sdev->dsp_oops_offset)
155 sdev->dsp_oops_offset = offset;
156 else
157 dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n",
158 sdev->dsp_oops_offset, offset);
159
160 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
161 snd_sof_trace_notify_for_error(sdev);
162}
163EXPORT_SYMBOL(snd_sof_dsp_panic);
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
new file mode 100644
index 000000000000..80fc3b374c2b
--- /dev/null
+++ b/sound/soc/sof/ops.h
@@ -0,0 +1,411 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 *
8 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 */
10
11#ifndef __SOUND_SOC_SOF_IO_H
12#define __SOUND_SOC_SOF_IO_H
13
14#include <linux/device.h>
15#include <linux/interrupt.h>
16#include <linux/kernel.h>
17#include <linux/types.h>
18#include <sound/pcm.h>
19#include "sof-priv.h"
20
21#define sof_ops(sdev) \
22 ((sdev)->pdata->desc->ops)
23
24/* Mandatory operations are verified during probing */
25
26/* init */
27static inline int snd_sof_probe(struct snd_sof_dev *sdev)
28{
29 return sof_ops(sdev)->probe(sdev);
30}
31
32static inline int snd_sof_remove(struct snd_sof_dev *sdev)
33{
34 if (sof_ops(sdev)->remove)
35 return sof_ops(sdev)->remove(sdev);
36
37 return 0;
38}
39
40/* control */
41
42/*
43 * snd_sof_dsp_run returns the core mask of the cores that are available
44 * after successful fw boot
45 */
46static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev)
47{
48 return sof_ops(sdev)->run(sdev);
49}
50
51static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev)
52{
53 if (sof_ops(sdev)->stall)
54 return sof_ops(sdev)->stall(sdev);
55
56 return 0;
57}
58
59static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev)
60{
61 if (sof_ops(sdev)->reset)
62 return sof_ops(sdev)->reset(sdev);
63
64 return 0;
65}
66
67/* dsp core power up/power down */
68static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev,
69 unsigned int core_mask)
70{
71 if (sof_ops(sdev)->core_power_up)
72 return sof_ops(sdev)->core_power_up(sdev, core_mask);
73
74 return 0;
75}
76
77static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev,
78 unsigned int core_mask)
79{
80 if (sof_ops(sdev)->core_power_down)
81 return sof_ops(sdev)->core_power_down(sdev, core_mask);
82
83 return 0;
84}
85
86/* pre/post fw load */
87static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev)
88{
89 if (sof_ops(sdev)->pre_fw_run)
90 return sof_ops(sdev)->pre_fw_run(sdev);
91
92 return 0;
93}
94
95static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev)
96{
97 if (sof_ops(sdev)->post_fw_run)
98 return sof_ops(sdev)->post_fw_run(sdev);
99
100 return 0;
101}
102
103/* power management */
104static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev)
105{
106 if (sof_ops(sdev)->resume)
107 return sof_ops(sdev)->resume(sdev);
108
109 return 0;
110}
111
112static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state)
113{
114 if (sof_ops(sdev)->suspend)
115 return sof_ops(sdev)->suspend(sdev, state);
116
117 return 0;
118}
119
120static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev)
121{
122 if (sof_ops(sdev)->runtime_resume)
123 return sof_ops(sdev)->runtime_resume(sdev);
124
125 return 0;
126}
127
128static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev,
129 int state)
130{
131 if (sof_ops(sdev)->runtime_suspend)
132 return sof_ops(sdev)->runtime_suspend(sdev, state);
133
134 return 0;
135}
136
137static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
138{
139 if (sof_ops(sdev)->set_hw_params_upon_resume)
140 sof_ops(sdev)->set_hw_params_upon_resume(sdev);
141}
142
143static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
144{
145 if (sof_ops(sdev)->set_clk)
146 return sof_ops(sdev)->set_clk(sdev, freq);
147
148 return 0;
149}
150
151/* debug */
152static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags)
153{
154 if (sof_ops(sdev)->dbg_dump)
155 return sof_ops(sdev)->dbg_dump(sdev, flags);
156}
157
158static inline void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
159{
160 if (sof_ops(sdev)->ipc_dump)
161 return sof_ops(sdev)->ipc_dump(sdev);
162}
163
164/* register IO */
165static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar,
166 u32 offset, u32 value)
167{
168 if (sof_ops(sdev)->write) {
169 sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value);
170 return;
171 }
172
173 dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
174}
175
176static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar,
177 u32 offset, u64 value)
178{
179 if (sof_ops(sdev)->write64) {
180 sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value);
181 return;
182 }
183
184 dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__);
185}
186
187static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar,
188 u32 offset)
189{
190 if (sof_ops(sdev)->read)
191 return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset);
192
193 dev_err(sdev->dev, "error: %s not defined\n", __func__);
194 return -ENOTSUPP;
195}
196
197static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar,
198 u32 offset)
199{
200 if (sof_ops(sdev)->read64)
201 return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset);
202
203 dev_err(sdev->dev, "error: %s not defined\n", __func__);
204 return -ENOTSUPP;
205}
206
207/* block IO */
208static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar,
209 u32 offset, void *dest, size_t bytes)
210{
211 sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes);
212}
213
214static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar,
215 u32 offset, void *src, size_t bytes)
216{
217 sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes);
218}
219
220/* ipc */
221static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev,
222 struct snd_sof_ipc_msg *msg)
223{
224 return sof_ops(sdev)->send_msg(sdev, msg);
225}
226
227/* host DMA trace */
228static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev,
229 u32 *stream_tag)
230{
231 if (sof_ops(sdev)->trace_init)
232 return sof_ops(sdev)->trace_init(sdev, stream_tag);
233
234 return 0;
235}
236
237static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev)
238{
239 if (sof_ops(sdev)->trace_release)
240 return sof_ops(sdev)->trace_release(sdev);
241
242 return 0;
243}
244
245static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd)
246{
247 if (sof_ops(sdev)->trace_trigger)
248 return sof_ops(sdev)->trace_trigger(sdev, cmd);
249
250 return 0;
251}
252
253/* host PCM ops */
254static inline int
255snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,
256 struct snd_pcm_substream *substream)
257{
258 if (sof_ops(sdev) && sof_ops(sdev)->pcm_open)
259 return sof_ops(sdev)->pcm_open(sdev, substream);
260
261 return 0;
262}
263
264/* disconnect pcm substream to a host stream */
265static inline int
266snd_sof_pcm_platform_close(struct snd_sof_dev *sdev,
267 struct snd_pcm_substream *substream)
268{
269 if (sof_ops(sdev) && sof_ops(sdev)->pcm_close)
270 return sof_ops(sdev)->pcm_close(sdev, substream);
271
272 return 0;
273}
274
275/* host stream hw params */
276static inline int
277snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
278 struct snd_pcm_substream *substream,
279 struct snd_pcm_hw_params *params,
280 struct sof_ipc_stream_params *ipc_params)
281{
282 if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params)
283 return sof_ops(sdev)->pcm_hw_params(sdev, substream,
284 params, ipc_params);
285
286 return 0;
287}
288
289/* host stream trigger */
290static inline int
291snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev,
292 struct snd_pcm_substream *substream, int cmd)
293{
294 if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger)
295 return sof_ops(sdev)->pcm_trigger(sdev, substream, cmd);
296
297 return 0;
298}
299
300/* host DSP message data */
301static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev,
302 struct snd_pcm_substream *substream,
303 void *p, size_t sz)
304{
305 sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz);
306}
307
308/* host configure DSP HW parameters */
309static inline int
310snd_sof_ipc_pcm_params(struct snd_sof_dev *sdev,
311 struct snd_pcm_substream *substream,
312 const struct sof_ipc_pcm_params_reply *reply)
313{
314 return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply);
315}
316
317/* host stream pointer */
318static inline snd_pcm_uframes_t
319snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev,
320 struct snd_pcm_substream *substream)
321{
322 if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer)
323 return sof_ops(sdev)->pcm_pointer(sdev, substream);
324
325 return 0;
326}
327
328static inline const struct snd_sof_dsp_ops
329*sof_get_ops(const struct sof_dev_desc *d,
330 const struct sof_ops_table mach_ops[], int asize)
331{
332 int i;
333
334 for (i = 0; i < asize; i++) {
335 if (d == mach_ops[i].desc)
336 return mach_ops[i].ops;
337 }
338
339 /* not found */
340 return NULL;
341}
342
343/**
344 * snd_sof_dsp_register_poll_timeout - Periodically poll an address
345 * until a condition is met or a timeout occurs
346 * @op: accessor function (takes @addr as its only argument)
347 * @addr: Address to poll
348 * @val: Variable to read the value into
349 * @cond: Break condition (usually involving @val)
350 * @sleep_us: Maximum time to sleep between reads in us (0
351 * tight-loops). Should be less than ~20ms since usleep_range
352 * is used (see Documentation/timers/timers-howto.txt).
353 * @timeout_us: Timeout in us, 0 means never timeout
354 *
355 * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
356 * case, the last read value at @addr is stored in @val. Must not
357 * be called from atomic context if sleep_us or timeout_us are used.
358 *
359 * This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
360 */
361#define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \
362({ \
363 u64 __timeout_us = (timeout_us); \
364 unsigned long __sleep_us = (sleep_us); \
365 ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
366 might_sleep_if((__sleep_us) != 0); \
367 for (;;) { \
368 (val) = snd_sof_dsp_read(sdev, bar, offset); \
369 if (cond) { \
370 dev_dbg(sdev->dev, \
371 "FW Poll Status: reg=%#x successful\n", (val)); \
372 break; \
373 } \
374 if (__timeout_us && \
375 ktime_compare(ktime_get(), __timeout) > 0) { \
376 (val) = snd_sof_dsp_read(sdev, bar, offset); \
377 dev_dbg(sdev->dev, \
378 "FW Poll Status: reg=%#x timedout\n", (val)); \
379 break; \
380 } \
381 if (__sleep_us) \
382 usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
383 } \
384 (cond) ? 0 : -ETIMEDOUT; \
385})
386
387/* This is for registers bits with attribute RWC */
388bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
389 u32 mask, u32 value);
390
391bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar,
392 u32 offset, u32 mask, u32 value);
393
394bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar,
395 u32 offset, u64 mask, u64 value);
396
397bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset,
398 u32 mask, u32 value);
399
400bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar,
401 u32 offset, u64 mask, u64 value);
402
403void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
404 u32 offset, u32 mask, u32 value);
405
406int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset,
407 u32 mask, u32 target, u32 timeout_ms,
408 u32 interval_us);
409
410void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset);
411#endif
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
new file mode 100644
index 000000000000..649968841dad
--- /dev/null
+++ b/sound/soc/sof/pcm.c
@@ -0,0 +1,767 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10// PCM Layer, interface between ALSA and IPC.
11//
12
13#include <linux/pm_runtime.h>
14#include <sound/pcm_params.h>
15#include <sound/sof.h>
16#include "sof-priv.h"
17#include "ops.h"
18
19#define DRV_NAME "sof-audio-component"
20
21/* Create DMA buffer page table for DSP */
22static int create_page_table(struct snd_pcm_substream *substream,
23 unsigned char *dma_area, size_t size)
24{
25 struct snd_soc_pcm_runtime *rtd = substream->private_data;
26 struct snd_soc_component *component =
27 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
28 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
29 struct snd_sof_pcm *spcm;
30 struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
31 int stream = substream->stream;
32
33 spcm = snd_sof_find_spcm_dai(sdev, rtd);
34 if (!spcm)
35 return -EINVAL;
36
37 return snd_sof_create_page_table(sdev, dmab,
38 spcm->stream[stream].page_table.area, size);
39}
40
41static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream,
42 const struct sof_ipc_pcm_params_reply *reply)
43{
44 struct snd_sof_dev *sdev = spcm->sdev;
45 /* validate offset */
46 int ret = snd_sof_ipc_pcm_params(sdev, substream, reply);
47
48 if (ret < 0)
49 dev_err(sdev->dev, "error: got wrong reply for PCM %d\n",
50 spcm->pcm.pcm_id);
51
52 return ret;
53}
54
55/*
56 * sof pcm period elapse work
57 */
58static void sof_pcm_period_elapsed_work(struct work_struct *work)
59{
60 struct snd_sof_pcm_stream *sps =
61 container_of(work, struct snd_sof_pcm_stream,
62 period_elapsed_work);
63
64 snd_pcm_period_elapsed(sps->substream);
65}
66
67/*
68 * sof pcm period elapse, this could be called at irq thread context.
69 */
70void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
71{
72 struct snd_soc_pcm_runtime *rtd = substream->private_data;
73 struct snd_soc_component *component =
74 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
75 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
76 struct snd_sof_pcm *spcm;
77
78 spcm = snd_sof_find_spcm_dai(sdev, rtd);
79 if (!spcm) {
80 dev_err(sdev->dev,
81 "error: period elapsed for unknown stream!\n");
82 return;
83 }
84
85 /*
86 * snd_pcm_period_elapsed() can be called in interrupt context
87 * before IRQ_HANDLED is returned. Inside snd_pcm_period_elapsed(),
88 * when the PCM is done draining or xrun happened, a STOP IPC will
89 * then be sent and this IPC will hit IPC timeout.
90 * To avoid sending IPC before the previous IPC is handled, we
91 * schedule delayed work here to call the snd_pcm_period_elapsed().
92 */
93 schedule_work(&spcm->stream[substream->stream].period_elapsed_work);
94}
95EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
96
97/* this may get called several times by oss emulation */
98static int sof_pcm_hw_params(struct snd_pcm_substream *substream,
99 struct snd_pcm_hw_params *params)
100{
101 struct snd_soc_pcm_runtime *rtd = substream->private_data;
102 struct snd_pcm_runtime *runtime = substream->runtime;
103 struct snd_soc_component *component =
104 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
105 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
106 struct snd_sof_pcm *spcm;
107 struct sof_ipc_pcm_params pcm;
108 struct sof_ipc_pcm_params_reply ipc_params_reply;
109 int ret;
110
111 /* nothing to do for BE */
112 if (rtd->dai_link->no_pcm)
113 return 0;
114
115 spcm = snd_sof_find_spcm_dai(sdev, rtd);
116 if (!spcm)
117 return -EINVAL;
118
119 dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n",
120 spcm->pcm.pcm_id, substream->stream);
121
122 memset(&pcm, 0, sizeof(pcm));
123
124 /* allocate audio buffer pages */
125 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
126 if (ret < 0) {
127 dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n",
128 params_buffer_bytes(params), spcm->pcm.pcm_id);
129 return ret;
130 }
131 if (ret) {
132 /*
133 * ret == 1 means the buffer is changed
134 * create compressed page table for audio firmware
135 * ret == 0 means the buffer is not changed
136 * so no need to regenerate the page table
137 */
138 ret = create_page_table(substream, runtime->dma_area,
139 runtime->dma_bytes);
140 if (ret < 0)
141 return ret;
142 }
143
144 /* number of pages should be rounded up */
145 pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes);
146
147 /* set IPC PCM parameters */
148 pcm.hdr.size = sizeof(pcm);
149 pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
150 pcm.comp_id = spcm->stream[substream->stream].comp_id;
151 pcm.params.hdr.size = sizeof(pcm.params);
152 pcm.params.buffer.phy_addr =
153 spcm->stream[substream->stream].page_table.addr;
154 pcm.params.buffer.size = runtime->dma_bytes;
155 pcm.params.direction = substream->stream;
156 pcm.params.sample_valid_bytes = params_width(params) >> 3;
157 pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
158 pcm.params.rate = params_rate(params);
159 pcm.params.channels = params_channels(params);
160 pcm.params.host_period_bytes = params_period_bytes(params);
161
162 /* container size */
163 ret = snd_pcm_format_physical_width(params_format(params));
164 if (ret < 0)
165 return ret;
166 pcm.params.sample_container_bytes = ret >> 3;
167
168 /* format */
169 switch (params_format(params)) {
170 case SNDRV_PCM_FORMAT_S16:
171 pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
172 break;
173 case SNDRV_PCM_FORMAT_S24:
174 pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
175 break;
176 case SNDRV_PCM_FORMAT_S32:
177 pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
178 break;
179 case SNDRV_PCM_FORMAT_FLOAT:
180 pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT;
181 break;
182 default:
183 return -EINVAL;
184 }
185
186 /* firmware already configured host stream */
187 ret = snd_sof_pcm_platform_hw_params(sdev,
188 substream,
189 params,
190 &pcm.params);
191 if (ret < 0) {
192 dev_err(sdev->dev, "error: platform hw params failed\n");
193 return ret;
194 }
195
196 dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag);
197
198 /* send IPC to the DSP */
199 ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
200 &ipc_params_reply, sizeof(ipc_params_reply));
201 if (ret < 0) {
202 dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n",
203 pcm.params.stream_tag);
204 return ret;
205 }
206
207 ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply);
208 if (ret < 0)
209 return ret;
210
211 /* save pcm hw_params */
212 memcpy(&spcm->params[substream->stream], params, sizeof(*params));
213
214 INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
215 sof_pcm_period_elapsed_work);
216
217 return ret;
218}
219
220static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
221{
222 struct snd_soc_pcm_runtime *rtd = substream->private_data;
223 struct snd_soc_component *component =
224 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
225 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
226 struct snd_sof_pcm *spcm;
227 struct sof_ipc_stream stream;
228 struct sof_ipc_reply reply;
229 int ret;
230
231 /* nothing to do for BE */
232 if (rtd->dai_link->no_pcm)
233 return 0;
234
235 spcm = snd_sof_find_spcm_dai(sdev, rtd);
236 if (!spcm)
237 return -EINVAL;
238
239 dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
240 substream->stream);
241
242 stream.hdr.size = sizeof(stream);
243 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
244 stream.comp_id = spcm->stream[substream->stream].comp_id;
245
246 /* send IPC to the DSP */
247 ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
248 sizeof(stream), &reply, sizeof(reply));
249
250 snd_pcm_lib_free_pages(substream);
251
252 cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
253
254 return ret;
255}
256
257static int sof_pcm_prepare(struct snd_pcm_substream *substream)
258{
259 struct snd_soc_pcm_runtime *rtd = substream->private_data;
260 struct snd_soc_component *component =
261 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
262 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
263 struct snd_sof_pcm *spcm;
264 int ret;
265
266 /* nothing to do for BE */
267 if (rtd->dai_link->no_pcm)
268 return 0;
269
270 spcm = snd_sof_find_spcm_dai(sdev, rtd);
271 if (!spcm)
272 return -EINVAL;
273
274 /*
275 * check if hw_params needs to be set-up again.
276 * This is only needed when resuming from system sleep.
277 */
278 if (!spcm->hw_params_upon_resume[substream->stream])
279 return 0;
280
281 dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id,
282 substream->stream);
283
284 /* set hw_params */
285 ret = sof_pcm_hw_params(substream, &spcm->params[substream->stream]);
286 if (ret < 0) {
287 dev_err(sdev->dev, "error: set pcm hw_params after resume\n");
288 return ret;
289 }
290
291 return 0;
292}
293
294/*
295 * FE dai link trigger actions are always executed in non-atomic context because
296 * they involve IPC's.
297 */
298static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
299{
300 struct snd_soc_pcm_runtime *rtd = substream->private_data;
301 struct snd_soc_component *component =
302 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
303 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
304 struct snd_sof_pcm *spcm;
305 struct sof_ipc_stream stream;
306 struct sof_ipc_reply reply;
307 int ret;
308
309 /* nothing to do for BE */
310 if (rtd->dai_link->no_pcm)
311 return 0;
312
313 spcm = snd_sof_find_spcm_dai(sdev, rtd);
314 if (!spcm)
315 return -EINVAL;
316
317 dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n",
318 spcm->pcm.pcm_id, substream->stream, cmd);
319
320 stream.hdr.size = sizeof(stream);
321 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG;
322 stream.comp_id = spcm->stream[substream->stream].comp_id;
323
324 switch (cmd) {
325 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
326 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE;
327 break;
328 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
329 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
330 break;
331 case SNDRV_PCM_TRIGGER_RESUME:
332 /* set up hw_params */
333 ret = sof_pcm_prepare(substream);
334 if (ret < 0) {
335 dev_err(sdev->dev,
336 "error: failed to set up hw_params upon resume\n");
337 return ret;
338 }
339
340 /* fallthrough */
341 case SNDRV_PCM_TRIGGER_START:
342 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START;
343 break;
344 case SNDRV_PCM_TRIGGER_SUSPEND:
345 case SNDRV_PCM_TRIGGER_STOP:
346 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
347 break;
348 default:
349 dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd);
350 return -EINVAL;
351 }
352
353 snd_sof_pcm_platform_trigger(sdev, substream, cmd);
354
355 /* send IPC to the DSP */
356 ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
357 sizeof(stream), &reply, sizeof(reply));
358
359 if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND)
360 return ret;
361
362 /*
363 * The hw_free op is usually called when the pcm stream is closed.
364 * Since the stream is not closed during suspend, the DSP needs to be
365 * notified explicitly to free pcm to prevent errors upon resume.
366 */
367 stream.hdr.size = sizeof(stream);
368 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE;
369 stream.comp_id = spcm->stream[substream->stream].comp_id;
370
371 /* send IPC to the DSP */
372 return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
373 sizeof(stream), &reply, sizeof(reply));
374}
375
376static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream)
377{
378 struct snd_soc_pcm_runtime *rtd = substream->private_data;
379 struct snd_soc_component *component =
380 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
381 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
382 struct snd_sof_pcm *spcm;
383 snd_pcm_uframes_t host, dai;
384
385 /* nothing to do for BE */
386 if (rtd->dai_link->no_pcm)
387 return 0;
388
389 /* use dsp ops pointer callback directly if set */
390 if (sof_ops(sdev)->pcm_pointer)
391 return sof_ops(sdev)->pcm_pointer(sdev, substream);
392
393 spcm = snd_sof_find_spcm_dai(sdev, rtd);
394 if (!spcm)
395 return -EINVAL;
396
397 /* read position from DSP */
398 host = bytes_to_frames(substream->runtime,
399 spcm->stream[substream->stream].posn.host_posn);
400 dai = bytes_to_frames(substream->runtime,
401 spcm->stream[substream->stream].posn.dai_posn);
402
403 dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
404 spcm->pcm.pcm_id, substream->stream, host, dai);
405
406 return host;
407}
408
409static int sof_pcm_open(struct snd_pcm_substream *substream)
410{
411 struct snd_soc_pcm_runtime *rtd = substream->private_data;
412 struct snd_pcm_runtime *runtime = substream->runtime;
413 struct snd_soc_component *component =
414 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
415 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
416 struct snd_sof_pcm *spcm;
417 struct snd_soc_tplg_stream_caps *caps;
418 int ret;
419 int err;
420
421 /* nothing to do for BE */
422 if (rtd->dai_link->no_pcm)
423 return 0;
424
425 spcm = snd_sof_find_spcm_dai(sdev, rtd);
426 if (!spcm)
427 return -EINVAL;
428
429 dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
430 substream->stream);
431
432 /* clear hw_params_upon_resume flag */
433 spcm->hw_params_upon_resume[substream->stream] = 0;
434
435 caps = &spcm->pcm.caps[substream->stream];
436
437 ret = pm_runtime_get_sync(sdev->dev);
438 if (ret < 0) {
439 dev_err(sdev->dev, "error: pcm open failed to resume %d\n",
440 ret);
441 pm_runtime_put_noidle(sdev->dev);
442 return ret;
443 }
444
445 /* set any runtime constraints based on topology */
446 snd_pcm_hw_constraint_step(substream->runtime, 0,
447 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
448 le32_to_cpu(caps->period_size_min));
449 snd_pcm_hw_constraint_step(substream->runtime, 0,
450 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
451 le32_to_cpu(caps->period_size_min));
452
453 /* set runtime config */
454 runtime->hw.info = SNDRV_PCM_INFO_MMAP |
455 SNDRV_PCM_INFO_MMAP_VALID |
456 SNDRV_PCM_INFO_INTERLEAVED |
457 SNDRV_PCM_INFO_PAUSE |
458 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
459 runtime->hw.formats = le64_to_cpu(caps->formats);
460 runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min);
461 runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max);
462 runtime->hw.periods_min = le32_to_cpu(caps->periods_min);
463 runtime->hw.periods_max = le32_to_cpu(caps->periods_max);
464
465 /*
466 * caps->buffer_size_min is not used since the
467 * snd_pcm_hardware structure only defines buffer_bytes_max
468 */
469 runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
470
471 dev_dbg(sdev->dev, "period min %zd max %zd bytes\n",
472 runtime->hw.period_bytes_min,
473 runtime->hw.period_bytes_max);
474 dev_dbg(sdev->dev, "period count %d max %d\n",
475 runtime->hw.periods_min,
476 runtime->hw.periods_max);
477 dev_dbg(sdev->dev, "buffer max %zd bytes\n",
478 runtime->hw.buffer_bytes_max);
479
480 /* set wait time - TODO: come from topology */
481 substream->wait_time = 500;
482
483 spcm->stream[substream->stream].posn.host_posn = 0;
484 spcm->stream[substream->stream].posn.dai_posn = 0;
485 spcm->stream[substream->stream].substream = substream;
486
487 ret = snd_sof_pcm_platform_open(sdev, substream);
488 if (ret < 0) {
489 dev_err(sdev->dev, "error: pcm open failed %d\n",
490 ret);
491
492 pm_runtime_mark_last_busy(sdev->dev);
493
494 err = pm_runtime_put_autosuspend(sdev->dev);
495 if (err < 0)
496 dev_err(sdev->dev, "error: pcm close failed to idle %d\n",
497 err);
498 }
499
500 return ret;
501}
502
503static int sof_pcm_close(struct snd_pcm_substream *substream)
504{
505 struct snd_soc_pcm_runtime *rtd = substream->private_data;
506 struct snd_soc_component *component =
507 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
508 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
509 struct snd_sof_pcm *spcm;
510 int err;
511
512 /* nothing to do for BE */
513 if (rtd->dai_link->no_pcm)
514 return 0;
515
516 spcm = snd_sof_find_spcm_dai(sdev, rtd);
517 if (!spcm)
518 return -EINVAL;
519
520 dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id,
521 substream->stream);
522
523 err = snd_sof_pcm_platform_close(sdev, substream);
524 if (err < 0) {
525 dev_err(sdev->dev, "error: pcm close failed %d\n",
526 err);
527 /*
528 * keep going, no point in preventing the close
529 * from happening
530 */
531 }
532
533 pm_runtime_mark_last_busy(sdev->dev);
534
535 err = pm_runtime_put_autosuspend(sdev->dev);
536 if (err < 0)
537 dev_err(sdev->dev, "error: pcm close failed to idle %d\n",
538 err);
539
540 return 0;
541}
542
543static struct snd_pcm_ops sof_pcm_ops = {
544 .open = sof_pcm_open,
545 .close = sof_pcm_close,
546 .ioctl = snd_pcm_lib_ioctl,
547 .hw_params = sof_pcm_hw_params,
548 .prepare = sof_pcm_prepare,
549 .hw_free = sof_pcm_hw_free,
550 .trigger = sof_pcm_trigger,
551 .pointer = sof_pcm_pointer,
552 .page = snd_pcm_sgbuf_ops_page,
553};
554
555/*
556 * Pre-allocate playback/capture audio buffer pages.
557 * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free
558 * snd_pcm_lib_preallocate_free_for_all() is called by the core.
559 */
560static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd)
561{
562 struct snd_soc_component *component =
563 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
564 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
565 struct snd_sof_pcm *spcm;
566 struct snd_pcm *pcm = rtd->pcm;
567 struct snd_soc_tplg_stream_caps *caps;
568 int stream = SNDRV_PCM_STREAM_PLAYBACK;
569
570 /* find SOF PCM for this RTD */
571 spcm = snd_sof_find_spcm_dai(sdev, rtd);
572 if (!spcm) {
573 dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
574 rtd->dai_link->id);
575 return 0;
576 }
577
578 dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
579
580 /* do we need to pre-allocate playback audio buffer pages */
581 if (!spcm->pcm.playback)
582 goto capture;
583
584 caps = &spcm->pcm.caps[stream];
585
586 /* pre-allocate playback audio buffer pages */
587 dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
588 caps->name, caps->buffer_size_min, caps->buffer_size_max);
589
590 snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
591 SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
592 le32_to_cpu(caps->buffer_size_min),
593 le32_to_cpu(caps->buffer_size_max));
594capture:
595 stream = SNDRV_PCM_STREAM_CAPTURE;
596
597 /* do we need to pre-allocate capture audio buffer pages */
598 if (!spcm->pcm.capture)
599 return 0;
600
601 caps = &spcm->pcm.caps[stream];
602
603 /* pre-allocate capture audio buffer pages */
604 dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
605 caps->name, caps->buffer_size_min, caps->buffer_size_max);
606
607 snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
608 SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
609 le32_to_cpu(caps->buffer_size_min),
610 le32_to_cpu(caps->buffer_size_max));
611
612 return 0;
613}
614
615/* fixup the BE DAI link to match any values from topology */
616static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
617 struct snd_pcm_hw_params *params)
618{
619 struct snd_interval *rate = hw_param_interval(params,
620 SNDRV_PCM_HW_PARAM_RATE);
621 struct snd_interval *channels = hw_param_interval(params,
622 SNDRV_PCM_HW_PARAM_CHANNELS);
623 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
624 struct snd_soc_component *component =
625 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
626 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
627 struct snd_sof_dai *dai =
628 snd_sof_find_dai(sdev, (char *)rtd->dai_link->name);
629
630 /* no topology exists for this BE, try a common configuration */
631 if (!dai) {
632 dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n",
633 rtd->dai_link->name);
634
635 /* set 48k, stereo, 16bits by default */
636 rate->min = 48000;
637 rate->max = 48000;
638
639 channels->min = 2;
640 channels->max = 2;
641
642 snd_mask_none(fmt);
643 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
644
645 return 0;
646 }
647
648 /* read format from topology */
649 snd_mask_none(fmt);
650
651 switch (dai->comp_dai.config.frame_fmt) {
652 case SOF_IPC_FRAME_S16_LE:
653 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
654 break;
655 case SOF_IPC_FRAME_S24_4LE:
656 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
657 break;
658 case SOF_IPC_FRAME_S32_LE:
659 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
660 break;
661 default:
662 dev_err(sdev->dev, "error: No available DAI format!\n");
663 return -EINVAL;
664 }
665
666 /* read rate and channels from topology */
667 switch (dai->dai_config->type) {
668 case SOF_DAI_INTEL_SSP:
669 rate->min = dai->dai_config->ssp.fsync_rate;
670 rate->max = dai->dai_config->ssp.fsync_rate;
671 channels->min = dai->dai_config->ssp.tdm_slots;
672 channels->max = dai->dai_config->ssp.tdm_slots;
673
674 dev_dbg(sdev->dev,
675 "rate_min: %d rate_max: %d\n", rate->min, rate->max);
676 dev_dbg(sdev->dev,
677 "channels_min: %d channels_max: %d\n",
678 channels->min, channels->max);
679
680 break;
681 case SOF_DAI_INTEL_DMIC:
682 /* DMIC only supports 16 or 32 bit formats */
683 if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
684 dev_err(sdev->dev,
685 "error: invalid fmt %d for DAI type %d\n",
686 dai->comp_dai.config.frame_fmt,
687 dai->dai_config->type);
688 }
689 break;
690 case SOF_DAI_INTEL_HDA:
691 /* do nothing for HDA dai_link */
692 break;
693 default:
694 dev_err(sdev->dev, "error: invalid DAI type %d\n",
695 dai->dai_config->type);
696 break;
697 }
698
699 return 0;
700}
701
702static int sof_pcm_probe(struct snd_soc_component *component)
703{
704 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
705 struct snd_sof_pdata *plat_data = sdev->pdata;
706 const char *tplg_filename;
707 int ret;
708
709 /* load the default topology */
710 sdev->component = component;
711
712 tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
713 "%s/%s",
714 plat_data->tplg_filename_prefix,
715 plat_data->tplg_filename);
716 if (!tplg_filename)
717 return -ENOMEM;
718
719 ret = snd_sof_load_topology(sdev, tplg_filename);
720 if (ret < 0) {
721 dev_err(sdev->dev, "error: failed to load DSP topology %d\n",
722 ret);
723 return ret;
724 }
725
726 /*
727 * Some platforms in SOF, ex: BYT, may not have their platform PM
728 * callbacks set. Increment the usage count so as to
729 * prevent the device from entering runtime suspend.
730 */
731 if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume)
732 pm_runtime_get_noresume(sdev->dev);
733
734 return ret;
735}
736
737static void sof_pcm_remove(struct snd_soc_component *component)
738{
739 /* remove topology */
740 snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
741}
742
743void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
744{
745 struct snd_soc_component_driver *pd = &sdev->plat_drv;
746 struct snd_sof_pdata *plat_data = sdev->pdata;
747 const char *drv_name;
748
749 drv_name = plat_data->machine->drv_name;
750
751 pd->name = "sof-audio-component";
752 pd->probe = sof_pcm_probe;
753 pd->remove = sof_pcm_remove;
754 pd->ops = &sof_pcm_ops;
755#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
756 pd->compr_ops = &sof_compressed_ops;
757#endif
758 pd->pcm_new = sof_pcm_new;
759 pd->ignore_machine = drv_name;
760 pd->be_hw_params_fixup = sof_pcm_dai_link_fixup;
761 pd->be_pcm_base = SOF_BE_PCM_BASE;
762 pd->use_dai_pcm_id = true;
763 pd->topology_name_prefix = "sof";
764
765 /* increment module refcount when a pcm is opened */
766 pd->module_get_upon_open = 1;
767}
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
new file mode 100644
index 000000000000..8ef1d51025d8
--- /dev/null
+++ b/sound/soc/sof/pm.c
@@ -0,0 +1,388 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include "ops.h"
12#include "sof-priv.h"
13
14static int sof_restore_kcontrols(struct snd_sof_dev *sdev)
15{
16 struct snd_sof_control *scontrol;
17 int ipc_cmd, ctrl_type;
18 int ret = 0;
19
20 /* restore kcontrol values */
21 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
22 /* reset readback offset for scontrol after resuming */
23 scontrol->readback_offset = 0;
24
25 /* notify DSP of kcontrol values */
26 switch (scontrol->cmd) {
27 case SOF_CTRL_CMD_VOLUME:
28 case SOF_CTRL_CMD_ENUM:
29 case SOF_CTRL_CMD_SWITCH:
30 ipc_cmd = SOF_IPC_COMP_SET_VALUE;
31 ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
32 ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
33 ipc_cmd, ctrl_type,
34 scontrol->cmd,
35 true);
36 break;
37 case SOF_CTRL_CMD_BINARY:
38 ipc_cmd = SOF_IPC_COMP_SET_DATA;
39 ctrl_type = SOF_CTRL_TYPE_DATA_SET;
40 ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
41 ipc_cmd, ctrl_type,
42 scontrol->cmd,
43 true);
44 break;
45
46 default:
47 break;
48 }
49
50 if (ret < 0) {
51 dev_err(sdev->dev,
52 "error: failed kcontrol value set for widget: %d\n",
53 scontrol->comp_id);
54
55 return ret;
56 }
57 }
58
59 return 0;
60}
61
62static int sof_restore_pipelines(struct snd_sof_dev *sdev)
63{
64 struct snd_sof_widget *swidget;
65 struct snd_sof_route *sroute;
66 struct sof_ipc_pipe_new *pipeline;
67 struct snd_sof_dai *dai;
68 struct sof_ipc_comp_dai *comp_dai;
69 struct sof_ipc_cmd_hdr *hdr;
70 int ret;
71
72 /* restore pipeline components */
73 list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
74 struct sof_ipc_comp_reply r;
75
76 /* skip if there is no private data */
77 if (!swidget->private)
78 continue;
79
80 switch (swidget->id) {
81 case snd_soc_dapm_dai_in:
82 case snd_soc_dapm_dai_out:
83 dai = swidget->private;
84 comp_dai = &dai->comp_dai;
85 ret = sof_ipc_tx_message(sdev->ipc,
86 comp_dai->comp.hdr.cmd,
87 comp_dai, sizeof(*comp_dai),
88 &r, sizeof(r));
89 break;
90 case snd_soc_dapm_scheduler:
91
92 /*
93 * During suspend, all DSP cores are powered off.
94 * Therefore upon resume, create the pipeline comp
95 * and power up the core that the pipeline is
96 * scheduled on.
97 */
98 pipeline = swidget->private;
99 ret = sof_load_pipeline_ipc(sdev, pipeline, &r);
100 break;
101 default:
102 hdr = swidget->private;
103 ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd,
104 swidget->private, hdr->size,
105 &r, sizeof(r));
106 break;
107 }
108 if (ret < 0) {
109 dev_err(sdev->dev,
110 "error: failed to load widget type %d with ID: %d\n",
111 swidget->widget->id, swidget->comp_id);
112
113 return ret;
114 }
115 }
116
117 /* restore pipeline connections */
118 list_for_each_entry_reverse(sroute, &sdev->route_list, list) {
119 struct sof_ipc_pipe_comp_connect *connect;
120 struct sof_ipc_reply reply;
121
122 /* skip if there's no private data */
123 if (!sroute->private)
124 continue;
125
126 connect = sroute->private;
127
128 /* send ipc */
129 ret = sof_ipc_tx_message(sdev->ipc,
130 connect->hdr.cmd,
131 connect, sizeof(*connect),
132 &reply, sizeof(reply));
133 if (ret < 0) {
134 dev_err(sdev->dev,
135 "error: failed to load route sink %s control %s source %s\n",
136 sroute->route->sink,
137 sroute->route->control ? sroute->route->control
138 : "none",
139 sroute->route->source);
140
141 return ret;
142 }
143 }
144
145 /* restore dai links */
146 list_for_each_entry_reverse(dai, &sdev->dai_list, list) {
147 struct sof_ipc_reply reply;
148 struct sof_ipc_dai_config *config = dai->dai_config;
149
150 if (!config) {
151 dev_err(sdev->dev, "error: no config for DAI %s\n",
152 dai->name);
153 continue;
154 }
155
156 ret = sof_ipc_tx_message(sdev->ipc,
157 config->hdr.cmd, config,
158 config->hdr.size,
159 &reply, sizeof(reply));
160
161 if (ret < 0) {
162 dev_err(sdev->dev,
163 "error: failed to set dai config for %s\n",
164 dai->name);
165
166 return ret;
167 }
168 }
169
170 /* complete pipeline */
171 list_for_each_entry(swidget, &sdev->widget_list, list) {
172 switch (swidget->id) {
173 case snd_soc_dapm_scheduler:
174 swidget->complete =
175 snd_sof_complete_pipeline(sdev, swidget);
176 break;
177 default:
178 break;
179 }
180 }
181
182 /* restore pipeline kcontrols */
183 ret = sof_restore_kcontrols(sdev);
184 if (ret < 0)
185 dev_err(sdev->dev,
186 "error: restoring kcontrols after resume\n");
187
188 return ret;
189}
190
191static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd)
192{
193 struct sof_ipc_pm_ctx pm_ctx;
194 struct sof_ipc_reply reply;
195
196 memset(&pm_ctx, 0, sizeof(pm_ctx));
197
198 /* configure ctx save ipc message */
199 pm_ctx.hdr.size = sizeof(pm_ctx);
200 pm_ctx.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd;
201
202 /* send ctx save ipc to dsp */
203 return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx,
204 sizeof(pm_ctx), &reply, sizeof(reply));
205}
206
207static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
208{
209 struct snd_pcm_substream *substream;
210 struct snd_sof_pcm *spcm;
211 snd_pcm_state_t state;
212 int dir;
213
214 /*
215 * SOF requires hw_params to be set-up internally upon resume.
216 * So, set the flag to indicate this for those streams that
217 * have been suspended.
218 */
219 list_for_each_entry(spcm, &sdev->pcm_list, list) {
220 for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
221 substream = spcm->stream[dir].substream;
222 if (!substream || !substream->runtime)
223 continue;
224
225 state = substream->runtime->status->state;
226 if (state == SNDRV_PCM_STATE_SUSPENDED)
227 spcm->hw_params_upon_resume[dir] = 1;
228 }
229 }
230
231 /* set internal flag for BE */
232 snd_sof_dsp_hw_params_upon_resume(sdev);
233}
234
235#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
236static void sof_cache_debugfs(struct snd_sof_dev *sdev)
237{
238 struct snd_sof_dfsentry *dfse;
239
240 list_for_each_entry(dfse, &sdev->dfsentry_list, list) {
241
242 /* nothing to do if debugfs buffer is not IO mem */
243 if (dfse->type == SOF_DFSENTRY_TYPE_BUF)
244 continue;
245
246 /* cache memory that is only accessible in D0 */
247 if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY)
248 memcpy_fromio(dfse->cache_buf, dfse->io_mem,
249 dfse->size);
250 }
251}
252#endif
253
254static int sof_resume(struct device *dev, bool runtime_resume)
255{
256 struct snd_sof_dev *sdev = dev_get_drvdata(dev);
257 int ret;
258
259 /* do nothing if dsp resume callbacks are not set */
260 if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume)
261 return 0;
262
263 /*
264 * if the runtime_resume flag is set, call the runtime_resume routine
265 * or else call the system resume routine
266 */
267 if (runtime_resume)
268 ret = snd_sof_dsp_runtime_resume(sdev);
269 else
270 ret = snd_sof_dsp_resume(sdev);
271 if (ret < 0) {
272 dev_err(sdev->dev,
273 "error: failed to power up DSP after resume\n");
274 return ret;
275 }
276
277 /* load the firmware */
278 ret = snd_sof_load_firmware(sdev);
279 if (ret < 0) {
280 dev_err(sdev->dev,
281 "error: failed to load DSP firmware after resume %d\n",
282 ret);
283 return ret;
284 }
285
286 /* boot the firmware */
287 ret = snd_sof_run_firmware(sdev);
288 if (ret < 0) {
289 dev_err(sdev->dev,
290 "error: failed to boot DSP firmware after resume %d\n",
291 ret);
292 return ret;
293 }
294
295 /* resume DMA trace, only need send ipc */
296 ret = snd_sof_init_trace_ipc(sdev);
297 if (ret < 0) {
298 /* non fatal */
299 dev_warn(sdev->dev,
300 "warning: failed to init trace after resume %d\n",
301 ret);
302 }
303
304 /* restore pipelines */
305 ret = sof_restore_pipelines(sdev);
306 if (ret < 0) {
307 dev_err(sdev->dev,
308 "error: failed to restore pipeline after resume %d\n",
309 ret);
310 return ret;
311 }
312
313 /* notify DSP of system resume */
314 ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
315 if (ret < 0)
316 dev_err(sdev->dev,
317 "error: ctx_restore ipc error during resume %d\n",
318 ret);
319
320 return ret;
321}
322
323static int sof_suspend(struct device *dev, bool runtime_suspend)
324{
325 struct snd_sof_dev *sdev = dev_get_drvdata(dev);
326 int ret;
327
328 /* do nothing if dsp suspend callback is not set */
329 if (!sof_ops(sdev)->suspend)
330 return 0;
331
332 /* release trace */
333 snd_sof_release_trace(sdev);
334
335 /* set restore_stream for all streams during system suspend */
336 if (!runtime_suspend)
337 sof_set_hw_params_upon_resume(sdev);
338
339#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
340 /* cache debugfs contents during runtime suspend */
341 if (runtime_suspend)
342 sof_cache_debugfs(sdev);
343#endif
344 /* notify DSP of upcoming power down */
345 ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
346 if (ret < 0) {
347 dev_err(sdev->dev,
348 "error: ctx_save ipc error during suspend %d\n",
349 ret);
350 return ret;
351 }
352
353 /* power down all DSP cores */
354 if (runtime_suspend)
355 ret = snd_sof_dsp_runtime_suspend(sdev, 0);
356 else
357 ret = snd_sof_dsp_suspend(sdev, 0);
358 if (ret < 0)
359 dev_err(sdev->dev,
360 "error: failed to power down DSP during suspend %d\n",
361 ret);
362
363 return ret;
364}
365
366int snd_sof_runtime_suspend(struct device *dev)
367{
368 return sof_suspend(dev, true);
369}
370EXPORT_SYMBOL(snd_sof_runtime_suspend);
371
372int snd_sof_runtime_resume(struct device *dev)
373{
374 return sof_resume(dev, true);
375}
376EXPORT_SYMBOL(snd_sof_runtime_resume);
377
378int snd_sof_resume(struct device *dev)
379{
380 return sof_resume(dev, false);
381}
382EXPORT_SYMBOL(snd_sof_resume);
383
384int snd_sof_suspend(struct device *dev)
385{
386 return sof_suspend(dev, false);
387}
388EXPORT_SYMBOL(snd_sof_suspend);
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
new file mode 100644
index 000000000000..e9cf69874b5b
--- /dev/null
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -0,0 +1,312 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/acpi.h>
12#include <linux/firmware.h>
13#include <linux/module.h>
14#include <linux/pm_runtime.h>
15#include <sound/soc-acpi.h>
16#include <sound/soc-acpi-intel-match.h>
17#include <sound/sof.h>
18#ifdef CONFIG_X86
19#include <asm/iosf_mbi.h>
20#endif
21
22#include "ops.h"
23
24/* platform specific devices */
25#include "intel/shim.h"
26
27static char *fw_path;
28module_param(fw_path, charp, 0444);
29MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
30
31static char *tplg_path;
32module_param(tplg_path, charp, 0444);
33MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
34
35#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL)
36static const struct sof_dev_desc sof_acpi_haswell_desc = {
37 .machines = snd_soc_acpi_intel_haswell_machines,
38 .resindex_lpe_base = 0,
39 .resindex_pcicfg_base = 1,
40 .resindex_imr_base = -1,
41 .irqindex_host_ipc = 0,
42 .chip_info = &hsw_chip_info,
43 .default_fw_path = "intel/sof",
44 .default_tplg_path = "intel/sof-tplg",
45 .nocodec_fw_filename = "sof-hsw.ri",
46 .nocodec_tplg_filename = "sof-hsw-nocodec.tplg",
47 .ops = &sof_hsw_ops,
48 .arch_ops = &sof_xtensa_arch_ops
49};
50#endif
51
52#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
53static const struct sof_dev_desc sof_acpi_broadwell_desc = {
54 .machines = snd_soc_acpi_intel_broadwell_machines,
55 .resindex_lpe_base = 0,
56 .resindex_pcicfg_base = 1,
57 .resindex_imr_base = -1,
58 .irqindex_host_ipc = 0,
59 .chip_info = &bdw_chip_info,
60 .default_fw_path = "intel/sof",
61 .default_tplg_path = "intel/sof-tplg",
62 .nocodec_fw_filename = "sof-bdw.ri",
63 .nocodec_tplg_filename = "sof-bdw-nocodec.tplg",
64 .ops = &sof_bdw_ops,
65 .arch_ops = &sof_xtensa_arch_ops
66};
67#endif
68
69#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
70
71/* BYTCR uses different IRQ index */
72static const struct sof_dev_desc sof_acpi_baytrailcr_desc = {
73 .machines = snd_soc_acpi_intel_baytrail_machines,
74 .resindex_lpe_base = 0,
75 .resindex_pcicfg_base = 1,
76 .resindex_imr_base = 2,
77 .irqindex_host_ipc = 0,
78 .chip_info = &byt_chip_info,
79 .default_fw_path = "intel/sof",
80 .default_tplg_path = "intel/sof-tplg",
81 .nocodec_fw_filename = "sof-byt.ri",
82 .nocodec_tplg_filename = "sof-byt-nocodec.tplg",
83 .ops = &sof_byt_ops,
84 .arch_ops = &sof_xtensa_arch_ops
85};
86
87static const struct sof_dev_desc sof_acpi_baytrail_desc = {
88 .machines = snd_soc_acpi_intel_baytrail_machines,
89 .resindex_lpe_base = 0,
90 .resindex_pcicfg_base = 1,
91 .resindex_imr_base = 2,
92 .irqindex_host_ipc = 5,
93 .chip_info = &byt_chip_info,
94 .default_fw_path = "intel/sof",
95 .default_tplg_path = "intel/sof-tplg",
96 .nocodec_fw_filename = "sof-byt.ri",
97 .nocodec_tplg_filename = "sof-byt-nocodec.tplg",
98 .ops = &sof_byt_ops,
99 .arch_ops = &sof_xtensa_arch_ops
100};
101
102#ifdef CONFIG_X86 /* TODO: move this to common helper */
103
104static bool is_byt_cr(struct platform_device *pdev)
105{
106 struct device *dev = &pdev->dev;
107 int status;
108
109 if (iosf_mbi_available()) {
110 u32 bios_status;
111 status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */
112 MBI_REG_READ, /* 0x10 */
113 0x006, /* BIOS_CONFIG */
114 &bios_status);
115
116 if (status) {
117 dev_err(dev, "could not read PUNIT BIOS_CONFIG\n");
118 } else {
119 /* bits 26:27 mirror PMIC options */
120 bios_status = (bios_status >> 26) & 3;
121
122 if (bios_status == 1 || bios_status == 3) {
123 dev_info(dev, "Detected Baytrail-CR platform\n");
124 return true;
125 }
126
127 dev_info(dev, "BYT-CR not detected\n");
128 }
129 } else {
130 dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n");
131 }
132
133 if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) {
134 /*
135 * Some devices detected as BYT-T have only a single IRQ listed,
136 * causing platform_get_irq with index 5 to return -ENXIO.
137 * The correct IRQ in this case is at index 0, as on BYT-CR.
138 */
139 dev_info(dev, "Falling back to Baytrail-CR platform\n");
140 return true;
141 }
142
143 return false;
144}
145#else
146static int is_byt_cr(struct platform_device *pdev)
147{
148 return 0;
149}
150#endif
151
152static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
153 .machines = snd_soc_acpi_intel_cherrytrail_machines,
154 .resindex_lpe_base = 0,
155 .resindex_pcicfg_base = 1,
156 .resindex_imr_base = 2,
157 .irqindex_host_ipc = 5,
158 .chip_info = &cht_chip_info,
159 .default_fw_path = "intel/sof",
160 .default_tplg_path = "intel/sof-tplg",
161 .nocodec_fw_filename = "sof-cht.ri",
162 .nocodec_tplg_filename = "sof-cht-nocodec.tplg",
163 .ops = &sof_cht_ops,
164 .arch_ops = &sof_xtensa_arch_ops
165};
166
167#endif
168
169static const struct dev_pm_ops sof_acpi_pm = {
170 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
171 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
172 NULL)
173};
174
175static void sof_acpi_probe_complete(struct device *dev)
176{
177 /* allow runtime_pm */
178 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
179 pm_runtime_use_autosuspend(dev);
180 pm_runtime_enable(dev);
181}
182
183static int sof_acpi_probe(struct platform_device *pdev)
184{
185 struct device *dev = &pdev->dev;
186 const struct sof_dev_desc *desc;
187 struct snd_soc_acpi_mach *mach;
188 struct snd_sof_pdata *sof_pdata;
189 const struct snd_sof_dsp_ops *ops;
190 int ret;
191
192 dev_dbg(&pdev->dev, "ACPI DSP detected");
193
194 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
195 if (!sof_pdata)
196 return -ENOMEM;
197
198 desc = device_get_match_data(dev);
199 if (!desc)
200 return -ENODEV;
201
202#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
203 if (desc == &sof_acpi_baytrail_desc && is_byt_cr(pdev))
204 desc = &sof_acpi_baytrailcr_desc;
205#endif
206
207 /* get ops for platform */
208 ops = desc->ops;
209 if (!ops) {
210 dev_err(dev, "error: no matching ACPI descriptor ops\n");
211 return -ENODEV;
212 }
213
214#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
215 /* force nocodec mode */
216 dev_warn(dev, "Force to use nocodec mode\n");
217 mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
218 if (!mach)
219 return -ENOMEM;
220 ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
221 if (ret < 0)
222 return ret;
223#else
224 /* find machine */
225 mach = snd_soc_acpi_find_machine(desc->machines);
226 if (!mach) {
227 dev_warn(dev, "warning: No matching ASoC machine driver found\n");
228 } else {
229 sof_pdata->fw_filename = mach->sof_fw_filename;
230 sof_pdata->tplg_filename = mach->sof_tplg_filename;
231 }
232#endif
233
234 if (mach) {
235 mach->mach_params.platform = dev_name(dev);
236 mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc;
237 }
238
239 sof_pdata->machine = mach;
240 sof_pdata->desc = desc;
241 sof_pdata->dev = &pdev->dev;
242 sof_pdata->platform = dev_name(dev);
243
244 /* alternate fw and tplg filenames ? */
245 if (fw_path)
246 sof_pdata->fw_filename_prefix = fw_path;
247 else
248 sof_pdata->fw_filename_prefix =
249 sof_pdata->desc->default_fw_path;
250
251 if (tplg_path)
252 sof_pdata->tplg_filename_prefix = tplg_path;
253 else
254 sof_pdata->tplg_filename_prefix =
255 sof_pdata->desc->default_tplg_path;
256
257#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
258 /* set callback to enable runtime_pm */
259 sof_pdata->sof_probe_complete = sof_acpi_probe_complete;
260#endif
261 /* call sof helper for DSP hardware probe */
262 ret = snd_sof_device_probe(dev, sof_pdata);
263 if (ret) {
264 dev_err(dev, "error: failed to probe DSP hardware!\n");
265 return ret;
266 }
267
268#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
269 sof_acpi_probe_complete(dev);
270#endif
271
272 return ret;
273}
274
275static int sof_acpi_remove(struct platform_device *pdev)
276{
277 pm_runtime_disable(&pdev->dev);
278
279 /* call sof helper for DSP hardware remove */
280 snd_sof_device_remove(&pdev->dev);
281
282 return 0;
283}
284
285static const struct acpi_device_id sof_acpi_match[] = {
286#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL)
287 { "INT33C8", (unsigned long)&sof_acpi_haswell_desc },
288#endif
289#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
290 { "INT3438", (unsigned long)&sof_acpi_broadwell_desc },
291#endif
292#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
293 { "80860F28", (unsigned long)&sof_acpi_baytrail_desc },
294 { "808622A8", (unsigned long)&sof_acpi_cherrytrail_desc },
295#endif
296 { }
297};
298MODULE_DEVICE_TABLE(acpi, sof_acpi_match);
299
300/* acpi_driver definition */
301static struct platform_driver snd_sof_acpi_driver = {
302 .probe = sof_acpi_probe,
303 .remove = sof_acpi_remove,
304 .driver = {
305 .name = "sof-audio-acpi",
306 .pm = &sof_acpi_pm,
307 .acpi_match_table = ACPI_PTR(sof_acpi_match),
308 },
309};
310module_platform_driver(snd_sof_acpi_driver);
311
312MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
new file mode 100644
index 000000000000..b778dffb2d25
--- /dev/null
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -0,0 +1,373 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/firmware.h>
12#include <linux/module.h>
13#include <linux/pci.h>
14#include <linux/pm_runtime.h>
15#include <sound/soc-acpi.h>
16#include <sound/soc-acpi-intel-match.h>
17#include <sound/sof.h>
18#include "ops.h"
19
20/* platform specific devices */
21#include "intel/shim.h"
22#include "intel/hda.h"
23
24static char *fw_path;
25module_param(fw_path, charp, 0444);
26MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
27
28static char *tplg_path;
29module_param(tplg_path, charp, 0444);
30MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
31
32#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
33static const struct sof_dev_desc bxt_desc = {
34 .machines = snd_soc_acpi_intel_bxt_machines,
35 .resindex_lpe_base = 0,
36 .resindex_pcicfg_base = -1,
37 .resindex_imr_base = -1,
38 .irqindex_host_ipc = -1,
39 .resindex_dma_base = -1,
40 .chip_info = &apl_chip_info,
41 .default_fw_path = "intel/sof",
42 .default_tplg_path = "intel/sof-tplg",
43 .nocodec_fw_filename = "sof-apl.ri",
44 .nocodec_tplg_filename = "sof-apl-nocodec.tplg",
45 .ops = &sof_apl_ops,
46 .arch_ops = &sof_xtensa_arch_ops
47};
48#endif
49
50#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
51static const struct sof_dev_desc glk_desc = {
52 .machines = snd_soc_acpi_intel_glk_machines,
53 .resindex_lpe_base = 0,
54 .resindex_pcicfg_base = -1,
55 .resindex_imr_base = -1,
56 .irqindex_host_ipc = -1,
57 .resindex_dma_base = -1,
58 .chip_info = &apl_chip_info,
59 .default_fw_path = "intel/sof",
60 .default_tplg_path = "intel/sof-tplg",
61 .nocodec_fw_filename = "sof-glk.ri",
62 .nocodec_tplg_filename = "sof-glk-nocodec.tplg",
63 .ops = &sof_apl_ops,
64 .arch_ops = &sof_xtensa_arch_ops
65};
66#endif
67
68#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
69static struct snd_soc_acpi_mach sof_tng_machines[] = {
70 {
71 .id = "INT343A",
72 .drv_name = "edison",
73 .sof_fw_filename = "sof-byt.ri",
74 .sof_tplg_filename = "sof-byt.tplg",
75 },
76 {}
77};
78
79static const struct sof_dev_desc tng_desc = {
80 .machines = sof_tng_machines,
81 .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */
82 .resindex_pcicfg_base = -1,
83 .resindex_imr_base = 0,
84 .irqindex_host_ipc = -1,
85 .resindex_dma_base = -1,
86 .chip_info = &tng_chip_info,
87 .default_fw_path = "intel/sof",
88 .default_tplg_path = "intel/sof-tplg",
89 .nocodec_fw_filename = "sof-byt.ri",
90 .nocodec_tplg_filename = "sof-byt.tplg",
91 .ops = &sof_tng_ops,
92 .arch_ops = &sof_xtensa_arch_ops
93};
94#endif
95
96#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
97static const struct sof_dev_desc cnl_desc = {
98 .machines = snd_soc_acpi_intel_cnl_machines,
99 .resindex_lpe_base = 0,
100 .resindex_pcicfg_base = -1,
101 .resindex_imr_base = -1,
102 .irqindex_host_ipc = -1,
103 .resindex_dma_base = -1,
104 .chip_info = &cnl_chip_info,
105 .default_fw_path = "intel/sof",
106 .default_tplg_path = "intel/sof-tplg",
107 .nocodec_fw_filename = "sof-cnl.ri",
108 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
109 .ops = &sof_cnl_ops,
110 .arch_ops = &sof_xtensa_arch_ops
111};
112#endif
113
114#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
115static const struct sof_dev_desc cfl_desc = {
116 .machines = snd_soc_acpi_intel_cnl_machines,
117 .resindex_lpe_base = 0,
118 .resindex_pcicfg_base = -1,
119 .resindex_imr_base = -1,
120 .irqindex_host_ipc = -1,
121 .resindex_dma_base = -1,
122 .chip_info = &cnl_chip_info,
123 .default_fw_path = "intel/sof",
124 .default_tplg_path = "intel/sof-tplg",
125 .nocodec_fw_filename = "sof-cnl.ri",
126 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
127 .ops = &sof_cnl_ops,
128 .arch_ops = &sof_xtensa_arch_ops
129};
130#endif
131
132#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
133static const struct sof_dev_desc icl_desc = {
134 .machines = snd_soc_acpi_intel_icl_machines,
135 .resindex_lpe_base = 0,
136 .resindex_pcicfg_base = -1,
137 .resindex_imr_base = -1,
138 .irqindex_host_ipc = -1,
139 .resindex_dma_base = -1,
140 .chip_info = &cnl_chip_info,
141 .default_fw_path = "intel/sof",
142 .default_tplg_path = "intel/sof-tplg",
143 .nocodec_fw_filename = "sof-icl.ri",
144 .nocodec_tplg_filename = "sof-icl-nocodec.tplg",
145 .ops = &sof_cnl_ops,
146 .arch_ops = &sof_xtensa_arch_ops
147};
148#endif
149
150#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE)
151static const struct sof_dev_desc skl_desc = {
152 .machines = snd_soc_acpi_intel_skl_machines,
153 .resindex_lpe_base = 0,
154 .resindex_pcicfg_base = -1,
155 .resindex_imr_base = -1,
156 .irqindex_host_ipc = -1,
157 .resindex_dma_base = -1,
158 .chip_info = &skl_chip_info,
159 .default_fw_path = "intel/sof",
160 .default_tplg_path = "intel/sof-tplg",
161 .nocodec_fw_filename = "sof-skl.ri",
162 .nocodec_tplg_filename = "sof-skl-nocodec.tplg",
163 .ops = &sof_skl_ops,
164 .arch_ops = &sof_xtensa_arch_ops
165};
166#endif
167
168#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE)
169static const struct sof_dev_desc kbl_desc = {
170 .machines = snd_soc_acpi_intel_kbl_machines,
171 .resindex_lpe_base = 0,
172 .resindex_pcicfg_base = -1,
173 .resindex_imr_base = -1,
174 .irqindex_host_ipc = -1,
175 .resindex_dma_base = -1,
176 .chip_info = &skl_chip_info,
177 .default_fw_path = "intel/sof",
178 .default_tplg_path = "intel/sof-tplg",
179 .nocodec_fw_filename = "sof-kbl.ri",
180 .nocodec_tplg_filename = "sof-kbl-nocodec.tplg",
181 .ops = &sof_skl_ops,
182 .arch_ops = &sof_xtensa_arch_ops
183};
184#endif
185
186static const struct dev_pm_ops sof_pci_pm = {
187 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
188 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
189 NULL)
190};
191
192static void sof_pci_probe_complete(struct device *dev)
193{
194 dev_dbg(dev, "Completing SOF PCI probe");
195
196 /* allow runtime_pm */
197 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
198 pm_runtime_use_autosuspend(dev);
199
200 /*
201 * runtime pm for pci device is "forbidden" by default.
202 * so call pm_runtime_allow() to enable it.
203 */
204 pm_runtime_allow(dev);
205
206 /* follow recommendation in pci-driver.c to decrement usage counter */
207 pm_runtime_put_noidle(dev);
208}
209
210static int sof_pci_probe(struct pci_dev *pci,
211 const struct pci_device_id *pci_id)
212{
213 struct device *dev = &pci->dev;
214 const struct sof_dev_desc *desc =
215 (const struct sof_dev_desc *)pci_id->driver_data;
216 struct snd_soc_acpi_mach *mach;
217 struct snd_sof_pdata *sof_pdata;
218 const struct snd_sof_dsp_ops *ops;
219 int ret;
220
221 dev_dbg(&pci->dev, "PCI DSP detected");
222
223 /* get ops for platform */
224 ops = desc->ops;
225 if (!ops) {
226 dev_err(dev, "error: no matching PCI descriptor ops\n");
227 return -ENODEV;
228 }
229
230 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
231 if (!sof_pdata)
232 return -ENOMEM;
233
234 ret = pcim_enable_device(pci);
235 if (ret < 0)
236 return ret;
237
238 ret = pci_request_regions(pci, "Audio DSP");
239 if (ret < 0)
240 return ret;
241
242#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
243 /* force nocodec mode */
244 dev_warn(dev, "Force to use nocodec mode\n");
245 mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
246 if (!mach) {
247 ret = -ENOMEM;
248 goto release_regions;
249 }
250 ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
251 if (ret < 0)
252 goto release_regions;
253
254#else
255 /* find machine */
256 mach = snd_soc_acpi_find_machine(desc->machines);
257 if (!mach) {
258 dev_warn(dev, "warning: No matching ASoC machine driver found\n");
259 } else {
260 mach->mach_params.platform = dev_name(dev);
261 sof_pdata->fw_filename = mach->sof_fw_filename;
262 sof_pdata->tplg_filename = mach->sof_tplg_filename;
263 }
264#endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */
265
266 sof_pdata->name = pci_name(pci);
267 sof_pdata->machine = mach;
268 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data;
269 sof_pdata->dev = dev;
270 sof_pdata->platform = dev_name(dev);
271
272 /* alternate fw and tplg filenames ? */
273 if (fw_path)
274 sof_pdata->fw_filename_prefix = fw_path;
275 else
276 sof_pdata->fw_filename_prefix =
277 sof_pdata->desc->default_fw_path;
278
279 if (tplg_path)
280 sof_pdata->tplg_filename_prefix = tplg_path;
281 else
282 sof_pdata->tplg_filename_prefix =
283 sof_pdata->desc->default_tplg_path;
284
285#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
286 /* set callback to enable runtime_pm */
287 sof_pdata->sof_probe_complete = sof_pci_probe_complete;
288#endif
289 /* call sof helper for DSP hardware probe */
290 ret = snd_sof_device_probe(dev, sof_pdata);
291 if (ret) {
292 dev_err(dev, "error: failed to probe DSP hardware!\n");
293 goto release_regions;
294 }
295
296#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
297 sof_pci_probe_complete(dev);
298#endif
299
300 return ret;
301
302release_regions:
303 pci_release_regions(pci);
304
305 return ret;
306}
307
308static void sof_pci_remove(struct pci_dev *pci)
309{
310 /* call sof helper for DSP hardware remove */
311 snd_sof_device_remove(&pci->dev);
312
313 /* follow recommendation in pci-driver.c to increment usage counter */
314 pm_runtime_get_noresume(&pci->dev);
315
316 /* release pci regions and disable device */
317 pci_release_regions(pci);
318}
319
320/* PCI IDs */
321static const struct pci_device_id sof_pci_ids[] = {
322#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
323 { PCI_DEVICE(0x8086, 0x119a),
324 .driver_data = (unsigned long)&tng_desc},
325#endif
326#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
327 /* BXT-P & Apollolake */
328 { PCI_DEVICE(0x8086, 0x5a98),
329 .driver_data = (unsigned long)&bxt_desc},
330 { PCI_DEVICE(0x8086, 0x1a98),
331 .driver_data = (unsigned long)&bxt_desc},
332#endif
333#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
334 { PCI_DEVICE(0x8086, 0x3198),
335 .driver_data = (unsigned long)&glk_desc},
336#endif
337#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
338 { PCI_DEVICE(0x8086, 0x9dc8),
339 .driver_data = (unsigned long)&cnl_desc},
340#endif
341#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
342 { PCI_DEVICE(0x8086, 0xa348),
343 .driver_data = (unsigned long)&cfl_desc},
344#endif
345#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE)
346 { PCI_DEVICE(0x8086, 0x9d71),
347 .driver_data = (unsigned long)&kbl_desc},
348#endif
349#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE)
350 { PCI_DEVICE(0x8086, 0x9d70),
351 .driver_data = (unsigned long)&skl_desc},
352#endif
353#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
354 { PCI_DEVICE(0x8086, 0x34C8),
355 .driver_data = (unsigned long)&icl_desc},
356#endif
357 { 0, }
358};
359MODULE_DEVICE_TABLE(pci, sof_pci_ids);
360
361/* pci_driver definition */
362static struct pci_driver snd_sof_pci_driver = {
363 .name = "sof-audio-pci",
364 .id_table = sof_pci_ids,
365 .probe = sof_pci_probe,
366 .remove = sof_pci_remove,
367 .driver = {
368 .pm = &sof_pci_pm,
369 },
370};
371module_pci_driver(snd_sof_pci_driver);
372
373MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
new file mode 100644
index 000000000000..1e85d6f9c5c3
--- /dev/null
+++ b/sound/soc/sof/sof-priv.h
@@ -0,0 +1,635 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
2/*
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * Copyright(c) 2018 Intel Corporation. All rights reserved.
7 *
8 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 */
10
11#ifndef __SOUND_SOC_SOF_PRIV_H
12#define __SOUND_SOC_SOF_PRIV_H
13
14#include <linux/device.h>
15
16#include <sound/hdaudio.h>
17#include <sound/soc.h>
18
19#include <sound/sof.h>
20#include <sound/sof/stream.h> /* needs to be included before control.h */
21#include <sound/sof/control.h>
22#include <sound/sof/dai.h>
23#include <sound/sof/info.h>
24#include <sound/sof/pm.h>
25#include <sound/sof/topology.h>
26#include <sound/sof/trace.h>
27
28#include <uapi/sound/sof/fw.h>
29
30/* debug flags */
31#define SOF_DBG_REGS BIT(1)
32#define SOF_DBG_MBOX BIT(2)
33#define SOF_DBG_TEXT BIT(3)
34#define SOF_DBG_PCI BIT(4)
35
36/* max BARs mmaped devices can use */
37#define SND_SOF_BARS 8
38
39/* time in ms for runtime suspend delay */
40#define SND_SOF_SUSPEND_DELAY_MS 2000
41
42/* DMA buffer size for trace */
43#define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16)
44
45/* max number of FE PCMs before BEs */
46#define SOF_BE_PCM_BASE 16
47
48#define SOF_IPC_DSP_REPLY 0
49#define SOF_IPC_HOST_REPLY 1
50
51/* convenience constructor for DAI driver streams */
52#define SOF_DAI_STREAM(sname, scmin, scmax, srates, sfmt) \
53 {.stream_name = sname, .channels_min = scmin, .channels_max = scmax, \
54 .rates = srates, .formats = sfmt}
55
56#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
57 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT)
58
59struct snd_sof_dev;
60struct snd_sof_ipc_msg;
61struct snd_sof_ipc;
62struct snd_sof_debugfs_map;
63struct snd_soc_tplg_ops;
64struct snd_soc_component;
65struct snd_sof_pdata;
66
67/*
68 * SOF DSP HW abstraction operations.
69 * Used to abstract DSP HW architecture and any IO busses between host CPU
70 * and DSP device(s).
71 */
72struct snd_sof_dsp_ops {
73
74 /* probe and remove */
75 int (*probe)(struct snd_sof_dev *sof_dev); /* mandatory */
76 int (*remove)(struct snd_sof_dev *sof_dev); /* optional */
77
78 /* DSP core boot / reset */
79 int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */
80 int (*stall)(struct snd_sof_dev *sof_dev); /* optional */
81 int (*reset)(struct snd_sof_dev *sof_dev); /* optional */
82 int (*core_power_up)(struct snd_sof_dev *sof_dev,
83 unsigned int core_mask); /* optional */
84 int (*core_power_down)(struct snd_sof_dev *sof_dev,
85 unsigned int core_mask); /* optional */
86
87 /*
88 * Register IO: only used by respective drivers themselves,
89 * TODO: consider removing these operations and calling respective
90 * implementations directly
91 */
92 void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr,
93 u32 value); /* optional */
94 u32 (*read)(struct snd_sof_dev *sof_dev,
95 void __iomem *addr); /* optional */
96 void (*write64)(struct snd_sof_dev *sof_dev, void __iomem *addr,
97 u64 value); /* optional */
98 u64 (*read64)(struct snd_sof_dev *sof_dev,
99 void __iomem *addr); /* optional */
100
101 /* memcpy IO */
102 void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar,
103 u32 offset, void *dest,
104 size_t size); /* mandatory */
105 void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar,
106 u32 offset, void *src,
107 size_t size); /* mandatory */
108
109 /* doorbell */
110 irqreturn_t (*irq_handler)(int irq, void *context); /* optional */
111 irqreturn_t (*irq_thread)(int irq, void *context); /* optional */
112
113 /* ipc */
114 int (*send_msg)(struct snd_sof_dev *sof_dev,
115 struct snd_sof_ipc_msg *msg); /* mandatory */
116
117 /* FW loading */
118 int (*load_firmware)(struct snd_sof_dev *sof_dev); /* mandatory */
119 int (*load_module)(struct snd_sof_dev *sof_dev,
120 struct snd_sof_mod_hdr *hdr); /* optional */
121 /*
122 * FW ready checks for ABI compatibility and creates
123 * memory windows at first boot
124 */
125 int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* optional */
126
127 /* connect pcm substream to a host stream */
128 int (*pcm_open)(struct snd_sof_dev *sdev,
129 struct snd_pcm_substream *substream); /* optional */
130 /* disconnect pcm substream to a host stream */
131 int (*pcm_close)(struct snd_sof_dev *sdev,
132 struct snd_pcm_substream *substream); /* optional */
133
134 /* host stream hw params */
135 int (*pcm_hw_params)(struct snd_sof_dev *sdev,
136 struct snd_pcm_substream *substream,
137 struct snd_pcm_hw_params *params,
138 struct sof_ipc_stream_params *ipc_params); /* optional */
139
140 /* host stream trigger */
141 int (*pcm_trigger)(struct snd_sof_dev *sdev,
142 struct snd_pcm_substream *substream,
143 int cmd); /* optional */
144
145 /* host stream pointer */
146 snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev,
147 struct snd_pcm_substream *substream); /* optional */
148
149 /* host read DSP stream data */
150 void (*ipc_msg_data)(struct snd_sof_dev *sdev,
151 struct snd_pcm_substream *substream,
152 void *p, size_t sz); /* mandatory */
153
154 /* host configure DSP HW parameters */
155 int (*ipc_pcm_params)(struct snd_sof_dev *sdev,
156 struct snd_pcm_substream *substream,
157 const struct sof_ipc_pcm_params_reply *reply); /* mandatory */
158
159 /* pre/post firmware run */
160 int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
161 int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */
162
163 /* DSP PM */
164 int (*suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */
165 int (*resume)(struct snd_sof_dev *sof_dev); /* optional */
166 int (*runtime_suspend)(struct snd_sof_dev *sof_dev,
167 int state); /* optional */
168 int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */
169 void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
170
171 /* DSP clocking */
172 int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */
173
174 /* debug */
175 const struct snd_sof_debugfs_map *debug_map; /* optional */
176 int debug_map_count; /* optional */
177 void (*dbg_dump)(struct snd_sof_dev *sof_dev,
178 u32 flags); /* optional */
179 void (*ipc_dump)(struct snd_sof_dev *sof_dev); /* optional */
180
181 /* host DMA trace initialization */
182 int (*trace_init)(struct snd_sof_dev *sdev,
183 u32 *stream_tag); /* optional */
184 int (*trace_release)(struct snd_sof_dev *sdev); /* optional */
185 int (*trace_trigger)(struct snd_sof_dev *sdev,
186 int cmd); /* optional */
187
188 /* DAI ops */
189 struct snd_soc_dai_driver *drv;
190 int num_drv;
191};
192
193/* DSP architecture specific callbacks for oops and stack dumps */
194struct sof_arch_ops {
195 void (*dsp_oops)(struct snd_sof_dev *sdev, void *oops);
196 void (*dsp_stack)(struct snd_sof_dev *sdev, void *oops,
197 u32 *stack, u32 stack_words);
198};
199
200#define sof_arch_ops(sdev) ((sdev)->pdata->desc->arch_ops)
201
202/* DSP device HW descriptor mapping between bus ID and ops */
203struct sof_ops_table {
204 const struct sof_dev_desc *desc;
205 const struct snd_sof_dsp_ops *ops;
206};
207
208enum sof_dfsentry_type {
209 SOF_DFSENTRY_TYPE_IOMEM = 0,
210 SOF_DFSENTRY_TYPE_BUF,
211};
212
213enum sof_debugfs_access_type {
214 SOF_DEBUGFS_ACCESS_ALWAYS = 0,
215 SOF_DEBUGFS_ACCESS_D0_ONLY,
216};
217
218/* FS entry for debug files that can expose DSP memories, registers */
219struct snd_sof_dfsentry {
220 struct dentry *dfsentry;
221 size_t size;
222 enum sof_dfsentry_type type;
223 /*
224 * access_type specifies if the
225 * memory -> DSP resource (memory, register etc) is always accessible
226 * or if it is accessible only when the DSP is in D0.
227 */
228 enum sof_debugfs_access_type access_type;
229#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
230 char *cache_buf; /* buffer to cache the contents of debugfs memory */
231#endif
232 struct snd_sof_dev *sdev;
233 struct list_head list; /* list in sdev dfsentry list */
234 union {
235 void __iomem *io_mem;
236 void *buf;
237 };
238};
239
240/* Debug mapping for any DSP memory or registers that can used for debug */
241struct snd_sof_debugfs_map {
242 const char *name;
243 u32 bar;
244 u32 offset;
245 u32 size;
246 /*
247 * access_type specifies if the memory is always accessible
248 * or if it is accessible only when the DSP is in D0.
249 */
250 enum sof_debugfs_access_type access_type;
251};
252
253/* mailbox descriptor, used for host <-> DSP IPC */
254struct snd_sof_mailbox {
255 u32 offset;
256 size_t size;
257};
258
259/* IPC message descriptor for host <-> DSP IO */
260struct snd_sof_ipc_msg {
261 /* message data */
262 u32 header;
263 void *msg_data;
264 void *reply_data;
265 size_t msg_size;
266 size_t reply_size;
267 int reply_error;
268
269 wait_queue_head_t waitq;
270 bool ipc_complete;
271};
272
273/* PCM stream, mapped to FW component */
274struct snd_sof_pcm_stream {
275 u32 comp_id;
276 struct snd_dma_buffer page_table;
277 struct sof_ipc_stream_posn posn;
278 struct snd_pcm_substream *substream;
279 struct work_struct period_elapsed_work;
280};
281
282/* ALSA SOF PCM device */
283struct snd_sof_pcm {
284 struct snd_sof_dev *sdev;
285 struct snd_soc_tplg_pcm pcm;
286 struct snd_sof_pcm_stream stream[2];
287 struct list_head list; /* list in sdev pcm list */
288 struct snd_pcm_hw_params params[2];
289 int hw_params_upon_resume[2]; /* set up hw_params upon resume */
290};
291
292/* ALSA SOF Kcontrol device */
293struct snd_sof_control {
294 struct snd_sof_dev *sdev;
295 int comp_id;
296 int num_channels;
297 u32 readback_offset; /* offset to mmaped data if used */
298 struct sof_ipc_ctrl_data *control_data;
299 u32 size; /* cdata size */
300 enum sof_ipc_ctrl_cmd cmd;
301 u32 *volume_table; /* volume table computed from tlv data*/
302
303 struct list_head list; /* list in sdev control list */
304};
305
306/* ASoC SOF DAPM widget */
307struct snd_sof_widget {
308 struct snd_sof_dev *sdev;
309 int comp_id;
310 int pipeline_id;
311 int complete;
312 int id;
313
314 struct snd_soc_dapm_widget *widget;
315 struct list_head list; /* list in sdev widget list */
316
317 void *private; /* core does not touch this */
318};
319
320/* ASoC SOF DAPM route */
321struct snd_sof_route {
322 struct snd_sof_dev *sdev;
323
324 struct snd_soc_dapm_route *route;
325 struct list_head list; /* list in sdev route list */
326
327 void *private;
328};
329
330/* ASoC DAI device */
331struct snd_sof_dai {
332 struct snd_sof_dev *sdev;
333 const char *name;
334
335 struct sof_ipc_comp_dai comp_dai;
336 struct sof_ipc_dai_config *dai_config;
337 struct list_head list; /* list in sdev dai list */
338};
339
340/*
341 * SOF Device Level.
342 */
343struct snd_sof_dev {
344 struct device *dev;
345 spinlock_t ipc_lock; /* lock for IPC users */
346 spinlock_t hw_lock; /* lock for HW IO access */
347
348 /*
349 * ASoC components. plat_drv fields are set dynamically so
350 * can't use const
351 */
352 struct snd_soc_component_driver plat_drv;
353
354 /* DSP firmware boot */
355 wait_queue_head_t boot_wait;
356 u32 boot_complete;
357 u32 first_boot;
358
359 /* work queue in case the probe is implemented in two steps */
360 struct work_struct probe_work;
361
362 /* DSP HW differentiation */
363 struct snd_sof_pdata *pdata;
364
365 /* IPC */
366 struct snd_sof_ipc *ipc;
367 struct snd_sof_mailbox dsp_box; /* DSP initiated IPC */
368 struct snd_sof_mailbox host_box; /* Host initiated IPC */
369 struct snd_sof_mailbox stream_box; /* Stream position update */
370 struct snd_sof_ipc_msg *msg;
371 int ipc_irq;
372 u32 next_comp_id; /* monotonic - reset during S3 */
373
374 /* memory bases for mmaped DSPs - set by dsp_init() */
375 void __iomem *bar[SND_SOF_BARS]; /* DSP base address */
376 int mmio_bar;
377 int mailbox_bar;
378 size_t dsp_oops_offset;
379
380 /* debug */
381 struct dentry *debugfs_root;
382 struct list_head dfsentry_list;
383
384 /* firmware loader */
385 struct snd_dma_buffer dmab;
386 struct snd_dma_buffer dmab_bdl;
387 struct sof_ipc_fw_ready fw_ready;
388 struct sof_ipc_fw_version fw_version;
389
390 /* topology */
391 struct snd_soc_tplg_ops *tplg_ops;
392 struct list_head pcm_list;
393 struct list_head kcontrol_list;
394 struct list_head widget_list;
395 struct list_head dai_list;
396 struct list_head route_list;
397 struct snd_soc_component *component;
398 u32 enabled_cores_mask; /* keep track of enabled cores */
399
400 /* FW configuration */
401 struct sof_ipc_dma_buffer_data *info_buffer;
402 struct sof_ipc_window *info_window;
403
404 /* IPC timeouts in ms */
405 int ipc_timeout;
406 int boot_timeout;
407
408 /* Wait queue for code loading */
409 wait_queue_head_t waitq;
410 int code_loading;
411
412 /* DMA for Trace */
413 struct snd_dma_buffer dmatb;
414 struct snd_dma_buffer dmatp;
415 int dma_trace_pages;
416 wait_queue_head_t trace_sleep;
417 u32 host_offset;
418 u32 dtrace_is_enabled;
419 u32 dtrace_error;
420 u32 msi_enabled;
421
422 void *private; /* core does not touch this */
423};
424
425/*
426 * Device Level.
427 */
428
429int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data);
430int snd_sof_device_remove(struct device *dev);
431
432int snd_sof_runtime_suspend(struct device *dev);
433int snd_sof_runtime_resume(struct device *dev);
434int snd_sof_resume(struct device *dev);
435int snd_sof_suspend(struct device *dev);
436
437void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
438
439int snd_sof_create_page_table(struct snd_sof_dev *sdev,
440 struct snd_dma_buffer *dmab,
441 unsigned char *page_table, size_t size);
442
443/*
444 * Firmware loading.
445 */
446int snd_sof_load_firmware(struct snd_sof_dev *sdev);
447int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev);
448int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev);
449int snd_sof_run_firmware(struct snd_sof_dev *sdev);
450int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
451 struct snd_sof_mod_hdr *module);
452void snd_sof_fw_unload(struct snd_sof_dev *sdev);
453int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset);
454
455/*
456 * IPC low level APIs.
457 */
458struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev);
459void snd_sof_ipc_free(struct snd_sof_dev *sdev);
460int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id);
461void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev);
462int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev,
463 struct sof_ipc_pcm_params *params);
464int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox,
465 size_t dspbox_size, u32 hostbox,
466 size_t hostbox_size);
467int snd_sof_ipc_valid(struct snd_sof_dev *sdev);
468int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
469 void *msg_data, size_t msg_bytes, void *reply_data,
470 size_t reply_bytes);
471struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
472 const char *name);
473struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
474 const char *pcm_name,
475 int dir);
476struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
477 const char *name);
478
479static inline
480struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev,
481 struct snd_soc_pcm_runtime *rtd)
482{
483 struct snd_sof_pcm *spcm = NULL;
484
485 list_for_each_entry(spcm, &sdev->pcm_list, list) {
486 if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id)
487 return spcm;
488 }
489
490 return NULL;
491}
492
493struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
494 const char *name);
495struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
496 unsigned int comp_id,
497 int *direction);
498struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
499 unsigned int pcm_id);
500void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
501
502/*
503 * Stream IPC
504 */
505int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
506 struct snd_sof_pcm *spcm, int direction,
507 struct sof_ipc_stream_posn *posn);
508
509/*
510 * Mixer IPC
511 */
512int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
513 struct snd_sof_control *scontrol, u32 ipc_cmd,
514 enum sof_ipc_ctrl_type ctrl_type,
515 enum sof_ipc_ctrl_cmd ctrl_cmd,
516 bool send);
517
518/*
519 * Topology.
520 * There is no snd_sof_free_topology since topology components will
521 * be freed by snd_soc_unregister_component,
522 */
523int snd_sof_init_topology(struct snd_sof_dev *sdev,
524 struct snd_soc_tplg_ops *ops);
525int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file);
526int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
527 struct snd_sof_widget *swidget);
528
529int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
530 struct sof_ipc_pipe_new *pipeline,
531 struct sof_ipc_comp_reply *r);
532
533/*
534 * Trace/debug
535 */
536int snd_sof_init_trace(struct snd_sof_dev *sdev);
537void snd_sof_release_trace(struct snd_sof_dev *sdev);
538void snd_sof_free_trace(struct snd_sof_dev *sdev);
539int snd_sof_dbg_init(struct snd_sof_dev *sdev);
540void snd_sof_free_debug(struct snd_sof_dev *sdev);
541int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev,
542 void __iomem *base, size_t size,
543 const char *name,
544 enum sof_debugfs_access_type access_type);
545int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
546 void *base, size_t size,
547 const char *name);
548int snd_sof_trace_update_pos(struct snd_sof_dev *sdev,
549 struct sof_ipc_dma_trace_posn *posn);
550void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev);
551void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code,
552 u32 tracep_code, void *oops,
553 struct sof_ipc_panic_info *panic_info,
554 void *stack, size_t stack_words);
555int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev);
556
557/*
558 * Platform specific ops.
559 */
560extern struct snd_compr_ops sof_compressed_ops;
561
562/*
563 * Kcontrols.
564 */
565
566int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
567 struct snd_ctl_elem_value *ucontrol);
568int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
569 struct snd_ctl_elem_value *ucontrol);
570int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
571 struct snd_ctl_elem_value *ucontrol);
572int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
573 struct snd_ctl_elem_value *ucontrol);
574int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
575 struct snd_ctl_elem_value *ucontrol);
576int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
577 struct snd_ctl_elem_value *ucontrol);
578int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
579 struct snd_ctl_elem_value *ucontrol);
580int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
581 struct snd_ctl_elem_value *ucontrol);
582int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
583 const unsigned int __user *binary_data,
584 unsigned int size);
585int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
586 unsigned int __user *binary_data,
587 unsigned int size);
588
589/*
590 * DSP Architectures.
591 */
592static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
593 u32 stack_words)
594{
595 if (sof_arch_ops(sdev)->dsp_stack)
596 sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words);
597}
598
599static inline void sof_oops(struct snd_sof_dev *sdev, void *oops)
600{
601 if (sof_arch_ops(sdev)->dsp_oops)
602 sof_arch_ops(sdev)->dsp_oops(sdev, oops);
603}
604
605extern const struct sof_arch_ops sof_xtensa_arch_ops;
606
607/*
608 * Utilities
609 */
610void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value);
611void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value);
612u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr);
613u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr);
614void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset,
615 void *message, size_t bytes);
616void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset,
617 void *message, size_t bytes);
618void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src,
619 size_t size);
620void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest,
621 size_t size);
622
623void intel_ipc_msg_data(struct snd_sof_dev *sdev,
624 struct snd_pcm_substream *substream,
625 void *p, size_t sz);
626int intel_ipc_pcm_params(struct snd_sof_dev *sdev,
627 struct snd_pcm_substream *substream,
628 const struct sof_ipc_pcm_params_reply *reply);
629
630int intel_pcm_open(struct snd_sof_dev *sdev,
631 struct snd_pcm_substream *substream);
632int intel_pcm_close(struct snd_sof_dev *sdev,
633 struct snd_pcm_substream *substream);
634
635#endif
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
new file mode 100644
index 000000000000..c88afa872a58
--- /dev/null
+++ b/sound/soc/sof/topology.c
@@ -0,0 +1,3179 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/firmware.h>
12#include <sound/tlv.h>
13#include <sound/pcm_params.h>
14#include <uapi/sound/sof/tokens.h>
15#include "sof-priv.h"
16#include "ops.h"
17
18#define COMP_ID_UNASSIGNED 0xffffffff
19/*
20 * Constants used in the computation of linear volume gain
21 * from dB gain 20th root of 10 in Q1.16 fixed-point notation
22 */
23#define VOL_TWENTIETH_ROOT_OF_TEN 73533
24/* 40th root of 10 in Q1.16 fixed-point notation*/
25#define VOL_FORTIETH_ROOT_OF_TEN 69419
26/*
27 * Volume fractional word length define to 16 sets
28 * the volume linear gain value to use Qx.16 format
29 */
30#define VOLUME_FWL 16
31/* 0.5 dB step value in topology TLV */
32#define VOL_HALF_DB_STEP 50
33/* Full volume for default values */
34#define VOL_ZERO_DB BIT(VOLUME_FWL)
35
36/* TLV data items */
37#define TLV_ITEMS 3
38#define TLV_MIN 0
39#define TLV_STEP 1
40#define TLV_MUTE 2
41
42/* size of tplg abi in byte */
43#define SOF_TPLG_ABI_SIZE 3
44
45/* send pcm params ipc */
46static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
47{
48 struct sof_ipc_pcm_params_reply ipc_params_reply;
49 struct snd_sof_dev *sdev = swidget->sdev;
50 struct sof_ipc_pcm_params pcm;
51 struct snd_pcm_hw_params *params;
52 struct snd_sof_pcm *spcm;
53 int ret = 0;
54
55 memset(&pcm, 0, sizeof(pcm));
56
57 /* get runtime PCM params using widget's stream name */
58 spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname);
59 if (!spcm) {
60 dev_err(sdev->dev, "error: cannot find PCM for %s\n",
61 swidget->widget->name);
62 return -EINVAL;
63 }
64
65 params = &spcm->params[dir];
66
67 /* set IPC PCM params */
68 pcm.hdr.size = sizeof(pcm);
69 pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
70 pcm.comp_id = swidget->comp_id;
71 pcm.params.hdr.size = sizeof(pcm.params);
72 pcm.params.direction = dir;
73 pcm.params.sample_valid_bytes = params_width(params) >> 3;
74 pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
75 pcm.params.rate = params_rate(params);
76 pcm.params.channels = params_channels(params);
77 pcm.params.host_period_bytes = params_period_bytes(params);
78
79 /* set format */
80 switch (params_format(params)) {
81 case SNDRV_PCM_FORMAT_S16:
82 pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
83 break;
84 case SNDRV_PCM_FORMAT_S24:
85 pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
86 break;
87 case SNDRV_PCM_FORMAT_S32:
88 pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
89 break;
90 default:
91 return -EINVAL;
92 }
93
94 /* send IPC to the DSP */
95 ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
96 &ipc_params_reply, sizeof(ipc_params_reply));
97 if (ret < 0)
98 dev_err(sdev->dev, "error: pcm params failed for %s\n",
99 swidget->widget->name);
100
101 return ret;
102}
103
104 /* send stream trigger ipc */
105static int ipc_trigger(struct snd_sof_widget *swidget, int cmd)
106{
107 struct snd_sof_dev *sdev = swidget->sdev;
108 struct sof_ipc_stream stream;
109 struct sof_ipc_reply reply;
110 int ret = 0;
111
112 /* set IPC stream params */
113 stream.hdr.size = sizeof(stream);
114 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
115 stream.comp_id = swidget->comp_id;
116
117 /* send IPC to the DSP */
118 ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
119 sizeof(stream), &reply, sizeof(reply));
120 if (ret < 0)
121 dev_err(sdev->dev, "error: failed to trigger %s\n",
122 swidget->widget->name);
123
124 return ret;
125}
126
127static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
128 struct snd_kcontrol *k, int event)
129{
130 struct snd_sof_widget *swidget = w->dobj.private;
131 struct snd_sof_dev *sdev;
132 int ret = 0;
133
134 if (!swidget)
135 return 0;
136
137 sdev = swidget->sdev;
138
139 dev_dbg(sdev->dev, "received event %d for widget %s\n",
140 event, w->name);
141
142 /* process events */
143 switch (event) {
144 case SND_SOC_DAPM_PRE_PMU:
145 /* set pcm params */
146 ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE);
147 if (ret < 0) {
148 dev_err(sdev->dev,
149 "error: failed to set pcm params for widget %s\n",
150 swidget->widget->name);
151 break;
152 }
153
154 /* start trigger */
155 ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
156 if (ret < 0)
157 dev_err(sdev->dev,
158 "error: failed to trigger widget %s\n",
159 swidget->widget->name);
160 break;
161 case SND_SOC_DAPM_POST_PMD:
162 /* stop trigger */
163 ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
164 if (ret < 0)
165 dev_err(sdev->dev,
166 "error: failed to trigger widget %s\n",
167 swidget->widget->name);
168
169 /* pcm free */
170 ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
171 if (ret < 0)
172 dev_err(sdev->dev,
173 "error: failed to trigger widget %s\n",
174 swidget->widget->name);
175 break;
176 default:
177 break;
178 }
179
180 return ret;
181}
182
183/* event handlers for keyword detect component */
184static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
185 {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event},
186};
187
188static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS])
189{
190 /* we only support dB scale TLV type at the moment */
191 if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE)
192 return -EINVAL;
193
194 /* min value in topology tlv data is multiplied by 100 */
195 tlv[TLV_MIN] = (int)p[SNDRV_CTL_TLVO_DB_SCALE_MIN] / 100;
196
197 /* volume steps */
198 tlv[TLV_STEP] = (int)(p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
199 TLV_DB_SCALE_MASK);
200
201 /* mute ON/OFF */
202 if ((p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] &
203 TLV_DB_SCALE_MUTE) == 0)
204 tlv[TLV_MUTE] = 0;
205 else
206 tlv[TLV_MUTE] = 1;
207
208 return 0;
209}
210
211/*
212 * Function to truncate an unsigned 64-bit number
213 * by x bits and return 32-bit unsigned number. This
214 * function also takes care of rounding while truncating
215 */
216static inline u32 vol_shift_64(u64 i, u32 x)
217{
218 /* do not truncate more than 32 bits */
219 if (x > 32)
220 x = 32;
221
222 if (x == 0)
223 return (u32)i;
224
225 return (u32)(((i >> (x - 1)) + 1) >> 1);
226}
227
228/*
229 * Function to compute a ^ exp where,
230 * a is a fractional number represented by a fixed-point
231 * integer with a fractional world length of "fwl"
232 * exp is an integer
233 * fwl is the fractional word length
234 * Return value is a fractional number represented by a
235 * fixed-point integer with a fractional word length of "fwl"
236 */
237static u32 vol_pow32(u32 a, int exp, u32 fwl)
238{
239 int i, iter;
240 u32 power = 1 << fwl;
241 u64 numerator;
242
243 /* if exponent is 0, return 1 */
244 if (exp == 0)
245 return power;
246
247 /* determine the number of iterations based on the exponent */
248 if (exp < 0)
249 iter = exp * -1;
250 else
251 iter = exp;
252
253 /* mutiply a "iter" times to compute power */
254 for (i = 0; i < iter; i++) {
255 /*
256 * Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl
257 * Truncate product back to fwl fractional bits with rounding
258 */
259 power = vol_shift_64((u64)power * a, fwl);
260 }
261
262 if (exp > 0) {
263 /* if exp is positive, return the result */
264 return power;
265 }
266
267 /* if exp is negative, return the multiplicative inverse */
268 numerator = (u64)1 << (fwl << 1);
269 do_div(numerator, power);
270
271 return (u32)numerator;
272}
273
274/*
275 * Function to calculate volume gain from TLV data.
276 * This function can only handle gain steps that are multiples of 0.5 dB
277 */
278static u32 vol_compute_gain(u32 value, int *tlv)
279{
280 int dB_gain;
281 u32 linear_gain;
282 int f_step;
283
284 /* mute volume */
285 if (value == 0 && tlv[TLV_MUTE])
286 return 0;
287
288 /*
289 * compute dB gain from tlv. tlv_step
290 * in topology is multiplied by 100
291 */
292 dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100;
293
294 /*
295 * compute linear gain represented by fixed-point
296 * int with VOLUME_FWL fractional bits
297 */
298 linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL);
299
300 /* extract the fractional part of volume step */
301 f_step = tlv[TLV_STEP] - (tlv[TLV_STEP] / 100);
302
303 /* if volume step is an odd multiple of 0.5 dB */
304 if (f_step == VOL_HALF_DB_STEP && (value & 1))
305 linear_gain = vol_shift_64((u64)linear_gain *
306 VOL_FORTIETH_ROOT_OF_TEN,
307 VOLUME_FWL);
308
309 return linear_gain;
310}
311
312/*
313 * Set up volume table for kcontrols from tlv data
314 * "size" specifies the number of entries in the table
315 */
316static int set_up_volume_table(struct snd_sof_control *scontrol,
317 int tlv[TLV_ITEMS], int size)
318{
319 int j;
320
321 /* init the volume table */
322 scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
323 if (!scontrol->volume_table)
324 return -ENOMEM;
325
326 /* populate the volume table */
327 for (j = 0; j < size ; j++)
328 scontrol->volume_table[j] = vol_compute_gain(j, tlv);
329
330 return 0;
331}
332
333struct sof_dai_types {
334 const char *name;
335 enum sof_ipc_dai_type type;
336};
337
338static const struct sof_dai_types sof_dais[] = {
339 {"SSP", SOF_DAI_INTEL_SSP},
340 {"HDA", SOF_DAI_INTEL_HDA},
341 {"DMIC", SOF_DAI_INTEL_DMIC},
342};
343
344static enum sof_ipc_dai_type find_dai(const char *name)
345{
346 int i;
347
348 for (i = 0; i < ARRAY_SIZE(sof_dais); i++) {
349 if (strcmp(name, sof_dais[i].name) == 0)
350 return sof_dais[i].type;
351 }
352
353 return SOF_DAI_INTEL_NONE;
354}
355
356/*
357 * Supported Frame format types and lookup, add new ones to end of list.
358 */
359
360struct sof_frame_types {
361 const char *name;
362 enum sof_ipc_frame frame;
363};
364
365static const struct sof_frame_types sof_frames[] = {
366 {"s16le", SOF_IPC_FRAME_S16_LE},
367 {"s24le", SOF_IPC_FRAME_S24_4LE},
368 {"s32le", SOF_IPC_FRAME_S32_LE},
369 {"float", SOF_IPC_FRAME_FLOAT},
370};
371
372static enum sof_ipc_frame find_format(const char *name)
373{
374 int i;
375
376 for (i = 0; i < ARRAY_SIZE(sof_frames); i++) {
377 if (strcmp(name, sof_frames[i].name) == 0)
378 return sof_frames[i].frame;
379 }
380
381 /* use s32le if nothing is specified */
382 return SOF_IPC_FRAME_S32_LE;
383}
384
385struct sof_process_types {
386 const char *name;
387 enum sof_ipc_process_type type;
388 enum sof_comp_type comp_type;
389};
390
391static const struct sof_process_types sof_process[] = {
392 {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR},
393 {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR},
394 {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
395 {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
396 {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
397};
398
399static enum sof_ipc_process_type find_process(const char *name)
400{
401 int i;
402
403 for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
404 if (strcmp(name, sof_process[i].name) == 0)
405 return sof_process[i].type;
406 }
407
408 return SOF_PROCESS_NONE;
409}
410
411static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
412{
413 int i;
414
415 for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
416 if (sof_process[i].type == type)
417 return sof_process[i].comp_type;
418 }
419
420 return SOF_COMP_NONE;
421}
422
423/*
424 * Standard Kcontrols.
425 */
426
427static int sof_control_load_volume(struct snd_soc_component *scomp,
428 struct snd_sof_control *scontrol,
429 struct snd_kcontrol_new *kc,
430 struct snd_soc_tplg_ctl_hdr *hdr)
431{
432 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
433 struct snd_soc_tplg_mixer_control *mc =
434 container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
435 struct sof_ipc_ctrl_data *cdata;
436 int tlv[TLV_ITEMS];
437 unsigned int i;
438 int ret;
439
440 /* validate topology data */
441 if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN)
442 return -EINVAL;
443
444 /* init the volume get/put data */
445 scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
446 sizeof(struct sof_ipc_ctrl_value_chan) *
447 le32_to_cpu(mc->num_channels);
448 scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
449 if (!scontrol->control_data)
450 return -ENOMEM;
451
452 scontrol->comp_id = sdev->next_comp_id;
453 scontrol->num_channels = le32_to_cpu(mc->num_channels);
454
455 /* set cmd for mixer control */
456 if (le32_to_cpu(mc->max) == 1) {
457 scontrol->cmd = SOF_CTRL_CMD_SWITCH;
458 goto out;
459 }
460
461 scontrol->cmd = SOF_CTRL_CMD_VOLUME;
462
463 /* extract tlv data */
464 if (get_tlv_data(kc->tlv.p, tlv) < 0) {
465 dev_err(sdev->dev, "error: invalid TLV data\n");
466 return -EINVAL;
467 }
468
469 /* set up volume table */
470 ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1);
471 if (ret < 0) {
472 dev_err(sdev->dev, "error: setting up volume table\n");
473 return ret;
474 }
475
476 /* set default volume values to 0dB in control */
477 cdata = scontrol->control_data;
478 for (i = 0; i < scontrol->num_channels; i++) {
479 cdata->chanv[i].channel = i;
480 cdata->chanv[i].value = VOL_ZERO_DB;
481 }
482
483out:
484 dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n",
485 scontrol->comp_id, scontrol->num_channels);
486
487 return 0;
488}
489
490static int sof_control_load_enum(struct snd_soc_component *scomp,
491 struct snd_sof_control *scontrol,
492 struct snd_kcontrol_new *kc,
493 struct snd_soc_tplg_ctl_hdr *hdr)
494{
495 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
496 struct snd_soc_tplg_enum_control *ec =
497 container_of(hdr, struct snd_soc_tplg_enum_control, hdr);
498
499 /* validate topology data */
500 if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN)
501 return -EINVAL;
502
503 /* init the enum get/put data */
504 scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
505 sizeof(struct sof_ipc_ctrl_value_chan) *
506 le32_to_cpu(ec->num_channels);
507 scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
508 if (!scontrol->control_data)
509 return -ENOMEM;
510
511 scontrol->comp_id = sdev->next_comp_id;
512 scontrol->num_channels = le32_to_cpu(ec->num_channels);
513
514 scontrol->cmd = SOF_CTRL_CMD_ENUM;
515
516 dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n",
517 scontrol->comp_id, scontrol->num_channels, scontrol->comp_id);
518
519 return 0;
520}
521
522static int sof_control_load_bytes(struct snd_soc_component *scomp,
523 struct snd_sof_control *scontrol,
524 struct snd_kcontrol_new *kc,
525 struct snd_soc_tplg_ctl_hdr *hdr)
526{
527 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
528 struct sof_ipc_ctrl_data *cdata;
529 struct snd_soc_tplg_bytes_control *control =
530 container_of(hdr, struct snd_soc_tplg_bytes_control, hdr);
531 struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value;
532 int max_size = sbe->max;
533
534 if (le32_to_cpu(control->priv.size) > max_size) {
535 dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n",
536 control->priv.size, max_size);
537 return -EINVAL;
538 }
539
540 /* init the get/put bytes data */
541 scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
542 le32_to_cpu(control->priv.size);
543 scontrol->control_data = kzalloc(max_size, GFP_KERNEL);
544 cdata = scontrol->control_data;
545 if (!scontrol->control_data)
546 return -ENOMEM;
547
548 scontrol->comp_id = sdev->next_comp_id;
549 scontrol->cmd = SOF_CTRL_CMD_BINARY;
550
551 dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n",
552 scontrol->comp_id, scontrol->num_channels);
553
554 if (le32_to_cpu(control->priv.size) > 0) {
555 memcpy(cdata->data, control->priv.data,
556 le32_to_cpu(control->priv.size));
557
558 if (cdata->data->magic != SOF_ABI_MAGIC) {
559 dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n",
560 cdata->data->magic);
561 return -EINVAL;
562 }
563 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION,
564 cdata->data->abi)) {
565 dev_err(sdev->dev,
566 "error: Incompatible ABI version 0x%08x.\n",
567 cdata->data->abi);
568 return -EINVAL;
569 }
570 if (cdata->data->size + sizeof(const struct sof_abi_hdr) !=
571 le32_to_cpu(control->priv.size)) {
572 dev_err(sdev->dev,
573 "error: Conflict in bytes vs. priv size.\n");
574 return -EINVAL;
575 }
576 }
577 return 0;
578}
579
580/*
581 * Topology Token Parsing.
582 * New tokens should be added to headers and parsing tables below.
583 */
584
585struct sof_topology_token {
586 u32 token;
587 u32 type;
588 int (*get_token)(void *elem, void *object, u32 offset, u32 size);
589 u32 offset;
590 u32 size;
591};
592
593static int get_token_u32(void *elem, void *object, u32 offset, u32 size)
594{
595 struct snd_soc_tplg_vendor_value_elem *velem = elem;
596 u32 *val = (u32 *)((u8 *)object + offset);
597
598 *val = le32_to_cpu(velem->value);
599 return 0;
600}
601
602static int get_token_u16(void *elem, void *object, u32 offset, u32 size)
603{
604 struct snd_soc_tplg_vendor_value_elem *velem = elem;
605 u16 *val = (u16 *)((u8 *)object + offset);
606
607 *val = (u16)le32_to_cpu(velem->value);
608 return 0;
609}
610
611static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size)
612{
613 struct snd_soc_tplg_vendor_string_elem *velem = elem;
614 u32 *val = (u32 *)((u8 *)object + offset);
615
616 *val = find_format(velem->string);
617 return 0;
618}
619
620static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size)
621{
622 struct snd_soc_tplg_vendor_string_elem *velem = elem;
623 u32 *val = (u32 *)((u8 *)object + offset);
624
625 *val = find_dai(velem->string);
626 return 0;
627}
628
629static int get_token_process_type(void *elem, void *object, u32 offset,
630 u32 size)
631{
632 struct snd_soc_tplg_vendor_string_elem *velem = elem;
633 u32 *val = (u32 *)((u8 *)object + offset);
634
635 *val = find_process(velem->string);
636 return 0;
637}
638
639/* Buffers */
640static const struct sof_topology_token buffer_tokens[] = {
641 {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
642 offsetof(struct sof_ipc_buffer, size), 0},
643 {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
644 offsetof(struct sof_ipc_buffer, caps), 0},
645};
646
647/* DAI */
648static const struct sof_topology_token dai_tokens[] = {
649 {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
650 offsetof(struct sof_ipc_comp_dai, type), 0},
651 {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
652 offsetof(struct sof_ipc_comp_dai, dai_index), 0},
653 {SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
654 offsetof(struct sof_ipc_comp_dai, direction), 0},
655};
656
657/* BE DAI link */
658static const struct sof_topology_token dai_link_tokens[] = {
659 {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
660 offsetof(struct sof_ipc_dai_config, type), 0},
661 {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
662 offsetof(struct sof_ipc_dai_config, dai_index), 0},
663};
664
665/* scheduling */
666static const struct sof_topology_token sched_tokens[] = {
667 {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
668 offsetof(struct sof_ipc_pipe_new, period), 0},
669 {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
670 offsetof(struct sof_ipc_pipe_new, priority), 0},
671 {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
672 offsetof(struct sof_ipc_pipe_new, period_mips), 0},
673 {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
674 offsetof(struct sof_ipc_pipe_new, core), 0},
675 {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
676 offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0},
677 {SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
678 offsetof(struct sof_ipc_pipe_new, time_domain), 0},
679};
680
681/* volume */
682static const struct sof_topology_token volume_tokens[] = {
683 {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
684 get_token_u32, offsetof(struct sof_ipc_comp_volume, ramp), 0},
685 {SOF_TKN_VOLUME_RAMP_STEP_MS,
686 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
687 offsetof(struct sof_ipc_comp_volume, initial_ramp), 0},
688};
689
690/* SRC */
691static const struct sof_topology_token src_tokens[] = {
692 {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
693 offsetof(struct sof_ipc_comp_src, source_rate), 0},
694 {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
695 offsetof(struct sof_ipc_comp_src, sink_rate), 0},
696};
697
698/* Tone */
699static const struct sof_topology_token tone_tokens[] = {
700};
701
702/* EFFECT */
703static const struct sof_topology_token process_tokens[] = {
704 {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING,
705 get_token_process_type,
706 offsetof(struct sof_ipc_comp_process, type), 0},
707};
708
709/* PCM */
710static const struct sof_topology_token pcm_tokens[] = {
711 {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
712 offsetof(struct sof_ipc_comp_host, dmac_config), 0},
713};
714
715/* Generic components */
716static const struct sof_topology_token comp_tokens[] = {
717 {SOF_TKN_COMP_PERIOD_SINK_COUNT,
718 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
719 offsetof(struct sof_ipc_comp_config, periods_sink), 0},
720 {SOF_TKN_COMP_PERIOD_SOURCE_COUNT,
721 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
722 offsetof(struct sof_ipc_comp_config, periods_source), 0},
723 {SOF_TKN_COMP_FORMAT,
724 SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
725 offsetof(struct sof_ipc_comp_config, frame_fmt), 0},
726};
727
728/* SSP */
729static const struct sof_topology_token ssp_tokens[] = {
730 {SOF_TKN_INTEL_SSP_CLKS_CONTROL,
731 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
732 offsetof(struct sof_ipc_dai_ssp_params, clks_control), 0},
733 {SOF_TKN_INTEL_SSP_MCLK_ID,
734 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
735 offsetof(struct sof_ipc_dai_ssp_params, mclk_id), 0},
736 {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
737 get_token_u32,
738 offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits), 0},
739 {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT,
740 get_token_u16,
741 offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width), 0},
742 {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
743 get_token_u32,
744 offsetof(struct sof_ipc_dai_ssp_params, quirks), 0},
745 {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL,
746 get_token_u16,
747 offsetof(struct sof_ipc_dai_ssp_params,
748 tdm_per_slot_padding_flag), 0},
749
750};
751
752/* DMIC */
753static const struct sof_topology_token dmic_tokens[] = {
754 {SOF_TKN_INTEL_DMIC_DRIVER_VERSION,
755 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
756 offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version),
757 0},
758 {SOF_TKN_INTEL_DMIC_CLK_MIN,
759 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
760 offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min), 0},
761 {SOF_TKN_INTEL_DMIC_CLK_MAX,
762 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
763 offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max), 0},
764 {SOF_TKN_INTEL_DMIC_SAMPLE_RATE,
765 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
766 offsetof(struct sof_ipc_dai_dmic_params, fifo_fs), 0},
767 {SOF_TKN_INTEL_DMIC_DUTY_MIN,
768 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
769 offsetof(struct sof_ipc_dai_dmic_params, duty_min), 0},
770 {SOF_TKN_INTEL_DMIC_DUTY_MAX,
771 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
772 offsetof(struct sof_ipc_dai_dmic_params, duty_max), 0},
773 {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE,
774 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
775 offsetof(struct sof_ipc_dai_dmic_params,
776 num_pdm_active), 0},
777 {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH,
778 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
779 offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0},
780};
781
782/*
783 * DMIC PDM Tokens
784 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
785 * as it increments the index while parsing the array of pdm tokens
786 * and determines the correct offset
787 */
788static const struct sof_topology_token dmic_pdm_tokens[] = {
789 {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID,
790 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
791 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id),
792 0},
793 {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable,
794 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
795 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a),
796 0},
797 {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable,
798 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
799 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b),
800 0},
801 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A,
802 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
803 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a),
804 0},
805 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B,
806 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
807 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b),
808 0},
809 {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE,
810 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
811 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge),
812 0},
813 {SOF_TKN_INTEL_DMIC_PDM_SKEW,
814 SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
815 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew),
816 0},
817};
818
819/* HDA */
820static const struct sof_topology_token hda_tokens[] = {
821};
822
823static void sof_parse_uuid_tokens(struct snd_soc_component *scomp,
824 void *object,
825 const struct sof_topology_token *tokens,
826 int count,
827 struct snd_soc_tplg_vendor_array *array)
828{
829 struct snd_soc_tplg_vendor_uuid_elem *elem;
830 int i, j;
831
832 /* parse element by element */
833 for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
834 elem = &array->uuid[i];
835
836 /* search for token */
837 for (j = 0; j < count; j++) {
838 /* match token type */
839 if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID)
840 continue;
841
842 /* match token id */
843 if (tokens[j].token != le32_to_cpu(elem->token))
844 continue;
845
846 /* matched - now load token */
847 tokens[j].get_token(elem, object, tokens[j].offset,
848 tokens[j].size);
849 }
850 }
851}
852
853static void sof_parse_string_tokens(struct snd_soc_component *scomp,
854 void *object,
855 const struct sof_topology_token *tokens,
856 int count,
857 struct snd_soc_tplg_vendor_array *array)
858{
859 struct snd_soc_tplg_vendor_string_elem *elem;
860 int i, j;
861
862 /* parse element by element */
863 for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
864 elem = &array->string[i];
865
866 /* search for token */
867 for (j = 0; j < count; j++) {
868 /* match token type */
869 if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING)
870 continue;
871
872 /* match token id */
873 if (tokens[j].token != le32_to_cpu(elem->token))
874 continue;
875
876 /* matched - now load token */
877 tokens[j].get_token(elem, object, tokens[j].offset,
878 tokens[j].size);
879 }
880 }
881}
882
883static void sof_parse_word_tokens(struct snd_soc_component *scomp,
884 void *object,
885 const struct sof_topology_token *tokens,
886 int count,
887 struct snd_soc_tplg_vendor_array *array)
888{
889 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
890 struct snd_soc_tplg_vendor_value_elem *elem;
891 size_t size = sizeof(struct sof_ipc_dai_dmic_pdm_ctrl);
892 int i, j;
893 u32 offset;
894 u32 *index = NULL;
895
896 /* parse element by element */
897 for (i = 0; i < le32_to_cpu(array->num_elems); i++) {
898 elem = &array->value[i];
899
900 /* search for token */
901 for (j = 0; j < count; j++) {
902 /* match token type */
903 if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD ||
904 tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT))
905 continue;
906
907 /* match token id */
908 if (tokens[j].token != le32_to_cpu(elem->token))
909 continue;
910
911 /* pdm config array index */
912 if (sdev->private)
913 index = sdev->private;
914
915 /* matched - determine offset */
916 switch (tokens[j].token) {
917 case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID:
918
919 /* inc number of pdm array index */
920 if (index)
921 (*index)++;
922 /* fallthrough */
923 case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable:
924 case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable:
925 case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A:
926 case SOF_TKN_INTEL_DMIC_PDM_POLARITY_B:
927 case SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE:
928 case SOF_TKN_INTEL_DMIC_PDM_SKEW:
929
930 /* check if array index is valid */
931 if (!index || *index == 0) {
932 dev_err(sdev->dev,
933 "error: invalid array offset\n");
934 continue;
935 } else {
936 /* offset within the pdm config array */
937 offset = size * (*index - 1);
938 }
939 break;
940 default:
941 offset = 0;
942 break;
943 }
944
945 /* load token */
946 tokens[j].get_token(elem, object,
947 offset + tokens[j].offset,
948 tokens[j].size);
949 }
950 }
951}
952
953static int sof_parse_tokens(struct snd_soc_component *scomp,
954 void *object,
955 const struct sof_topology_token *tokens,
956 int count,
957 struct snd_soc_tplg_vendor_array *array,
958 int priv_size)
959{
960 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
961 int asize;
962
963 while (priv_size > 0) {
964 asize = le32_to_cpu(array->size);
965
966 /* validate asize */
967 if (asize < 0) { /* FIXME: A zero-size array makes no sense */
968 dev_err(sdev->dev, "error: invalid array size 0x%x\n",
969 asize);
970 return -EINVAL;
971 }
972
973 /* make sure there is enough data before parsing */
974 priv_size -= asize;
975 if (priv_size < 0) {
976 dev_err(sdev->dev, "error: invalid array size 0x%x\n",
977 asize);
978 return -EINVAL;
979 }
980
981 /* call correct parser depending on type */
982 switch (le32_to_cpu(array->type)) {
983 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
984 sof_parse_uuid_tokens(scomp, object, tokens, count,
985 array);
986 break;
987 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
988 sof_parse_string_tokens(scomp, object, tokens, count,
989 array);
990 break;
991 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
992 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
993 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
994 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
995 sof_parse_word_tokens(scomp, object, tokens, count,
996 array);
997 break;
998 default:
999 dev_err(sdev->dev, "error: unknown token type %d\n",
1000 array->type);
1001 return -EINVAL;
1002 }
1003
1004 /* next array */
1005 array = (struct snd_soc_tplg_vendor_array *)((u8 *)array
1006 + asize);
1007 }
1008 return 0;
1009}
1010
1011static void sof_dbg_comp_config(struct snd_soc_component *scomp,
1012 struct sof_ipc_comp_config *config)
1013{
1014 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1015
1016 dev_dbg(sdev->dev, " config: periods snk %d src %d fmt %d\n",
1017 config->periods_sink, config->periods_source,
1018 config->frame_fmt);
1019}
1020
1021/* external kcontrol init - used for any driver specific init */
1022static int sof_control_load(struct snd_soc_component *scomp, int index,
1023 struct snd_kcontrol_new *kc,
1024 struct snd_soc_tplg_ctl_hdr *hdr)
1025{
1026 struct soc_mixer_control *sm;
1027 struct soc_bytes_ext *sbe;
1028 struct soc_enum *se;
1029 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1030 struct snd_soc_dobj *dobj;
1031 struct snd_sof_control *scontrol;
1032 int ret = -EINVAL;
1033
1034 dev_dbg(sdev->dev, "tplg: load control type %d name : %s\n",
1035 hdr->type, hdr->name);
1036
1037 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1038 if (!scontrol)
1039 return -ENOMEM;
1040
1041 scontrol->sdev = sdev;
1042
1043 switch (le32_to_cpu(hdr->ops.info)) {
1044 case SND_SOC_TPLG_CTL_VOLSW:
1045 case SND_SOC_TPLG_CTL_VOLSW_SX:
1046 case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1047 sm = (struct soc_mixer_control *)kc->private_value;
1048 dobj = &sm->dobj;
1049 ret = sof_control_load_volume(scomp, scontrol, kc, hdr);
1050 break;
1051 case SND_SOC_TPLG_CTL_BYTES:
1052 sbe = (struct soc_bytes_ext *)kc->private_value;
1053 dobj = &sbe->dobj;
1054 ret = sof_control_load_bytes(scomp, scontrol, kc, hdr);
1055 break;
1056 case SND_SOC_TPLG_CTL_ENUM:
1057 case SND_SOC_TPLG_CTL_ENUM_VALUE:
1058 se = (struct soc_enum *)kc->private_value;
1059 dobj = &se->dobj;
1060 ret = sof_control_load_enum(scomp, scontrol, kc, hdr);
1061 break;
1062 case SND_SOC_TPLG_CTL_RANGE:
1063 case SND_SOC_TPLG_CTL_STROBE:
1064 case SND_SOC_TPLG_DAPM_CTL_VOLSW:
1065 case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
1066 case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
1067 case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
1068 case SND_SOC_TPLG_DAPM_CTL_PIN:
1069 default:
1070 dev_warn(sdev->dev, "control type not supported %d:%d:%d\n",
1071 hdr->ops.get, hdr->ops.put, hdr->ops.info);
1072 kfree(scontrol);
1073 return 0;
1074 }
1075
1076 dobj->private = scontrol;
1077 list_add(&scontrol->list, &sdev->kcontrol_list);
1078 return ret;
1079}
1080
1081static int sof_control_unload(struct snd_soc_component *scomp,
1082 struct snd_soc_dobj *dobj)
1083{
1084 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1085 struct sof_ipc_free fcomp;
1086 struct snd_sof_control *scontrol = dobj->private;
1087
1088 dev_dbg(sdev->dev, "tplg: unload control name : %s\n", scomp->name);
1089
1090 fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
1091 fcomp.hdr.size = sizeof(fcomp);
1092 fcomp.id = scontrol->comp_id;
1093
1094 kfree(scontrol->control_data);
1095 list_del(&scontrol->list);
1096 kfree(scontrol);
1097 /* send IPC to the DSP */
1098 return sof_ipc_tx_message(sdev->ipc,
1099 fcomp.hdr.cmd, &fcomp, sizeof(fcomp),
1100 NULL, 0);
1101}
1102
1103/*
1104 * DAI Topology
1105 */
1106
1107static int sof_connect_dai_widget(struct snd_soc_component *scomp,
1108 struct snd_soc_dapm_widget *w,
1109 struct snd_soc_tplg_dapm_widget *tw,
1110 struct snd_sof_dai *dai)
1111{
1112 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1113 struct snd_soc_card *card = scomp->card;
1114 struct snd_soc_pcm_runtime *rtd;
1115
1116 list_for_each_entry(rtd, &card->rtd_list, list) {
1117 dev_vdbg(sdev->dev, "tplg: check widget: %s stream: %s dai stream: %s\n",
1118 w->name, w->sname, rtd->dai_link->stream_name);
1119
1120 if (!w->sname || !rtd->dai_link->stream_name)
1121 continue;
1122
1123 /* does stream match DAI link ? */
1124 if (strcmp(w->sname, rtd->dai_link->stream_name))
1125 continue;
1126
1127 switch (w->id) {
1128 case snd_soc_dapm_dai_out:
1129 rtd->cpu_dai->capture_widget = w;
1130 dai->name = rtd->dai_link->name;
1131 dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n",
1132 w->name, rtd->dai_link->name);
1133 break;
1134 case snd_soc_dapm_dai_in:
1135 rtd->cpu_dai->playback_widget = w;
1136 dai->name = rtd->dai_link->name;
1137 dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n",
1138 w->name, rtd->dai_link->name);
1139 break;
1140 default:
1141 break;
1142 }
1143 }
1144
1145 /* check we have a connection */
1146 if (!dai->name) {
1147 dev_err(sdev->dev, "error: can't connect DAI %s stream %s\n",
1148 w->name, w->sname);
1149 return -EINVAL;
1150 }
1151
1152 return 0;
1153}
1154
1155static int sof_widget_load_dai(struct snd_soc_component *scomp, int index,
1156 struct snd_sof_widget *swidget,
1157 struct snd_soc_tplg_dapm_widget *tw,
1158 struct sof_ipc_comp_reply *r,
1159 struct snd_sof_dai *dai)
1160{
1161 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1162 struct snd_soc_tplg_private *private = &tw->priv;
1163 struct sof_ipc_comp_dai comp_dai;
1164 int ret;
1165
1166 /* configure dai IPC message */
1167 memset(&comp_dai, 0, sizeof(comp_dai));
1168 comp_dai.comp.hdr.size = sizeof(comp_dai);
1169 comp_dai.comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1170 comp_dai.comp.id = swidget->comp_id;
1171 comp_dai.comp.type = SOF_COMP_DAI;
1172 comp_dai.comp.pipeline_id = index;
1173 comp_dai.config.hdr.size = sizeof(comp_dai.config);
1174
1175 ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens,
1176 ARRAY_SIZE(dai_tokens), private->array,
1177 le32_to_cpu(private->size));
1178 if (ret != 0) {
1179 dev_err(sdev->dev, "error: parse dai tokens failed %d\n",
1180 le32_to_cpu(private->size));
1181 return ret;
1182 }
1183
1184 ret = sof_parse_tokens(scomp, &comp_dai.config, comp_tokens,
1185 ARRAY_SIZE(comp_tokens), private->array,
1186 le32_to_cpu(private->size));
1187 if (ret != 0) {
1188 dev_err(sdev->dev, "error: parse dai.cfg tokens failed %d\n",
1189 private->size);
1190 return ret;
1191 }
1192
1193 dev_dbg(sdev->dev, "dai %s: type %d index %d\n",
1194 swidget->widget->name, comp_dai.type, comp_dai.dai_index);
1195 sof_dbg_comp_config(scomp, &comp_dai.config);
1196
1197 ret = sof_ipc_tx_message(sdev->ipc, comp_dai.comp.hdr.cmd,
1198 &comp_dai, sizeof(comp_dai), r, sizeof(*r));
1199
1200 if (ret == 0 && dai) {
1201 dai->sdev = sdev;
1202 memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai));
1203 }
1204
1205 return ret;
1206}
1207
1208/*
1209 * Buffer topology
1210 */
1211
1212static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index,
1213 struct snd_sof_widget *swidget,
1214 struct snd_soc_tplg_dapm_widget *tw,
1215 struct sof_ipc_comp_reply *r)
1216{
1217 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1218 struct snd_soc_tplg_private *private = &tw->priv;
1219 struct sof_ipc_buffer *buffer;
1220 int ret;
1221
1222 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
1223 if (!buffer)
1224 return -ENOMEM;
1225
1226 /* configure dai IPC message */
1227 buffer->comp.hdr.size = sizeof(*buffer);
1228 buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW;
1229 buffer->comp.id = swidget->comp_id;
1230 buffer->comp.type = SOF_COMP_BUFFER;
1231 buffer->comp.pipeline_id = index;
1232
1233 ret = sof_parse_tokens(scomp, buffer, buffer_tokens,
1234 ARRAY_SIZE(buffer_tokens), private->array,
1235 le32_to_cpu(private->size));
1236 if (ret != 0) {
1237 dev_err(sdev->dev, "error: parse buffer tokens failed %d\n",
1238 private->size);
1239 kfree(buffer);
1240 return ret;
1241 }
1242
1243 dev_dbg(sdev->dev, "buffer %s: size %d caps 0x%x\n",
1244 swidget->widget->name, buffer->size, buffer->caps);
1245
1246 swidget->private = buffer;
1247
1248 ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer,
1249 sizeof(*buffer), r, sizeof(*r));
1250 if (ret < 0) {
1251 dev_err(sdev->dev, "error: buffer %s load failed\n",
1252 swidget->widget->name);
1253 kfree(buffer);
1254 }
1255
1256 return ret;
1257}
1258
1259/* bind PCM ID to host component ID */
1260static int spcm_bind(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
1261 int dir)
1262{
1263 struct snd_sof_widget *host_widget;
1264
1265 host_widget = snd_sof_find_swidget_sname(sdev,
1266 spcm->pcm.caps[dir].name,
1267 dir);
1268 if (!host_widget) {
1269 dev_err(sdev->dev, "can't find host comp to bind pcm\n");
1270 return -EINVAL;
1271 }
1272
1273 spcm->stream[dir].comp_id = host_widget->comp_id;
1274
1275 return 0;
1276}
1277
1278/*
1279 * PCM Topology
1280 */
1281
1282static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
1283 struct snd_sof_widget *swidget,
1284 enum sof_ipc_stream_direction dir,
1285 struct snd_soc_tplg_dapm_widget *tw,
1286 struct sof_ipc_comp_reply *r)
1287{
1288 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1289 struct snd_soc_tplg_private *private = &tw->priv;
1290 struct sof_ipc_comp_host *host;
1291 int ret;
1292
1293 host = kzalloc(sizeof(*host), GFP_KERNEL);
1294 if (!host)
1295 return -ENOMEM;
1296
1297 /* configure host comp IPC message */
1298 host->comp.hdr.size = sizeof(*host);
1299 host->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1300 host->comp.id = swidget->comp_id;
1301 host->comp.type = SOF_COMP_HOST;
1302 host->comp.pipeline_id = index;
1303 host->direction = dir;
1304 host->config.hdr.size = sizeof(host->config);
1305
1306 ret = sof_parse_tokens(scomp, host, pcm_tokens,
1307 ARRAY_SIZE(pcm_tokens), private->array,
1308 le32_to_cpu(private->size));
1309 if (ret != 0) {
1310 dev_err(sdev->dev, "error: parse host tokens failed %d\n",
1311 private->size);
1312 goto err;
1313 }
1314
1315 ret = sof_parse_tokens(scomp, &host->config, comp_tokens,
1316 ARRAY_SIZE(comp_tokens), private->array,
1317 le32_to_cpu(private->size));
1318 if (ret != 0) {
1319 dev_err(sdev->dev, "error: parse host.cfg tokens failed %d\n",
1320 le32_to_cpu(private->size));
1321 goto err;
1322 }
1323
1324 dev_dbg(sdev->dev, "loaded host %s\n", swidget->widget->name);
1325 sof_dbg_comp_config(scomp, &host->config);
1326
1327 swidget->private = host;
1328
1329 ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host,
1330 sizeof(*host), r, sizeof(*r));
1331 if (ret >= 0)
1332 return ret;
1333err:
1334 kfree(host);
1335 return ret;
1336}
1337
1338/*
1339 * Pipeline Topology
1340 */
1341int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
1342 struct sof_ipc_pipe_new *pipeline,
1343 struct sof_ipc_comp_reply *r)
1344{
1345 struct sof_ipc_pm_core_config pm_core_config;
1346 int ret;
1347
1348 ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
1349 sizeof(*pipeline), r, sizeof(*r));
1350 if (ret < 0) {
1351 dev_err(sdev->dev, "error: load pipeline ipc failure\n");
1352 return ret;
1353 }
1354
1355 /* power up the core that this pipeline is scheduled on */
1356 ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core);
1357 if (ret < 0) {
1358 dev_err(sdev->dev, "error: powering up pipeline schedule core %d\n",
1359 pipeline->core);
1360 return ret;
1361 }
1362
1363 /* update enabled cores mask */
1364 sdev->enabled_cores_mask |= 1 << pipeline->core;
1365
1366 /*
1367 * Now notify DSP that the core that this pipeline is scheduled on
1368 * has been powered up
1369 */
1370 memset(&pm_core_config, 0, sizeof(pm_core_config));
1371 pm_core_config.enable_mask = sdev->enabled_cores_mask;
1372
1373 /* configure CORE_ENABLE ipc message */
1374 pm_core_config.hdr.size = sizeof(pm_core_config);
1375 pm_core_config.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE;
1376
1377 /* send ipc */
1378 ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
1379 &pm_core_config, sizeof(pm_core_config),
1380 &pm_core_config, sizeof(pm_core_config));
1381 if (ret < 0)
1382 dev_err(sdev->dev, "error: core enable ipc failure\n");
1383
1384 return ret;
1385}
1386
1387static int sof_widget_load_pipeline(struct snd_soc_component *scomp,
1388 int index, struct snd_sof_widget *swidget,
1389 struct snd_soc_tplg_dapm_widget *tw,
1390 struct sof_ipc_comp_reply *r)
1391{
1392 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1393 struct snd_soc_tplg_private *private = &tw->priv;
1394 struct sof_ipc_pipe_new *pipeline;
1395 struct snd_sof_widget *comp_swidget;
1396 int ret;
1397
1398 pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
1399 if (!pipeline)
1400 return -ENOMEM;
1401
1402 /* configure dai IPC message */
1403 pipeline->hdr.size = sizeof(*pipeline);
1404 pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW;
1405 pipeline->pipeline_id = index;
1406 pipeline->comp_id = swidget->comp_id;
1407
1408 /* component at start of pipeline is our stream id */
1409 comp_swidget = snd_sof_find_swidget(sdev, tw->sname);
1410 if (!comp_swidget) {
1411 dev_err(sdev->dev, "error: widget %s refers to non existent widget %s\n",
1412 tw->name, tw->sname);
1413 ret = -EINVAL;
1414 goto err;
1415 }
1416
1417 pipeline->sched_id = comp_swidget->comp_id;
1418
1419 dev_dbg(sdev->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n",
1420 pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id);
1421
1422 ret = sof_parse_tokens(scomp, pipeline, sched_tokens,
1423 ARRAY_SIZE(sched_tokens), private->array,
1424 le32_to_cpu(private->size));
1425 if (ret != 0) {
1426 dev_err(sdev->dev, "error: parse pipeline tokens failed %d\n",
1427 private->size);
1428 goto err;
1429 }
1430
1431 dev_dbg(sdev->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n",
1432 swidget->widget->name, pipeline->period, pipeline->priority,
1433 pipeline->period_mips, pipeline->core, pipeline->frames_per_sched);
1434
1435 swidget->private = pipeline;
1436
1437 /* send ipc's to create pipeline comp and power up schedule core */
1438 ret = sof_load_pipeline_ipc(sdev, pipeline, r);
1439 if (ret >= 0)
1440 return ret;
1441err:
1442 kfree(pipeline);
1443 return ret;
1444}
1445
1446/*
1447 * Mixer topology
1448 */
1449
1450static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index,
1451 struct snd_sof_widget *swidget,
1452 struct snd_soc_tplg_dapm_widget *tw,
1453 struct sof_ipc_comp_reply *r)
1454{
1455 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1456 struct snd_soc_tplg_private *private = &tw->priv;
1457 struct sof_ipc_comp_mixer *mixer;
1458 int ret;
1459
1460 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
1461 if (!mixer)
1462 return -ENOMEM;
1463
1464 /* configure mixer IPC message */
1465 mixer->comp.hdr.size = sizeof(*mixer);
1466 mixer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1467 mixer->comp.id = swidget->comp_id;
1468 mixer->comp.type = SOF_COMP_MIXER;
1469 mixer->comp.pipeline_id = index;
1470 mixer->config.hdr.size = sizeof(mixer->config);
1471
1472 ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens,
1473 ARRAY_SIZE(comp_tokens), private->array,
1474 le32_to_cpu(private->size));
1475 if (ret != 0) {
1476 dev_err(sdev->dev, "error: parse mixer.cfg tokens failed %d\n",
1477 private->size);
1478 kfree(mixer);
1479 return ret;
1480 }
1481
1482 sof_dbg_comp_config(scomp, &mixer->config);
1483
1484 swidget->private = mixer;
1485
1486 ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer,
1487 sizeof(*mixer), r, sizeof(*r));
1488 if (ret < 0)
1489 kfree(mixer);
1490
1491 return ret;
1492}
1493
1494/*
1495 * Mux topology
1496 */
1497static int sof_widget_load_mux(struct snd_soc_component *scomp, int index,
1498 struct snd_sof_widget *swidget,
1499 struct snd_soc_tplg_dapm_widget *tw,
1500 struct sof_ipc_comp_reply *r)
1501{
1502 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1503 struct snd_soc_tplg_private *private = &tw->priv;
1504 struct sof_ipc_comp_mux *mux;
1505 int ret;
1506
1507 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
1508 if (!mux)
1509 return -ENOMEM;
1510
1511 /* configure mux IPC message */
1512 mux->comp.hdr.size = sizeof(*mux);
1513 mux->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1514 mux->comp.id = swidget->comp_id;
1515 mux->comp.type = SOF_COMP_MUX;
1516 mux->comp.pipeline_id = index;
1517 mux->config.hdr.size = sizeof(mux->config);
1518
1519 ret = sof_parse_tokens(scomp, &mux->config, comp_tokens,
1520 ARRAY_SIZE(comp_tokens), private->array,
1521 le32_to_cpu(private->size));
1522 if (ret != 0) {
1523 dev_err(sdev->dev, "error: parse mux.cfg tokens failed %d\n",
1524 private->size);
1525 kfree(mux);
1526 return ret;
1527 }
1528
1529 sof_dbg_comp_config(scomp, &mux->config);
1530
1531 swidget->private = mux;
1532
1533 ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux,
1534 sizeof(*mux), r, sizeof(*r));
1535 if (ret < 0)
1536 kfree(mux);
1537
1538 return ret;
1539}
1540
1541/*
1542 * PGA Topology
1543 */
1544
1545static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
1546 struct snd_sof_widget *swidget,
1547 struct snd_soc_tplg_dapm_widget *tw,
1548 struct sof_ipc_comp_reply *r)
1549{
1550 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1551 struct snd_soc_tplg_private *private = &tw->priv;
1552 struct sof_ipc_comp_volume *volume;
1553 int ret;
1554
1555 volume = kzalloc(sizeof(*volume), GFP_KERNEL);
1556 if (!volume)
1557 return -ENOMEM;
1558
1559 if (le32_to_cpu(tw->num_kcontrols) != 1) {
1560 dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n",
1561 tw->num_kcontrols);
1562 ret = -EINVAL;
1563 goto err;
1564 }
1565
1566 /* configure volume IPC message */
1567 volume->comp.hdr.size = sizeof(*volume);
1568 volume->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1569 volume->comp.id = swidget->comp_id;
1570 volume->comp.type = SOF_COMP_VOLUME;
1571 volume->comp.pipeline_id = index;
1572 volume->config.hdr.size = sizeof(volume->config);
1573
1574 ret = sof_parse_tokens(scomp, volume, volume_tokens,
1575 ARRAY_SIZE(volume_tokens), private->array,
1576 le32_to_cpu(private->size));
1577 if (ret != 0) {
1578 dev_err(sdev->dev, "error: parse volume tokens failed %d\n",
1579 private->size);
1580 goto err;
1581 }
1582 ret = sof_parse_tokens(scomp, &volume->config, comp_tokens,
1583 ARRAY_SIZE(comp_tokens), private->array,
1584 le32_to_cpu(private->size));
1585 if (ret != 0) {
1586 dev_err(sdev->dev, "error: parse volume.cfg tokens failed %d\n",
1587 le32_to_cpu(private->size));
1588 goto err;
1589 }
1590
1591 sof_dbg_comp_config(scomp, &volume->config);
1592
1593 swidget->private = volume;
1594
1595 ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume,
1596 sizeof(*volume), r, sizeof(*r));
1597 if (ret >= 0)
1598 return ret;
1599err:
1600 kfree(volume);
1601 return ret;
1602}
1603
1604/*
1605 * SRC Topology
1606 */
1607
1608static int sof_widget_load_src(struct snd_soc_component *scomp, int index,
1609 struct snd_sof_widget *swidget,
1610 struct snd_soc_tplg_dapm_widget *tw,
1611 struct sof_ipc_comp_reply *r)
1612{
1613 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1614 struct snd_soc_tplg_private *private = &tw->priv;
1615 struct sof_ipc_comp_src *src;
1616 int ret;
1617
1618 src = kzalloc(sizeof(*src), GFP_KERNEL);
1619 if (!src)
1620 return -ENOMEM;
1621
1622 /* configure src IPC message */
1623 src->comp.hdr.size = sizeof(*src);
1624 src->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1625 src->comp.id = swidget->comp_id;
1626 src->comp.type = SOF_COMP_SRC;
1627 src->comp.pipeline_id = index;
1628 src->config.hdr.size = sizeof(src->config);
1629
1630 ret = sof_parse_tokens(scomp, src, src_tokens,
1631 ARRAY_SIZE(src_tokens), private->array,
1632 le32_to_cpu(private->size));
1633 if (ret != 0) {
1634 dev_err(sdev->dev, "error: parse src tokens failed %d\n",
1635 private->size);
1636 goto err;
1637 }
1638
1639 ret = sof_parse_tokens(scomp, &src->config, comp_tokens,
1640 ARRAY_SIZE(comp_tokens), private->array,
1641 le32_to_cpu(private->size));
1642 if (ret != 0) {
1643 dev_err(sdev->dev, "error: parse src.cfg tokens failed %d\n",
1644 le32_to_cpu(private->size));
1645 goto err;
1646 }
1647
1648 dev_dbg(sdev->dev, "src %s: source rate %d sink rate %d\n",
1649 swidget->widget->name, src->source_rate, src->sink_rate);
1650 sof_dbg_comp_config(scomp, &src->config);
1651
1652 swidget->private = src;
1653
1654 ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src,
1655 sizeof(*src), r, sizeof(*r));
1656 if (ret >= 0)
1657 return ret;
1658err:
1659 kfree(src);
1660 return ret;
1661}
1662
1663/*
1664 * Signal Generator Topology
1665 */
1666
1667static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index,
1668 struct snd_sof_widget *swidget,
1669 struct snd_soc_tplg_dapm_widget *tw,
1670 struct sof_ipc_comp_reply *r)
1671{
1672 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1673 struct snd_soc_tplg_private *private = &tw->priv;
1674 struct sof_ipc_comp_tone *tone;
1675 int ret;
1676
1677 tone = kzalloc(sizeof(*tone), GFP_KERNEL);
1678 if (!tone)
1679 return -ENOMEM;
1680
1681 /* configure siggen IPC message */
1682 tone->comp.hdr.size = sizeof(*tone);
1683 tone->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1684 tone->comp.id = swidget->comp_id;
1685 tone->comp.type = SOF_COMP_TONE;
1686 tone->comp.pipeline_id = index;
1687 tone->config.hdr.size = sizeof(tone->config);
1688
1689 ret = sof_parse_tokens(scomp, tone, tone_tokens,
1690 ARRAY_SIZE(tone_tokens), private->array,
1691 le32_to_cpu(private->size));
1692 if (ret != 0) {
1693 dev_err(sdev->dev, "error: parse tone tokens failed %d\n",
1694 le32_to_cpu(private->size));
1695 goto err;
1696 }
1697
1698 ret = sof_parse_tokens(scomp, &tone->config, comp_tokens,
1699 ARRAY_SIZE(comp_tokens), private->array,
1700 le32_to_cpu(private->size));
1701 if (ret != 0) {
1702 dev_err(sdev->dev, "error: parse tone.cfg tokens failed %d\n",
1703 le32_to_cpu(private->size));
1704 goto err;
1705 }
1706
1707 dev_dbg(sdev->dev, "tone %s: frequency %d amplitude %d\n",
1708 swidget->widget->name, tone->frequency, tone->amplitude);
1709 sof_dbg_comp_config(scomp, &tone->config);
1710
1711 swidget->private = tone;
1712
1713 ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone,
1714 sizeof(*tone), r, sizeof(*r));
1715 if (ret >= 0)
1716 return ret;
1717err:
1718 kfree(tone);
1719 return ret;
1720}
1721
1722static int sof_process_load(struct snd_soc_component *scomp, int index,
1723 struct snd_sof_widget *swidget,
1724 struct snd_soc_tplg_dapm_widget *tw,
1725 struct sof_ipc_comp_reply *r,
1726 int type)
1727{
1728 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1729 struct snd_soc_tplg_private *private = &tw->priv;
1730 struct snd_soc_dapm_widget *widget = swidget->widget;
1731 const struct snd_kcontrol_new *kc;
1732 struct soc_bytes_ext *sbe;
1733 struct soc_mixer_control *sm;
1734 struct soc_enum *se;
1735 struct snd_sof_control *scontrol = NULL;
1736 struct sof_abi_hdr *pdata = NULL;
1737 struct sof_ipc_comp_process *process;
1738 size_t ipc_size, ipc_data_size = 0;
1739 int ret, i, offset = 0;
1740
1741 if (type == SOF_COMP_NONE) {
1742 dev_err(sdev->dev, "error: invalid process comp type %d\n",
1743 type);
1744 return -EINVAL;
1745 }
1746
1747 /*
1748 * get possible component controls - get size of all pdata,
1749 * then memcpy with headers
1750 */
1751 for (i = 0; i < widget->num_kcontrols; i++) {
1752
1753 kc = &widget->kcontrol_news[i];
1754
1755 switch (widget->dobj.widget.kcontrol_type) {
1756 case SND_SOC_TPLG_TYPE_MIXER:
1757 sm = (struct soc_mixer_control *)kc->private_value;
1758 scontrol = sm->dobj.private;
1759 break;
1760 case SND_SOC_TPLG_TYPE_BYTES:
1761 sbe = (struct soc_bytes_ext *)kc->private_value;
1762 scontrol = sbe->dobj.private;
1763 break;
1764 case SND_SOC_TPLG_TYPE_ENUM:
1765 se = (struct soc_enum *)kc->private_value;
1766 scontrol = se->dobj.private;
1767 break;
1768 default:
1769 dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n",
1770 widget->dobj.widget.kcontrol_type,
1771 widget->name);
1772 return -EINVAL;
1773 }
1774
1775 if (!scontrol) {
1776 dev_err(sdev->dev, "error: no scontrol for widget %s\n",
1777 widget->name);
1778 return -EINVAL;
1779 }
1780
1781 /* don't include if no private data */
1782 pdata = scontrol->control_data->data;
1783 if (!pdata)
1784 continue;
1785
1786 /* make sure data is valid - data can be updated at runtime */
1787 if (pdata->magic != SOF_ABI_MAGIC)
1788 continue;
1789
1790 ipc_data_size += pdata->size;
1791 }
1792
1793 ipc_size = sizeof(struct sof_ipc_comp_process) +
1794 le32_to_cpu(private->size) +
1795 ipc_data_size;
1796
1797 process = kzalloc(ipc_size, GFP_KERNEL);
1798 if (!process)
1799 return -ENOMEM;
1800
1801 /* configure iir IPC message */
1802 process->comp.hdr.size = ipc_size;
1803 process->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
1804 process->comp.id = swidget->comp_id;
1805 process->comp.type = type;
1806 process->comp.pipeline_id = index;
1807 process->config.hdr.size = sizeof(process->config);
1808
1809 ret = sof_parse_tokens(scomp, &process->config, comp_tokens,
1810 ARRAY_SIZE(comp_tokens), private->array,
1811 le32_to_cpu(private->size));
1812 if (ret != 0) {
1813 dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n",
1814 le32_to_cpu(private->size));
1815 goto err;
1816 }
1817
1818 sof_dbg_comp_config(scomp, &process->config);
1819
1820 /*
1821 * found private data in control, so copy it.
1822 * get possible component controls - get size of all pdata,
1823 * then memcpy with headers
1824 */
1825 for (i = 0; i < widget->num_kcontrols; i++) {
1826 kc = &widget->kcontrol_news[i];
1827
1828 switch (widget->dobj.widget.kcontrol_type) {
1829 case SND_SOC_TPLG_TYPE_MIXER:
1830 sm = (struct soc_mixer_control *)kc->private_value;
1831 scontrol = sm->dobj.private;
1832 break;
1833 case SND_SOC_TPLG_TYPE_BYTES:
1834 sbe = (struct soc_bytes_ext *)kc->private_value;
1835 scontrol = sbe->dobj.private;
1836 break;
1837 case SND_SOC_TPLG_TYPE_ENUM:
1838 se = (struct soc_enum *)kc->private_value;
1839 scontrol = se->dobj.private;
1840 break;
1841 default:
1842 dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n",
1843 widget->dobj.widget.kcontrol_type,
1844 widget->name);
1845 return -EINVAL;
1846 }
1847
1848 /* don't include if no private data */
1849 pdata = scontrol->control_data->data;
1850 if (!pdata)
1851 continue;
1852
1853 /* make sure data is valid - data can be updated at runtime */
1854 if (pdata->magic != SOF_ABI_MAGIC)
1855 continue;
1856
1857 memcpy(&process->data + offset, pdata->data, pdata->size);
1858 offset += pdata->size;
1859 }
1860
1861 process->size = ipc_data_size;
1862 swidget->private = process;
1863
1864 ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process,
1865 ipc_size, r, sizeof(*r));
1866 if (ret >= 0)
1867 return ret;
1868err:
1869 kfree(process);
1870 return ret;
1871}
1872
1873/*
1874 * Processing Component Topology - can be "effect", "codec", or general
1875 * "processing".
1876 */
1877
1878static int sof_widget_load_process(struct snd_soc_component *scomp, int index,
1879 struct snd_sof_widget *swidget,
1880 struct snd_soc_tplg_dapm_widget *tw,
1881 struct sof_ipc_comp_reply *r)
1882{
1883 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1884 struct snd_soc_tplg_private *private = &tw->priv;
1885 struct sof_ipc_comp_process config;
1886 int ret;
1887
1888 /* check we have some tokens - we need at least process type */
1889 if (le32_to_cpu(private->size) == 0) {
1890 dev_err(sdev->dev, "error: process tokens not found\n");
1891 return -EINVAL;
1892 }
1893
1894 memset(&config, 0, sizeof(config));
1895
1896 /* get the process token */
1897 ret = sof_parse_tokens(scomp, &config, process_tokens,
1898 ARRAY_SIZE(process_tokens), private->array,
1899 le32_to_cpu(private->size));
1900 if (ret != 0) {
1901 dev_err(sdev->dev, "error: parse process tokens failed %d\n",
1902 le32_to_cpu(private->size));
1903 return ret;
1904 }
1905
1906 /* now load process specific data and send IPC */
1907 ret = sof_process_load(scomp, index, swidget, tw, r,
1908 find_process_comp_type(config.type));
1909 if (ret < 0) {
1910 dev_err(sdev->dev, "error: process loading failed\n");
1911 return ret;
1912 }
1913
1914 return 0;
1915}
1916
1917static int sof_widget_bind_event(struct snd_sof_dev *sdev,
1918 struct snd_sof_widget *swidget,
1919 u16 event_type)
1920{
1921 struct sof_ipc_comp *ipc_comp;
1922
1923 /* validate widget event type */
1924 switch (event_type) {
1925 case SOF_KEYWORD_DETECT_DAPM_EVENT:
1926 /* only KEYWORD_DETECT comps should handle this */
1927 if (swidget->id != snd_soc_dapm_effect)
1928 break;
1929
1930 ipc_comp = swidget->private;
1931 if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
1932 break;
1933
1934 /* bind event to keyword detect comp */
1935 return snd_soc_tplg_widget_bind_event(swidget->widget,
1936 sof_kwd_events,
1937 ARRAY_SIZE(sof_kwd_events),
1938 event_type);
1939 default:
1940 break;
1941 }
1942
1943 dev_err(sdev->dev,
1944 "error: invalid event type %d for widget %s\n",
1945 event_type, swidget->widget->name);
1946 return -EINVAL;
1947}
1948
1949/* external widget init - used for any driver specific init */
1950static int sof_widget_ready(struct snd_soc_component *scomp, int index,
1951 struct snd_soc_dapm_widget *w,
1952 struct snd_soc_tplg_dapm_widget *tw)
1953{
1954 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1955 struct snd_sof_widget *swidget;
1956 struct snd_sof_dai *dai;
1957 struct sof_ipc_comp_reply reply;
1958 struct snd_sof_control *scontrol;
1959 int ret = 0;
1960
1961 swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
1962 if (!swidget)
1963 return -ENOMEM;
1964
1965 swidget->sdev = sdev;
1966 swidget->widget = w;
1967 swidget->comp_id = sdev->next_comp_id++;
1968 swidget->complete = 0;
1969 swidget->id = w->id;
1970 swidget->pipeline_id = index;
1971 swidget->private = NULL;
1972 memset(&reply, 0, sizeof(reply));
1973
1974 dev_dbg(sdev->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n",
1975 swidget->comp_id, index, swidget->id, tw->name,
1976 strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
1977 ? tw->sname : "none");
1978
1979 /* handle any special case widgets */
1980 switch (w->id) {
1981 case snd_soc_dapm_dai_in:
1982 case snd_soc_dapm_dai_out:
1983 dai = kzalloc(sizeof(*dai), GFP_KERNEL);
1984 if (!dai) {
1985 kfree(swidget);
1986 return -ENOMEM;
1987 }
1988
1989 ret = sof_widget_load_dai(scomp, index, swidget, tw, &reply,
1990 dai);
1991 if (ret == 0) {
1992 sof_connect_dai_widget(scomp, w, tw, dai);
1993 list_add(&dai->list, &sdev->dai_list);
1994 swidget->private = dai;
1995 } else {
1996 kfree(dai);
1997 }
1998 break;
1999 case snd_soc_dapm_mixer:
2000 ret = sof_widget_load_mixer(scomp, index, swidget, tw, &reply);
2001 break;
2002 case snd_soc_dapm_pga:
2003 ret = sof_widget_load_pga(scomp, index, swidget, tw, &reply);
2004 /* Find scontrol for this pga and set readback offset*/
2005 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
2006 if (scontrol->comp_id == swidget->comp_id) {
2007 scontrol->readback_offset = reply.offset;
2008 break;
2009 }
2010 }
2011 break;
2012 case snd_soc_dapm_buffer:
2013 ret = sof_widget_load_buffer(scomp, index, swidget, tw, &reply);
2014 break;
2015 case snd_soc_dapm_scheduler:
2016 ret = sof_widget_load_pipeline(scomp, index, swidget, tw,
2017 &reply);
2018 break;
2019 case snd_soc_dapm_aif_out:
2020 ret = sof_widget_load_pcm(scomp, index, swidget,
2021 SOF_IPC_STREAM_CAPTURE, tw, &reply);
2022 break;
2023 case snd_soc_dapm_aif_in:
2024 ret = sof_widget_load_pcm(scomp, index, swidget,
2025 SOF_IPC_STREAM_PLAYBACK, tw, &reply);
2026 break;
2027 case snd_soc_dapm_src:
2028 ret = sof_widget_load_src(scomp, index, swidget, tw, &reply);
2029 break;
2030 case snd_soc_dapm_siggen:
2031 ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply);
2032 break;
2033 case snd_soc_dapm_effect:
2034 ret = sof_widget_load_process(scomp, index, swidget, tw,
2035 &reply);
2036 break;
2037 case snd_soc_dapm_mux:
2038 case snd_soc_dapm_demux:
2039 ret = sof_widget_load_mux(scomp, index, swidget, tw, &reply);
2040 break;
2041 case snd_soc_dapm_switch:
2042 case snd_soc_dapm_dai_link:
2043 case snd_soc_dapm_kcontrol:
2044 default:
2045 dev_warn(sdev->dev, "warning: widget type %d name %s not handled\n",
2046 swidget->id, tw->name);
2047 break;
2048 }
2049
2050 /* check IPC reply */
2051 if (ret < 0 || reply.rhdr.error < 0) {
2052 dev_err(sdev->dev,
2053 "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n",
2054 tw->shift, swidget->id, tw->name,
2055 strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
2056 ? tw->sname : "none", reply.rhdr.error);
2057 kfree(swidget);
2058 return ret;
2059 }
2060
2061 /* bind widget to external event */
2062 if (tw->event_type) {
2063 ret = sof_widget_bind_event(sdev, swidget,
2064 le16_to_cpu(tw->event_type));
2065 if (ret) {
2066 dev_err(sdev->dev, "error: widget event binding failed\n");
2067 kfree(swidget->private);
2068 kfree(swidget);
2069 return ret;
2070 }
2071 }
2072
2073 w->dobj.private = swidget;
2074 list_add(&swidget->list, &sdev->widget_list);
2075 return ret;
2076}
2077
2078static int sof_route_unload(struct snd_soc_component *scomp,
2079 struct snd_soc_dobj *dobj)
2080{
2081 struct snd_sof_route *sroute;
2082
2083 sroute = dobj->private;
2084 if (!sroute)
2085 return 0;
2086
2087 /* free sroute and its private data */
2088 kfree(sroute->private);
2089 list_del(&sroute->list);
2090 kfree(sroute);
2091
2092 return 0;
2093}
2094
2095static int sof_widget_unload(struct snd_soc_component *scomp,
2096 struct snd_soc_dobj *dobj)
2097{
2098 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2099 const struct snd_kcontrol_new *kc;
2100 struct snd_soc_dapm_widget *widget;
2101 struct sof_ipc_pipe_new *pipeline;
2102 struct snd_sof_control *scontrol;
2103 struct snd_sof_widget *swidget;
2104 struct soc_mixer_control *sm;
2105 struct soc_bytes_ext *sbe;
2106 struct snd_sof_dai *dai;
2107 struct soc_enum *se;
2108 int ret = 0;
2109 int i;
2110
2111 swidget = dobj->private;
2112 if (!swidget)
2113 return 0;
2114
2115 widget = swidget->widget;
2116
2117 switch (swidget->id) {
2118 case snd_soc_dapm_dai_in:
2119 case snd_soc_dapm_dai_out:
2120 dai = swidget->private;
2121
2122 if (dai) {
2123 /* free dai config */
2124 kfree(dai->dai_config);
2125 list_del(&dai->list);
2126 }
2127 break;
2128 case snd_soc_dapm_scheduler:
2129
2130 /* power down the pipeline schedule core */
2131 pipeline = swidget->private;
2132 ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
2133 if (ret < 0)
2134 dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n",
2135 pipeline->core);
2136
2137 /* update enabled cores mask */
2138 sdev->enabled_cores_mask &= ~(1 << pipeline->core);
2139
2140 break;
2141 default:
2142 break;
2143 }
2144 for (i = 0; i < widget->num_kcontrols; i++) {
2145 kc = &widget->kcontrol_news[i];
2146 switch (dobj->widget.kcontrol_type) {
2147 case SND_SOC_TPLG_TYPE_MIXER:
2148 sm = (struct soc_mixer_control *)kc->private_value;
2149 scontrol = sm->dobj.private;
2150 if (sm->max > 1)
2151 kfree(scontrol->volume_table);
2152 break;
2153 case SND_SOC_TPLG_TYPE_ENUM:
2154 se = (struct soc_enum *)kc->private_value;
2155 scontrol = se->dobj.private;
2156 break;
2157 case SND_SOC_TPLG_TYPE_BYTES:
2158 sbe = (struct soc_bytes_ext *)kc->private_value;
2159 scontrol = sbe->dobj.private;
2160 break;
2161 default:
2162 dev_warn(sdev->dev, "unsupported kcontrol_type\n");
2163 goto out;
2164 }
2165 kfree(scontrol->control_data);
2166 list_del(&scontrol->list);
2167 kfree(scontrol);
2168 }
2169
2170out:
2171 /* free private value */
2172 kfree(swidget->private);
2173
2174 /* remove and free swidget object */
2175 list_del(&swidget->list);
2176 kfree(swidget);
2177
2178 return ret;
2179}
2180
2181/*
2182 * DAI HW configuration.
2183 */
2184
2185/* FE DAI - used for any driver specific init */
2186static int sof_dai_load(struct snd_soc_component *scomp, int index,
2187 struct snd_soc_dai_driver *dai_drv,
2188 struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
2189{
2190 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2191 struct snd_soc_tplg_stream_caps *caps;
2192 struct snd_sof_pcm *spcm;
2193 int stream = SNDRV_PCM_STREAM_PLAYBACK;
2194 int ret = 0;
2195
2196 /* nothing to do for BEs atm */
2197 if (!pcm)
2198 return 0;
2199
2200 spcm = kzalloc(sizeof(*spcm), GFP_KERNEL);
2201 if (!spcm)
2202 return -ENOMEM;
2203
2204 spcm->sdev = sdev;
2205 spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED;
2206 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED;
2207
2208 if (pcm) {
2209 spcm->pcm = *pcm;
2210 dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name);
2211 }
2212 dai_drv->dobj.private = spcm;
2213 list_add(&spcm->list, &sdev->pcm_list);
2214
2215 /* do we need to allocate playback PCM DMA pages */
2216 if (!spcm->pcm.playback)
2217 goto capture;
2218
2219 caps = &spcm->pcm.caps[stream];
2220
2221 /* allocate playback page table buffer */
2222 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
2223 PAGE_SIZE, &spcm->stream[stream].page_table);
2224 if (ret < 0) {
2225 dev_err(sdev->dev, "error: can't alloc page table for %s %d\n",
2226 caps->name, ret);
2227
2228 return ret;
2229 }
2230
2231 /* bind pcm to host comp */
2232 ret = spcm_bind(sdev, spcm, stream);
2233 if (ret) {
2234 dev_err(sdev->dev,
2235 "error: can't bind pcm to host\n");
2236 goto free_playback_tables;
2237 }
2238
2239capture:
2240 stream = SNDRV_PCM_STREAM_CAPTURE;
2241
2242 /* do we need to allocate capture PCM DMA pages */
2243 if (!spcm->pcm.capture)
2244 return ret;
2245
2246 caps = &spcm->pcm.caps[stream];
2247
2248 /* allocate capture page table buffer */
2249 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
2250 PAGE_SIZE, &spcm->stream[stream].page_table);
2251 if (ret < 0) {
2252 dev_err(sdev->dev, "error: can't alloc page table for %s %d\n",
2253 caps->name, ret);
2254 goto free_playback_tables;
2255 }
2256
2257 /* bind pcm to host comp */
2258 ret = spcm_bind(sdev, spcm, stream);
2259 if (ret) {
2260 dev_err(sdev->dev,
2261 "error: can't bind pcm to host\n");
2262 snd_dma_free_pages(&spcm->stream[stream].page_table);
2263 goto free_playback_tables;
2264 }
2265
2266 return ret;
2267
2268free_playback_tables:
2269 if (spcm->pcm.playback)
2270 snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table);
2271
2272 return ret;
2273}
2274
2275static int sof_dai_unload(struct snd_soc_component *scomp,
2276 struct snd_soc_dobj *dobj)
2277{
2278 struct snd_sof_pcm *spcm = dobj->private;
2279
2280 /* free PCM DMA pages */
2281 if (spcm->pcm.playback)
2282 snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table);
2283
2284 if (spcm->pcm.capture)
2285 snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table);
2286
2287 /* remove from list and free spcm */
2288 list_del(&spcm->list);
2289 kfree(spcm);
2290
2291 return 0;
2292}
2293
2294static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
2295 struct sof_ipc_dai_config *config)
2296{
2297 /* clock directions wrt codec */
2298 if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) {
2299 /* codec is bclk master */
2300 if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
2301 config->format |= SOF_DAI_FMT_CBM_CFM;
2302 else
2303 config->format |= SOF_DAI_FMT_CBM_CFS;
2304 } else {
2305 /* codec is bclk slave */
2306 if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM)
2307 config->format |= SOF_DAI_FMT_CBS_CFM;
2308 else
2309 config->format |= SOF_DAI_FMT_CBS_CFS;
2310 }
2311
2312 /* inverted clocks ? */
2313 if (hw_config->invert_bclk) {
2314 if (hw_config->invert_fsync)
2315 config->format |= SOF_DAI_FMT_IB_IF;
2316 else
2317 config->format |= SOF_DAI_FMT_IB_NF;
2318 } else {
2319 if (hw_config->invert_fsync)
2320 config->format |= SOF_DAI_FMT_NB_IF;
2321 else
2322 config->format |= SOF_DAI_FMT_NB_NF;
2323 }
2324}
2325
2326/* set config for all DAI's with name matching the link name */
2327static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size,
2328 struct snd_soc_dai_link *link,
2329 struct sof_ipc_dai_config *config)
2330{
2331 struct snd_sof_dai *dai;
2332 int found = 0;
2333
2334 list_for_each_entry(dai, &sdev->dai_list, list) {
2335 if (!dai->name)
2336 continue;
2337
2338 if (strcmp(link->name, dai->name) == 0) {
2339 dai->dai_config = kmemdup(config, size, GFP_KERNEL);
2340 if (!dai->dai_config)
2341 return -ENOMEM;
2342
2343 found = 1;
2344 }
2345 }
2346
2347 /*
2348 * machine driver may define a dai link with playback and capture
2349 * dai enabled, but the dai link in topology would support both, one
2350 * or none of them. Here print a warning message to notify user
2351 */
2352 if (!found) {
2353 dev_warn(sdev->dev, "warning: failed to find dai for dai link %s",
2354 link->name);
2355 }
2356
2357 return 0;
2358}
2359
2360static int sof_link_ssp_load(struct snd_soc_component *scomp, int index,
2361 struct snd_soc_dai_link *link,
2362 struct snd_soc_tplg_link_config *cfg,
2363 struct snd_soc_tplg_hw_config *hw_config,
2364 struct sof_ipc_dai_config *config)
2365{
2366 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2367 struct snd_soc_tplg_private *private = &cfg->priv;
2368 struct sof_ipc_reply reply;
2369 u32 size = sizeof(*config);
2370 int ret;
2371
2372 /* handle master/slave and inverted clocks */
2373 sof_dai_set_format(hw_config, config);
2374
2375 /* init IPC */
2376 memset(&config->ssp, 0, sizeof(struct sof_ipc_dai_ssp_params));
2377 config->hdr.size = size;
2378
2379 ret = sof_parse_tokens(scomp, &config->ssp, ssp_tokens,
2380 ARRAY_SIZE(ssp_tokens), private->array,
2381 le32_to_cpu(private->size));
2382 if (ret != 0) {
2383 dev_err(sdev->dev, "error: parse ssp tokens failed %d\n",
2384 le32_to_cpu(private->size));
2385 return ret;
2386 }
2387
2388 config->ssp.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
2389 config->ssp.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
2390 config->ssp.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
2391 config->ssp.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
2392 config->ssp.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
2393 config->ssp.mclk_direction = hw_config->mclk_direction;
2394 config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots);
2395 config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots);
2396
2397 dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n",
2398 config->dai_index, config->format,
2399 config->ssp.mclk_rate, config->ssp.bclk_rate,
2400 config->ssp.fsync_rate, config->ssp.sample_valid_bits,
2401 config->ssp.tdm_slot_width, config->ssp.tdm_slots,
2402 config->ssp.mclk_id, config->ssp.quirks);
2403
2404 /* validate SSP fsync rate and channel count */
2405 if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) {
2406 dev_err(sdev->dev, "error: invalid fsync rate for SSP%d\n",
2407 config->dai_index);
2408 return -EINVAL;
2409 }
2410
2411 if (config->ssp.tdm_slots < 1 || config->ssp.tdm_slots > 8) {
2412 dev_err(sdev->dev, "error: invalid channel count for SSP%d\n",
2413 config->dai_index);
2414 return -EINVAL;
2415 }
2416
2417 /* send message to DSP */
2418 ret = sof_ipc_tx_message(sdev->ipc,
2419 config->hdr.cmd, config, size, &reply,
2420 sizeof(reply));
2421
2422 if (ret < 0) {
2423 dev_err(sdev->dev, "error: failed to set DAI config for SSP%d\n",
2424 config->dai_index);
2425 return ret;
2426 }
2427
2428 /* set config for all DAI's with name matching the link name */
2429 ret = sof_set_dai_config(sdev, size, link, config);
2430 if (ret < 0)
2431 dev_err(sdev->dev, "error: failed to save DAI config for SSP%d\n",
2432 config->dai_index);
2433
2434 return ret;
2435}
2436
2437static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
2438 struct snd_soc_dai_link *link,
2439 struct snd_soc_tplg_link_config *cfg,
2440 struct snd_soc_tplg_hw_config *hw_config,
2441 struct sof_ipc_dai_config *config)
2442{
2443 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2444 struct snd_soc_tplg_private *private = &cfg->priv;
2445 struct sof_ipc_dai_config *ipc_config;
2446 struct sof_ipc_reply reply;
2447 struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
2448 struct sof_ipc_fw_version *v = &ready->version;
2449 u32 size;
2450 int ret, j;
2451
2452 /*
2453 * config is only used for the common params in dmic_params structure
2454 * that does not include the PDM controller config array
2455 * Set the common params to 0.
2456 */
2457 memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params));
2458
2459 /* get DMIC tokens */
2460 ret = sof_parse_tokens(scomp, &config->dmic, dmic_tokens,
2461 ARRAY_SIZE(dmic_tokens), private->array,
2462 le32_to_cpu(private->size));
2463 if (ret != 0) {
2464 dev_err(sdev->dev, "error: parse dmic tokens failed %d\n",
2465 le32_to_cpu(private->size));
2466 return ret;
2467 }
2468
2469 /*
2470 * allocate memory for dmic dai config accounting for the
2471 * variable number of active pdm controllers
2472 * This will be the ipc payload for setting dai config
2473 */
2474 size = sizeof(*config) + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) *
2475 config->dmic.num_pdm_active;
2476
2477 ipc_config = kzalloc(size, GFP_KERNEL);
2478 if (!ipc_config)
2479 return -ENOMEM;
2480
2481 /* copy the common dai config and dmic params */
2482 memcpy(ipc_config, config, sizeof(*config));
2483
2484 /*
2485 * alloc memory for private member
2486 * Used to track the pdm config array index currently being parsed
2487 */
2488 sdev->private = kzalloc(sizeof(u32), GFP_KERNEL);
2489 if (!sdev->private) {
2490 kfree(ipc_config);
2491 return -ENOMEM;
2492 }
2493
2494 /* get DMIC PDM tokens */
2495 ret = sof_parse_tokens(scomp, &ipc_config->dmic.pdm[0], dmic_pdm_tokens,
2496 ARRAY_SIZE(dmic_pdm_tokens), private->array,
2497 le32_to_cpu(private->size));
2498 if (ret != 0) {
2499 dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n",
2500 le32_to_cpu(private->size));
2501 goto err;
2502 }
2503
2504 /* set IPC header size */
2505 ipc_config->hdr.size = size;
2506
2507 /* debug messages */
2508 dev_dbg(sdev->dev, "tplg: config DMIC%d driver version %d\n",
2509 ipc_config->dai_index, ipc_config->dmic.driver_ipc_version);
2510 dev_dbg(sdev->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n",
2511 ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max,
2512 ipc_config->dmic.duty_min);
2513 dev_dbg(sdev->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n",
2514 ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs,
2515 ipc_config->dmic.num_pdm_active);
2516 dev_dbg(sdev->dev, "fifo word length %hd\n",
2517 ipc_config->dmic.fifo_bits);
2518
2519 for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) {
2520 dev_dbg(sdev->dev, "pdm %hd mic a %hd mic b %hd\n",
2521 ipc_config->dmic.pdm[j].id,
2522 ipc_config->dmic.pdm[j].enable_mic_a,
2523 ipc_config->dmic.pdm[j].enable_mic_b);
2524 dev_dbg(sdev->dev, "pdm %hd polarity a %hd polarity b %hd\n",
2525 ipc_config->dmic.pdm[j].id,
2526 ipc_config->dmic.pdm[j].polarity_mic_a,
2527 ipc_config->dmic.pdm[j].polarity_mic_b);
2528 dev_dbg(sdev->dev, "pdm %hd clk_edge %hd skew %hd\n",
2529 ipc_config->dmic.pdm[j].id,
2530 ipc_config->dmic.pdm[j].clk_edge,
2531 ipc_config->dmic.pdm[j].skew);
2532 }
2533
2534 if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) {
2535 /* this takes care of backwards compatible handling of fifo_bits_b */
2536 ipc_config->dmic.reserved_2 = ipc_config->dmic.fifo_bits;
2537 }
2538
2539 /* send message to DSP */
2540 ret = sof_ipc_tx_message(sdev->ipc,
2541 ipc_config->hdr.cmd, ipc_config, size, &reply,
2542 sizeof(reply));
2543
2544 if (ret < 0) {
2545 dev_err(sdev->dev,
2546 "error: failed to set DAI config for DMIC%d\n",
2547 config->dai_index);
2548 goto err;
2549 }
2550
2551 /* set config for all DAI's with name matching the link name */
2552 ret = sof_set_dai_config(sdev, size, link, ipc_config);
2553 if (ret < 0)
2554 dev_err(sdev->dev, "error: failed to save DAI config for DMIC%d\n",
2555 config->dai_index);
2556
2557err:
2558 kfree(sdev->private);
2559 kfree(ipc_config);
2560
2561 return ret;
2562}
2563
2564/*
2565 * for hda link, playback and capture are supported by different dai
2566 * in FW. Here get the dai_index, set dma channel of each dai
2567 * and send config to FW. In FW, each dai sets config by dai_index
2568 */
2569static int sof_link_hda_process(struct snd_sof_dev *sdev,
2570 struct snd_soc_dai_link *link,
2571 struct sof_ipc_dai_config *config,
2572 int tx_slot,
2573 int rx_slot)
2574{
2575 struct sof_ipc_reply reply;
2576 u32 size = sizeof(*config);
2577 struct snd_sof_dai *sof_dai;
2578 int found = 0;
2579 int ret;
2580
2581 list_for_each_entry(sof_dai, &sdev->dai_list, list) {
2582 if (!sof_dai->name)
2583 continue;
2584
2585 if (strcmp(link->name, sof_dai->name) == 0) {
2586 if (sof_dai->comp_dai.direction ==
2587 SNDRV_PCM_STREAM_PLAYBACK) {
2588 if (!link->dpcm_playback)
2589 return -EINVAL;
2590
2591 config->hda.link_dma_ch = tx_slot;
2592 } else {
2593 if (!link->dpcm_capture)
2594 return -EINVAL;
2595
2596 config->hda.link_dma_ch = rx_slot;
2597 }
2598
2599 config->dai_index = sof_dai->comp_dai.dai_index;
2600 found = 1;
2601
2602 /* save config in dai component */
2603 sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
2604 if (!sof_dai->dai_config)
2605 return -ENOMEM;
2606
2607 /* send message to DSP */
2608 ret = sof_ipc_tx_message(sdev->ipc,
2609 config->hdr.cmd, config, size,
2610 &reply, sizeof(reply));
2611
2612 if (ret < 0) {
2613 dev_err(sdev->dev, "error: failed to set DAI config for direction:%d of HDA dai %d\n",
2614 sof_dai->comp_dai.direction,
2615 config->dai_index);
2616
2617 return ret;
2618 }
2619 }
2620 }
2621
2622 /*
2623 * machine driver may define a dai link with playback and capture
2624 * dai enabled, but the dai link in topology would support both, one
2625 * or none of them. Here print a warning message to notify user
2626 */
2627 if (!found) {
2628 dev_warn(sdev->dev, "warning: failed to find dai for dai link %s",
2629 link->name);
2630 }
2631
2632 return 0;
2633}
2634
2635static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
2636 struct snd_soc_dai_link *link,
2637 struct snd_soc_tplg_link_config *cfg,
2638 struct snd_soc_tplg_hw_config *hw_config,
2639 struct sof_ipc_dai_config *config)
2640{
2641 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2642 struct snd_soc_dai_link_component dai_component;
2643 struct snd_soc_tplg_private *private = &cfg->priv;
2644 struct snd_soc_dai *dai;
2645 u32 size = sizeof(*config);
2646 u32 tx_num = 0;
2647 u32 tx_slot = 0;
2648 u32 rx_num = 0;
2649 u32 rx_slot = 0;
2650 int ret;
2651
2652 /* init IPC */
2653 memset(&dai_component, 0, sizeof(dai_component));
2654 memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params));
2655 config->hdr.size = size;
2656
2657 /* get any bespoke DAI tokens */
2658 ret = sof_parse_tokens(scomp, config, hda_tokens,
2659 ARRAY_SIZE(hda_tokens), private->array,
2660 le32_to_cpu(private->size));
2661 if (ret != 0) {
2662 dev_err(sdev->dev, "error: parse hda tokens failed %d\n",
2663 le32_to_cpu(private->size));
2664 return ret;
2665 }
2666
2667 dai_component.dai_name = link->cpu_dai_name;
2668 dai = snd_soc_find_dai(&dai_component);
2669 if (!dai) {
2670 dev_err(sdev->dev, "error: failed to find dai %s in %s",
2671 dai_component.dai_name, __func__);
2672 return -EINVAL;
2673 }
2674
2675 if (link->dpcm_playback)
2676 tx_num = 1;
2677
2678 if (link->dpcm_capture)
2679 rx_num = 1;
2680
2681 ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot,
2682 &rx_num, &rx_slot);
2683 if (ret < 0) {
2684 dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n",
2685 config->dai_index);
2686
2687 return ret;
2688 }
2689
2690 ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot);
2691 if (ret < 0)
2692 dev_err(sdev->dev, "error: failed to process hda dai link %s",
2693 link->name);
2694
2695 return ret;
2696}
2697
2698/* DAI link - used for any driver specific init */
2699static int sof_link_load(struct snd_soc_component *scomp, int index,
2700 struct snd_soc_dai_link *link,
2701 struct snd_soc_tplg_link_config *cfg)
2702{
2703 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2704 struct snd_soc_tplg_private *private = &cfg->priv;
2705 struct sof_ipc_dai_config config;
2706 struct snd_soc_tplg_hw_config *hw_config;
2707 int num_hw_configs;
2708 int ret;
2709 int i = 0;
2710
2711 link->platform_name = dev_name(sdev->dev);
2712
2713 /*
2714 * Set nonatomic property for FE dai links as their trigger action
2715 * involves IPC's.
2716 */
2717 if (!link->no_pcm) {
2718 link->nonatomic = true;
2719
2720 /* nothing more to do for FE dai links */
2721 return 0;
2722 }
2723
2724 /* check we have some tokens - we need at least DAI type */
2725 if (le32_to_cpu(private->size) == 0) {
2726 dev_err(sdev->dev, "error: expected tokens for DAI, none found\n");
2727 return -EINVAL;
2728 }
2729
2730 /* Send BE DAI link configurations to DSP */
2731 memset(&config, 0, sizeof(config));
2732
2733 /* get any common DAI tokens */
2734 ret = sof_parse_tokens(scomp, &config, dai_link_tokens,
2735 ARRAY_SIZE(dai_link_tokens), private->array,
2736 le32_to_cpu(private->size));
2737 if (ret != 0) {
2738 dev_err(sdev->dev, "error: parse link tokens failed %d\n",
2739 le32_to_cpu(private->size));
2740 return ret;
2741 }
2742
2743 /*
2744 * DAI links are expected to have at least 1 hw_config.
2745 * But some older topologies might have no hw_config for HDA dai links.
2746 */
2747 num_hw_configs = le32_to_cpu(cfg->num_hw_configs);
2748 if (!num_hw_configs) {
2749 if (config.type != SOF_DAI_INTEL_HDA) {
2750 dev_err(sdev->dev, "error: unexpected DAI config count %d!\n",
2751 le32_to_cpu(cfg->num_hw_configs));
2752 return -EINVAL;
2753 }
2754 } else {
2755 dev_dbg(sdev->dev, "tplg: %d hw_configs found, default id: %d!\n",
2756 cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id));
2757
2758 for (i = 0; i < num_hw_configs; i++) {
2759 if (cfg->hw_config[i].id == cfg->default_hw_config_id)
2760 break;
2761 }
2762
2763 if (i == num_hw_configs) {
2764 dev_err(sdev->dev, "error: default hw_config id: %d not found!\n",
2765 le32_to_cpu(cfg->default_hw_config_id));
2766 return -EINVAL;
2767 }
2768 }
2769
2770 /* configure dai IPC message */
2771 hw_config = &cfg->hw_config[i];
2772
2773 config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
2774 config.format = le32_to_cpu(hw_config->fmt);
2775
2776 /* now load DAI specific data and send IPC - type comes from token */
2777 switch (config.type) {
2778 case SOF_DAI_INTEL_SSP:
2779 ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config,
2780 &config);
2781 break;
2782 case SOF_DAI_INTEL_DMIC:
2783 ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config,
2784 &config);
2785 break;
2786 case SOF_DAI_INTEL_HDA:
2787 ret = sof_link_hda_load(scomp, index, link, cfg, hw_config,
2788 &config);
2789 break;
2790 default:
2791 dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type);
2792 ret = -EINVAL;
2793 break;
2794 }
2795 if (ret < 0)
2796 return ret;
2797
2798 return 0;
2799}
2800
2801static int sof_link_hda_unload(struct snd_sof_dev *sdev,
2802 struct snd_soc_dai_link *link)
2803{
2804 struct snd_soc_dai_link_component dai_component;
2805 struct snd_soc_dai *dai;
2806 int ret = 0;
2807
2808 memset(&dai_component, 0, sizeof(dai_component));
2809 dai_component.dai_name = link->cpu_dai_name;
2810 dai = snd_soc_find_dai(&dai_component);
2811 if (!dai) {
2812 dev_err(sdev->dev, "error: failed to find dai %s in %s",
2813 dai_component.dai_name, __func__);
2814 return -EINVAL;
2815 }
2816
2817 /*
2818 * FIXME: this call to hw_free is mainly to release the link DMA ID.
2819 * This is abusing the API and handling SOC internals is not
2820 * recommended. This part will be reworked.
2821 */
2822 if (dai->driver->ops->hw_free)
2823 ret = dai->driver->ops->hw_free(NULL, dai);
2824 if (ret < 0)
2825 dev_err(sdev->dev, "error: failed to free hda resource for %s\n",
2826 link->name);
2827
2828 return ret;
2829}
2830
2831static int sof_link_unload(struct snd_soc_component *scomp,
2832 struct snd_soc_dobj *dobj)
2833{
2834 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2835 struct snd_soc_dai_link *link =
2836 container_of(dobj, struct snd_soc_dai_link, dobj);
2837
2838 struct snd_sof_dai *sof_dai;
2839 int ret = 0;
2840
2841 /* only BE link is loaded by sof */
2842 if (!link->no_pcm)
2843 return 0;
2844
2845 list_for_each_entry(sof_dai, &sdev->dai_list, list) {
2846 if (!sof_dai->name)
2847 continue;
2848
2849 if (strcmp(link->name, sof_dai->name) == 0)
2850 goto found;
2851 }
2852
2853 dev_err(sdev->dev, "error: failed to find dai %s in %s",
2854 link->name, __func__);
2855 return -EINVAL;
2856found:
2857
2858 switch (sof_dai->dai_config->type) {
2859 case SOF_DAI_INTEL_SSP:
2860 case SOF_DAI_INTEL_DMIC:
2861 /* no resource needs to be released for SSP and DMIC */
2862 break;
2863 case SOF_DAI_INTEL_HDA:
2864 ret = sof_link_hda_unload(sdev, link);
2865 break;
2866 default:
2867 dev_err(sdev->dev, "error: invalid DAI type %d\n",
2868 sof_dai->dai_config->type);
2869 ret = -EINVAL;
2870 break;
2871 }
2872
2873 return ret;
2874}
2875
2876/* DAI link - used for any driver specific init */
2877static int sof_route_load(struct snd_soc_component *scomp, int index,
2878 struct snd_soc_dapm_route *route)
2879{
2880 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
2881 struct sof_ipc_pipe_comp_connect *connect;
2882 struct snd_sof_widget *source_swidget, *sink_swidget;
2883 struct snd_soc_dobj *dobj = &route->dobj;
2884 struct snd_sof_route *sroute;
2885 struct sof_ipc_reply reply;
2886 int ret = 0;
2887
2888 /* allocate memory for sroute and connect */
2889 sroute = kzalloc(sizeof(*sroute), GFP_KERNEL);
2890 if (!sroute)
2891 return -ENOMEM;
2892
2893 sroute->sdev = sdev;
2894
2895 connect = kzalloc(sizeof(*connect), GFP_KERNEL);
2896 if (!connect) {
2897 kfree(sroute);
2898 return -ENOMEM;
2899 }
2900
2901 connect->hdr.size = sizeof(*connect);
2902 connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
2903
2904 dev_dbg(sdev->dev, "sink %s control %s source %s\n",
2905 route->sink, route->control ? route->control : "none",
2906 route->source);
2907
2908 /* source component */
2909 source_swidget = snd_sof_find_swidget(sdev, (char *)route->source);
2910 if (!source_swidget) {
2911 dev_err(sdev->dev, "error: source %s not found\n",
2912 route->source);
2913 ret = -EINVAL;
2914 goto err;
2915 }
2916
2917 /*
2918 * Virtual widgets of type output/out_drv may be added in topology
2919 * for compatibility. These are not handled by the FW.
2920 * So, don't send routes whose source/sink widget is of such types
2921 * to the DSP.
2922 */
2923 if (source_swidget->id == snd_soc_dapm_out_drv ||
2924 source_swidget->id == snd_soc_dapm_output)
2925 goto err;
2926
2927 connect->source_id = source_swidget->comp_id;
2928
2929 /* sink component */
2930 sink_swidget = snd_sof_find_swidget(sdev, (char *)route->sink);
2931 if (!sink_swidget) {
2932 dev_err(sdev->dev, "error: sink %s not found\n",
2933 route->sink);
2934 ret = -EINVAL;
2935 goto err;
2936 }
2937
2938 /*
2939 * Don't send routes whose sink widget is of type
2940 * output or out_drv to the DSP
2941 */
2942 if (sink_swidget->id == snd_soc_dapm_out_drv ||
2943 sink_swidget->id == snd_soc_dapm_output)
2944 goto err;
2945
2946 connect->sink_id = sink_swidget->comp_id;
2947
2948 /*
2949 * For virtual routes, both sink and source are not
2950 * buffer. Since only buffer linked to component is supported by
2951 * FW, others are reported as error, add check in route function,
2952 * do not send it to FW when both source and sink are not buffer
2953 */
2954 if (source_swidget->id != snd_soc_dapm_buffer &&
2955 sink_swidget->id != snd_soc_dapm_buffer) {
2956 dev_dbg(sdev->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n",
2957 route->source, route->sink);
2958 ret = 0;
2959 goto err;
2960 } else {
2961 ret = sof_ipc_tx_message(sdev->ipc,
2962 connect->hdr.cmd,
2963 connect, sizeof(*connect),
2964 &reply, sizeof(reply));
2965
2966 /* check IPC return value */
2967 if (ret < 0) {
2968 dev_err(sdev->dev, "error: failed to add route sink %s control %s source %s\n",
2969 route->sink,
2970 route->control ? route->control : "none",
2971 route->source);
2972 goto err;
2973 }
2974
2975 /* check IPC reply */
2976 if (reply.error < 0) {
2977 dev_err(sdev->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n",
2978 route->sink,
2979 route->control ? route->control : "none",
2980 route->source, reply.error);
2981 ret = reply.error;
2982 goto err;
2983 }
2984
2985 sroute->route = route;
2986 dobj->private = sroute;
2987 sroute->private = connect;
2988
2989 /* add route to route list */
2990 list_add(&sroute->list, &sdev->route_list);
2991
2992 return ret;
2993 }
2994
2995err:
2996 kfree(connect);
2997 kfree(sroute);
2998 return ret;
2999}
3000
3001int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
3002 struct snd_sof_widget *swidget)
3003{
3004 struct sof_ipc_pipe_ready ready;
3005 struct sof_ipc_reply reply;
3006 int ret;
3007
3008 dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
3009 swidget->widget->name, swidget->comp_id);
3010
3011 memset(&ready, 0, sizeof(ready));
3012 ready.hdr.size = sizeof(ready);
3013 ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
3014 ready.comp_id = swidget->comp_id;
3015
3016 ret = sof_ipc_tx_message(sdev->ipc,
3017 ready.hdr.cmd, &ready, sizeof(ready), &reply,
3018 sizeof(reply));
3019 if (ret < 0)
3020 return ret;
3021 return 1;
3022}
3023
3024/* completion - called at completion of firmware loading */
3025static void sof_complete(struct snd_soc_component *scomp)
3026{
3027 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3028 struct snd_sof_widget *swidget;
3029
3030 /* some widget types require completion notificattion */
3031 list_for_each_entry(swidget, &sdev->widget_list, list) {
3032 if (swidget->complete)
3033 continue;
3034
3035 switch (swidget->id) {
3036 case snd_soc_dapm_scheduler:
3037 swidget->complete =
3038 snd_sof_complete_pipeline(sdev, swidget);
3039 break;
3040 default:
3041 break;
3042 }
3043 }
3044}
3045
3046/* manifest - optional to inform component of manifest */
3047static int sof_manifest(struct snd_soc_component *scomp, int index,
3048 struct snd_soc_tplg_manifest *man)
3049{
3050 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
3051 u32 size;
3052 u32 abi_version;
3053
3054 size = le32_to_cpu(man->priv.size);
3055
3056 /* backward compatible with tplg without ABI info */
3057 if (!size) {
3058 dev_dbg(sdev->dev, "No topology ABI info\n");
3059 return 0;
3060 }
3061
3062 if (size != SOF_TPLG_ABI_SIZE) {
3063 dev_err(sdev->dev, "error: invalid topology ABI size\n");
3064 return -EINVAL;
3065 }
3066
3067 dev_info(sdev->dev,
3068 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
3069 man->priv.data[0], man->priv.data[1],
3070 man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
3071 SOF_ABI_PATCH);
3072
3073 abi_version = SOF_ABI_VER(man->priv.data[0],
3074 man->priv.data[1],
3075 man->priv.data[2]);
3076
3077 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
3078 dev_err(sdev->dev, "error: incompatible topology ABI version\n");
3079 return -EINVAL;
3080 }
3081
3082 if (abi_version > SOF_ABI_VERSION) {
3083 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
3084 dev_warn(sdev->dev, "warn: topology ABI is more recent than kernel\n");
3085 } else {
3086 dev_err(sdev->dev, "error: topology ABI is more recent than kernel\n");
3087 return -EINVAL;
3088 }
3089 }
3090
3091 return 0;
3092}
3093
3094/* vendor specific kcontrol handlers available for binding */
3095static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = {
3096 {SOF_TPLG_KCTL_VOL_ID, snd_sof_volume_get, snd_sof_volume_put},
3097 {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_get, snd_sof_bytes_put},
3098 {SOF_TPLG_KCTL_ENUM_ID, snd_sof_enum_get, snd_sof_enum_put},
3099 {SOF_TPLG_KCTL_SWITCH_ID, snd_sof_switch_get, snd_sof_switch_put},
3100};
3101
3102/* vendor specific bytes ext handlers available for binding */
3103static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = {
3104 {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_ext_get, snd_sof_bytes_ext_put},
3105};
3106
3107static struct snd_soc_tplg_ops sof_tplg_ops = {
3108 /* external kcontrol init - used for any driver specific init */
3109 .control_load = sof_control_load,
3110 .control_unload = sof_control_unload,
3111
3112 /* external kcontrol init - used for any driver specific init */
3113 .dapm_route_load = sof_route_load,
3114 .dapm_route_unload = sof_route_unload,
3115
3116 /* external widget init - used for any driver specific init */
3117 /* .widget_load is not currently used */
3118 .widget_ready = sof_widget_ready,
3119 .widget_unload = sof_widget_unload,
3120
3121 /* FE DAI - used for any driver specific init */
3122 .dai_load = sof_dai_load,
3123 .dai_unload = sof_dai_unload,
3124
3125 /* DAI link - used for any driver specific init */
3126 .link_load = sof_link_load,
3127 .link_unload = sof_link_unload,
3128
3129 /* completion - called at completion of firmware loading */
3130 .complete = sof_complete,
3131
3132 /* manifest - optional to inform component of manifest */
3133 .manifest = sof_manifest,
3134
3135 /* vendor specific kcontrol handlers available for binding */
3136 .io_ops = sof_io_ops,
3137 .io_ops_count = ARRAY_SIZE(sof_io_ops),
3138
3139 /* vendor specific bytes ext handlers available for binding */
3140 .bytes_ext_ops = sof_bytes_ext_ops,
3141 .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops),
3142};
3143
3144int snd_sof_init_topology(struct snd_sof_dev *sdev,
3145 struct snd_soc_tplg_ops *ops)
3146{
3147 /* TODO: support linked list of topologies */
3148 sdev->tplg_ops = ops;
3149 return 0;
3150}
3151EXPORT_SYMBOL(snd_sof_init_topology);
3152
3153int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file)
3154{
3155 const struct firmware *fw;
3156 int ret;
3157
3158 dev_dbg(sdev->dev, "loading topology:%s\n", file);
3159
3160 ret = request_firmware(&fw, file, sdev->dev);
3161 if (ret < 0) {
3162 dev_err(sdev->dev, "error: tplg request firmware %s failed err: %d\n",
3163 file, ret);
3164 return ret;
3165 }
3166
3167 ret = snd_soc_tplg_component_load(sdev->component,
3168 &sof_tplg_ops, fw,
3169 SND_SOC_TPLG_INDEX_ALL);
3170 if (ret < 0) {
3171 dev_err(sdev->dev, "error: tplg component load failed %d\n",
3172 ret);
3173 ret = -EINVAL;
3174 }
3175
3176 release_firmware(fw);
3177 return ret;
3178}
3179EXPORT_SYMBOL(snd_sof_load_topology);
diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c
new file mode 100644
index 000000000000..d588e4b70fad
--- /dev/null
+++ b/sound/soc/sof/trace.c
@@ -0,0 +1,297 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9//
10
11#include <linux/debugfs.h>
12#include <linux/sched/signal.h>
13#include "sof-priv.h"
14#include "ops.h"
15
16static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev,
17 loff_t pos, size_t buffer_size)
18{
19 wait_queue_entry_t wait;
20 loff_t host_offset = READ_ONCE(sdev->host_offset);
21
22 /*
23 * If host offset is less than local pos, it means write pointer of
24 * host DMA buffer has been wrapped. We should output the trace data
25 * at the end of host DMA buffer at first.
26 */
27 if (host_offset < pos)
28 return buffer_size - pos;
29
30 /* If there is available trace data now, it is unnecessary to wait. */
31 if (host_offset > pos)
32 return host_offset - pos;
33
34 /* wait for available trace data from FW */
35 init_waitqueue_entry(&wait, current);
36 set_current_state(TASK_INTERRUPTIBLE);
37 add_wait_queue(&sdev->trace_sleep, &wait);
38
39 if (!signal_pending(current)) {
40 /* set timeout to max value, no error code */
41 schedule_timeout(MAX_SCHEDULE_TIMEOUT);
42 }
43 remove_wait_queue(&sdev->trace_sleep, &wait);
44
45 /* return bytes available for copy */
46 host_offset = READ_ONCE(sdev->host_offset);
47 if (host_offset < pos)
48 return buffer_size - pos;
49
50 return host_offset - pos;
51}
52
53static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer,
54 size_t count, loff_t *ppos)
55{
56 struct snd_sof_dfsentry *dfse = file->private_data;
57 struct snd_sof_dev *sdev = dfse->sdev;
58 unsigned long rem;
59 loff_t lpos = *ppos;
60 size_t avail, buffer_size = dfse->size;
61 u64 lpos_64;
62
63 /* make sure we know about any failures on the DSP side */
64 sdev->dtrace_error = false;
65
66 /* check pos and count */
67 if (lpos < 0)
68 return -EINVAL;
69 if (!count)
70 return 0;
71
72 /* check for buffer wrap and count overflow */
73 lpos_64 = lpos;
74 lpos = do_div(lpos_64, buffer_size);
75
76 if (count > buffer_size - lpos) /* min() not used to avoid sparse warnings */
77 count = buffer_size - lpos;
78
79 /* get available count based on current host offset */
80 avail = sof_wait_trace_avail(sdev, lpos, buffer_size);
81 if (sdev->dtrace_error) {
82 dev_err(sdev->dev, "error: trace IO error\n");
83 return -EIO;
84 }
85
86 /* make sure count is <= avail */
87 count = avail > count ? count : avail;
88
89 /* copy available trace data to debugfs */
90 rem = copy_to_user(buffer, ((u8 *)(dfse->buf) + lpos), count);
91 if (rem)
92 return -EFAULT;
93
94 *ppos += count;
95
96 /* move debugfs reading position */
97 return count;
98}
99
100static const struct file_operations sof_dfs_trace_fops = {
101 .open = simple_open,
102 .read = sof_dfsentry_trace_read,
103 .llseek = default_llseek,
104};
105
106static int trace_debugfs_create(struct snd_sof_dev *sdev)
107{
108 struct snd_sof_dfsentry *dfse;
109
110 if (!sdev)
111 return -EINVAL;
112
113 dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL);
114 if (!dfse)
115 return -ENOMEM;
116
117 dfse->type = SOF_DFSENTRY_TYPE_BUF;
118 dfse->buf = sdev->dmatb.area;
119 dfse->size = sdev->dmatb.bytes;
120 dfse->sdev = sdev;
121
122 dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root,
123 dfse, &sof_dfs_trace_fops);
124 if (!dfse->dfsentry) {
125 /* can't rely on debugfs, only log error and keep going */
126 dev_err(sdev->dev,
127 "error: cannot create debugfs entry for trace\n");
128 }
129
130 return 0;
131}
132
133int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev)
134{
135 struct sof_ipc_dma_trace_params params;
136 struct sof_ipc_reply ipc_reply;
137 int ret;
138
139 if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages)
140 return -EINVAL;
141
142 /* set IPC parameters */
143 params.hdr.size = sizeof(params);
144 params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_PARAMS;
145 params.buffer.phy_addr = sdev->dmatp.addr;
146 params.buffer.size = sdev->dmatb.bytes;
147 params.buffer.pages = sdev->dma_trace_pages;
148 params.stream_tag = 0;
149
150 sdev->host_offset = 0;
151
152 ret = snd_sof_dma_trace_init(sdev, &params.stream_tag);
153 if (ret < 0) {
154 dev_err(sdev->dev,
155 "error: fail in snd_sof_dma_trace_init %d\n", ret);
156 return ret;
157 }
158 dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag);
159
160 /* send IPC to the DSP */
161 ret = sof_ipc_tx_message(sdev->ipc,
162 params.hdr.cmd, &params, sizeof(params),
163 &ipc_reply, sizeof(ipc_reply));
164 if (ret < 0) {
165 dev_err(sdev->dev,
166 "error: can't set params for DMA for trace %d\n", ret);
167 goto trace_release;
168 }
169
170 ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START);
171 if (ret < 0) {
172 dev_err(sdev->dev,
173 "error: snd_sof_dma_trace_trigger: start: %d\n", ret);
174 goto trace_release;
175 }
176
177 sdev->dtrace_is_enabled = true;
178
179 return 0;
180
181trace_release:
182 snd_sof_dma_trace_release(sdev);
183 return ret;
184}
185
186int snd_sof_init_trace(struct snd_sof_dev *sdev)
187{
188 int ret;
189
190 /* set false before start initialization */
191 sdev->dtrace_is_enabled = false;
192
193 /* allocate trace page table buffer */
194 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev,
195 PAGE_SIZE, &sdev->dmatp);
196 if (ret < 0) {
197 dev_err(sdev->dev,
198 "error: can't alloc page table for trace %d\n", ret);
199 return ret;
200 }
201
202 /* allocate trace data buffer */
203 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
204 DMA_BUF_SIZE_FOR_TRACE, &sdev->dmatb);
205 if (ret < 0) {
206 dev_err(sdev->dev,
207 "error: can't alloc buffer for trace %d\n", ret);
208 goto page_err;
209 }
210
211 /* create compressed page table for audio firmware */
212 ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area,
213 sdev->dmatb.bytes);
214 if (ret < 0)
215 goto table_err;
216
217 sdev->dma_trace_pages = ret;
218 dev_dbg(sdev->dev, "dma_trace_pages: %d\n", sdev->dma_trace_pages);
219
220 if (sdev->first_boot) {
221 ret = trace_debugfs_create(sdev);
222 if (ret < 0)
223 goto table_err;
224 }
225
226 init_waitqueue_head(&sdev->trace_sleep);
227
228 ret = snd_sof_init_trace_ipc(sdev);
229 if (ret < 0)
230 goto table_err;
231
232 return 0;
233table_err:
234 sdev->dma_trace_pages = 0;
235 snd_dma_free_pages(&sdev->dmatb);
236page_err:
237 snd_dma_free_pages(&sdev->dmatp);
238 return ret;
239}
240EXPORT_SYMBOL(snd_sof_init_trace);
241
242int snd_sof_trace_update_pos(struct snd_sof_dev *sdev,
243 struct sof_ipc_dma_trace_posn *posn)
244{
245 if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) {
246 sdev->host_offset = posn->host_offset;
247 wake_up(&sdev->trace_sleep);
248 }
249
250 if (posn->overflow != 0)
251 dev_err(sdev->dev,
252 "error: DSP trace buffer overflow %u bytes. Total messages %d\n",
253 posn->overflow, posn->messages);
254
255 return 0;
256}
257
258/* an error has occurred within the DSP that prevents further trace */
259void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev)
260{
261 if (sdev->dtrace_is_enabled) {
262 dev_err(sdev->dev, "error: waking up any trace sleepers\n");
263 sdev->dtrace_error = true;
264 wake_up(&sdev->trace_sleep);
265 }
266}
267EXPORT_SYMBOL(snd_sof_trace_notify_for_error);
268
269void snd_sof_release_trace(struct snd_sof_dev *sdev)
270{
271 int ret;
272
273 if (!sdev->dtrace_is_enabled)
274 return;
275
276 ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP);
277 if (ret < 0)
278 dev_err(sdev->dev,
279 "error: snd_sof_dma_trace_trigger: stop: %d\n", ret);
280
281 ret = snd_sof_dma_trace_release(sdev);
282 if (ret < 0)
283 dev_err(sdev->dev,
284 "error: fail in snd_sof_dma_trace_release %d\n", ret);
285
286 sdev->dtrace_is_enabled = false;
287}
288EXPORT_SYMBOL(snd_sof_release_trace);
289
290void snd_sof_free_trace(struct snd_sof_dev *sdev)
291{
292 snd_sof_release_trace(sdev);
293
294 snd_dma_free_pages(&sdev->dmatb);
295 snd_dma_free_pages(&sdev->dmatp);
296}
297EXPORT_SYMBOL(snd_sof_free_trace);
diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c
new file mode 100644
index 000000000000..2ac4c3da0320
--- /dev/null
+++ b/sound/soc/sof/utils.c
@@ -0,0 +1,112 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Keyon Jie <yang.jie@linux.intel.com>
9//
10
11#include <linux/io-64-nonatomic-lo-hi.h>
12#include <linux/platform_device.h>
13#include <sound/soc.h>
14#include <sound/sof.h>
15#include "sof-priv.h"
16
17/*
18 * Register IO
19 *
20 * The sof_io_xyz() wrappers are typically referenced in snd_sof_dsp_ops
21 * structures and cannot be inlined.
22 */
23
24void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value)
25{
26 writel(value, addr);
27}
28EXPORT_SYMBOL(sof_io_write);
29
30u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr)
31{
32 return readl(addr);
33}
34EXPORT_SYMBOL(sof_io_read);
35
36void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value)
37{
38 writeq(value, addr);
39}
40EXPORT_SYMBOL(sof_io_write64);
41
42u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr)
43{
44 return readq(addr);
45}
46EXPORT_SYMBOL(sof_io_read64);
47
48/*
49 * IPC Mailbox IO
50 */
51
52void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset,
53 void *message, size_t bytes)
54{
55 void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset;
56
57 memcpy_toio(dest, message, bytes);
58}
59EXPORT_SYMBOL(sof_mailbox_write);
60
61void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset,
62 void *message, size_t bytes)
63{
64 void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset;
65
66 memcpy_fromio(message, src, bytes);
67}
68EXPORT_SYMBOL(sof_mailbox_read);
69
70/*
71 * Memory copy.
72 */
73
74void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src,
75 size_t size)
76{
77 void __iomem *dest = sdev->bar[bar] + offset;
78 const u8 *src_byte = src;
79 u32 affected_mask;
80 u32 tmp;
81 int m, n;
82
83 m = size / 4;
84 n = size % 4;
85
86 /* __iowrite32_copy use 32bit size values so divide by 4 */
87 __iowrite32_copy(dest, src, m);
88
89 if (n) {
90 affected_mask = (1 << (8 * n)) - 1;
91
92 /* first read the 32bit data of dest, then change affected
93 * bytes, and write back to dest. For unaffected bytes, it
94 * should not be changed
95 */
96 tmp = ioread32(dest + m * 4);
97 tmp &= ~affected_mask;
98
99 tmp |= *(u32 *)(src_byte + m * 4) & affected_mask;
100 iowrite32(tmp, dest + m * 4);
101 }
102}
103EXPORT_SYMBOL(sof_block_write);
104
105void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest,
106 size_t size)
107{
108 void __iomem *src = sdev->bar[bar] + offset;
109
110 memcpy_fromio(dest, src, size);
111}
112EXPORT_SYMBOL(sof_block_read);
diff --git a/sound/soc/sof/xtensa/Kconfig b/sound/soc/sof/xtensa/Kconfig
new file mode 100644
index 000000000000..8a9343b85146
--- /dev/null
+++ b/sound/soc/sof/xtensa/Kconfig
@@ -0,0 +1,2 @@
1config SND_SOC_SOF_XTENSA
2 tristate
diff --git a/sound/soc/sof/xtensa/Makefile b/sound/soc/sof/xtensa/Makefile
new file mode 100644
index 000000000000..cc89c7472a38
--- /dev/null
+++ b/sound/soc/sof/xtensa/Makefile
@@ -0,0 +1,5 @@
1# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2
3snd-sof-xtensa-dsp-objs := core.o
4
5obj-$(CONFIG_SND_SOC_SOF_XTENSA) += snd-sof-xtensa-dsp.o
diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c
new file mode 100644
index 000000000000..c3ad23a85b99
--- /dev/null
+++ b/sound/soc/sof/xtensa/core.c
@@ -0,0 +1,138 @@
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Author: Pan Xiuli <xiuli.pan@linux.intel.com>
9//
10
11#include <linux/module.h>
12#include <sound/sof.h>
13#include <sound/sof/xtensa.h>
14#include "../sof-priv.h"
15
16struct xtensa_exception_cause {
17 u32 id;
18 const char *msg;
19 const char *description;
20};
21
22/*
23 * From 4.4.1.5 table 4-64 Exception Causes of Xtensa
24 * Instruction Set Architecture (ISA) Reference Manual
25 */
26static const struct xtensa_exception_cause xtensa_exception_causes[] = {
27 {0, "IllegalInstructionCause", "Illegal instruction"},
28 {1, "SyscallCause", "SYSCALL instruction"},
29 {2, "InstructionFetchErrorCause",
30 "Processor internal physical address or data error during instruction fetch"},
31 {3, "LoadStoreErrorCause",
32 "Processor internal physical address or data error during load or store"},
33 {4, "Level1InterruptCause",
34 "Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register"},
35 {5, "AllocaCause",
36 "MOVSP instruction, if caller’s registers are not in the register file"},
37 {6, "IntegerDivideByZeroCause",
38 "QUOS, QUOU, REMS, or REMU divisor operand is zero"},
39 {8, "PrivilegedCause",
40 "Attempt to execute a privileged operation when CRING ? 0"},
41 {9, "LoadStoreAlignmentCause", "Load or store to an unaligned address"},
42 {12, "InstrPIFDataErrorCause",
43 "PIF data error during instruction fetch"},
44 {13, "LoadStorePIFDataErrorCause",
45 "Synchronous PIF data error during LoadStore access"},
46 {14, "InstrPIFAddrErrorCause",
47 "PIF address error during instruction fetch"},
48 {15, "LoadStorePIFAddrErrorCause",
49 "Synchronous PIF address error during LoadStore access"},
50 {16, "InstTLBMissCause", "Error during Instruction TLB refill"},
51 {17, "InstTLBMultiHitCause",
52 "Multiple instruction TLB entries matched"},
53 {18, "InstFetchPrivilegeCause",
54 "An instruction fetch referenced a virtual address at a ring level less than CRING"},
55 {20, "InstFetchProhibitedCause",
56 "An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch"},
57 {24, "LoadStoreTLBMissCause",
58 "Error during TLB refill for a load or store"},
59 {25, "LoadStoreTLBMultiHitCause",
60 "Multiple TLB entries matched for a load or store"},
61 {26, "LoadStorePrivilegeCause",
62 "A load or store referenced a virtual address at a ring level less than CRING"},
63 {28, "LoadProhibitedCause",
64 "A load referenced a page mapped with an attribute that does not permit loads"},
65 {32, "Coprocessor0Disabled",
66 "Coprocessor 0 instruction when cp0 disabled"},
67 {33, "Coprocessor1Disabled",
68 "Coprocessor 1 instruction when cp1 disabled"},
69 {34, "Coprocessor2Disabled",
70 "Coprocessor 2 instruction when cp2 disabled"},
71 {35, "Coprocessor3Disabled",
72 "Coprocessor 3 instruction when cp3 disabled"},
73 {36, "Coprocessor4Disabled",
74 "Coprocessor 4 instruction when cp4 disabled"},
75 {37, "Coprocessor5Disabled",
76 "Coprocessor 5 instruction when cp5 disabled"},
77 {38, "Coprocessor6Disabled",
78 "Coprocessor 6 instruction when cp6 disabled"},
79 {39, "Coprocessor7Disabled",
80 "Coprocessor 7 instruction when cp7 disabled"},
81};
82
83/* only need xtensa atm */
84static void xtensa_dsp_oops(struct snd_sof_dev *sdev, void *oops)
85{
86 struct sof_ipc_dsp_oops_xtensa *xoops = oops;
87 int i;
88
89 dev_err(sdev->dev, "error: DSP Firmware Oops\n");
90 for (i = 0; i < ARRAY_SIZE(xtensa_exception_causes); i++) {
91 if (xtensa_exception_causes[i].id == xoops->exccause) {
92 dev_err(sdev->dev, "error: Exception Cause: %s, %s\n",
93 xtensa_exception_causes[i].msg,
94 xtensa_exception_causes[i].description);
95 }
96 }
97 dev_err(sdev->dev, "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n",
98 xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar);
99 dev_err(sdev->dev, "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x",
100 xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4);
101 dev_err(sdev->dev, "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x",
102 xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc);
103 dev_err(sdev->dev, "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x",
104 xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5);
105 dev_err(sdev->dev, "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x",
106 xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt);
107}
108
109static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
110 u32 stack_words)
111{
112 struct sof_ipc_dsp_oops_xtensa *xoops = oops;
113 u32 stack_ptr = xoops->stack;
114 /* 4 * 8chars + 3 ws + 1 terminating NUL */
115 unsigned char buf[4 * 8 + 3 + 1];
116 int i;
117
118 dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr);
119
120 /*
121 * example output:
122 * 0x0049fbb0: 8000f2d0 0049fc00 6f6c6c61 00632e63
123 */
124 for (i = 0; i < stack_words; i += 4) {
125 hex_dump_to_buffer(stack + i * 4, 16, 16, 4,
126 buf, sizeof(buf), false);
127 dev_err(sdev->dev, "0x%08x: %s\n", stack_ptr + i, buf);
128 }
129}
130
131const struct sof_arch_ops sof_xtensa_arch_ops = {
132 .dsp_oops = xtensa_dsp_oops,
133 .dsp_stack = xtensa_stack,
134};
135EXPORT_SYMBOL(sof_xtensa_arch_ops);
136
137MODULE_DESCRIPTION("SOF Xtensa DSP support");
138MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sprd/Kconfig b/sound/soc/sprd/Kconfig
index 43ece7daf0e9..21f9cc34f8bd 100644
--- a/sound/soc/sprd/Kconfig
+++ b/sound/soc/sprd/Kconfig
@@ -1,6 +1,15 @@
1config SND_SOC_SPRD 1config SND_SOC_SPRD
2 tristate "SoC Audio for the Spreadtrum SoC chips" 2 tristate "SoC Audio for the Spreadtrum SoC chips"
3 depends on ARCH_SPRD || COMPILE_TEST 3 depends on ARCH_SPRD || COMPILE_TEST
4 select SND_SOC_COMPRESS
4 help 5 help
5 Say Y or M if you want to add support for codecs attached to 6 Say Y or M if you want to add support for codecs attached to
6 the Spreadtrum SoCs' Audio interfaces. 7 the Spreadtrum SoCs' Audio interfaces.
8
9config SND_SOC_SPRD_MCDT
10 bool "Spreadtrum multi-channel data transfer support"
11 depends on SND_SOC_SPRD
12 help
13 Say y here to enable multi-channel data transfer support. It
14 is used for sound stream transmission between audio subsystem
15 and other AP/CP subsystem.
diff --git a/sound/soc/sprd/Makefile b/sound/soc/sprd/Makefile
index 47620e57a9f2..a95fa56cd000 100644
--- a/sound/soc/sprd/Makefile
+++ b/sound/soc/sprd/Makefile
@@ -1,4 +1,8 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2# Spreadtrum Audio Support 2# Spreadtrum Audio Support
3 3
4obj-$(CONFIG_SND_SOC_SPRD) += sprd-pcm-dma.o 4snd-soc-sprd-platform-objs := sprd-pcm-dma.o sprd-pcm-compress.o
5
6obj-$(CONFIG_SND_SOC_SPRD) += snd-soc-sprd-platform.o
7
8obj-$(CONFIG_SND_SOC_SPRD_MCDT) += sprd-mcdt.o
diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c
new file mode 100644
index 000000000000..7448015a4935
--- /dev/null
+++ b/sound/soc/sprd/sprd-mcdt.c
@@ -0,0 +1,1011 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2019 Spreadtrum Communications Inc.
3
4#include <linux/errno.h>
5#include <linux/interrupt.h>
6#include <linux/io.h>
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/mutex.h>
10#include <linux/of.h>
11#include <linux/platform_device.h>
12#include <linux/spinlock.h>
13
14#include "sprd-mcdt.h"
15
16/* MCDT registers definition */
17#define MCDT_CH0_TXD 0x0
18#define MCDT_CH0_RXD 0x28
19#define MCDT_DAC0_WTMK 0x60
20#define MCDT_ADC0_WTMK 0x88
21#define MCDT_DMA_EN 0xb0
22
23#define MCDT_INT_EN0 0xb4
24#define MCDT_INT_EN1 0xb8
25#define MCDT_INT_EN2 0xbc
26
27#define MCDT_INT_CLR0 0xc0
28#define MCDT_INT_CLR1 0xc4
29#define MCDT_INT_CLR2 0xc8
30
31#define MCDT_INT_RAW1 0xcc
32#define MCDT_INT_RAW2 0xd0
33#define MCDT_INT_RAW3 0xd4
34
35#define MCDT_INT_MSK1 0xd8
36#define MCDT_INT_MSK2 0xdc
37#define MCDT_INT_MSK3 0xe0
38
39#define MCDT_DAC0_FIFO_ADDR_ST 0xe4
40#define MCDT_ADC0_FIFO_ADDR_ST 0xe8
41
42#define MCDT_CH_FIFO_ST0 0x134
43#define MCDT_CH_FIFO_ST1 0x138
44#define MCDT_CH_FIFO_ST2 0x13c
45
46#define MCDT_INT_MSK_CFG0 0x140
47#define MCDT_INT_MSK_CFG1 0x144
48
49#define MCDT_DMA_CFG0 0x148
50#define MCDT_FIFO_CLR 0x14c
51#define MCDT_DMA_CFG1 0x150
52#define MCDT_DMA_CFG2 0x154
53#define MCDT_DMA_CFG3 0x158
54#define MCDT_DMA_CFG4 0x15c
55#define MCDT_DMA_CFG5 0x160
56
57/* Channel water mark definition */
58#define MCDT_CH_FIFO_AE_SHIFT 16
59#define MCDT_CH_FIFO_AE_MASK GENMASK(24, 16)
60#define MCDT_CH_FIFO_AF_MASK GENMASK(8, 0)
61
62/* DMA channel select definition */
63#define MCDT_DMA_CH0_SEL_MASK GENMASK(3, 0)
64#define MCDT_DMA_CH0_SEL_SHIFT 0
65#define MCDT_DMA_CH1_SEL_MASK GENMASK(7, 4)
66#define MCDT_DMA_CH1_SEL_SHIFT 4
67#define MCDT_DMA_CH2_SEL_MASK GENMASK(11, 8)
68#define MCDT_DMA_CH2_SEL_SHIFT 8
69#define MCDT_DMA_CH3_SEL_MASK GENMASK(15, 12)
70#define MCDT_DMA_CH3_SEL_SHIFT 12
71#define MCDT_DMA_CH4_SEL_MASK GENMASK(19, 16)
72#define MCDT_DMA_CH4_SEL_SHIFT 16
73#define MCDT_DAC_DMA_SHIFT 16
74
75/* DMA channel ACK select definition */
76#define MCDT_DMA_ACK_SEL_MASK GENMASK(3, 0)
77
78/* Channel FIFO definition */
79#define MCDT_CH_FIFO_ADDR_SHIFT 16
80#define MCDT_CH_FIFO_ADDR_MASK GENMASK(9, 0)
81#define MCDT_ADC_FIFO_SHIFT 16
82#define MCDT_FIFO_LENGTH 512
83
84#define MCDT_ADC_CHANNEL_NUM 10
85#define MCDT_DAC_CHANNEL_NUM 10
86#define MCDT_CHANNEL_NUM (MCDT_ADC_CHANNEL_NUM + MCDT_DAC_CHANNEL_NUM)
87
88enum sprd_mcdt_fifo_int {
89 MCDT_ADC_FIFO_AE_INT,
90 MCDT_ADC_FIFO_AF_INT,
91 MCDT_DAC_FIFO_AE_INT,
92 MCDT_DAC_FIFO_AF_INT,
93 MCDT_ADC_FIFO_OV_INT,
94 MCDT_DAC_FIFO_OV_INT
95};
96
97enum sprd_mcdt_fifo_sts {
98 MCDT_ADC_FIFO_REAL_FULL,
99 MCDT_ADC_FIFO_REAL_EMPTY,
100 MCDT_ADC_FIFO_AF,
101 MCDT_ADC_FIFO_AE,
102 MCDT_DAC_FIFO_REAL_FULL,
103 MCDT_DAC_FIFO_REAL_EMPTY,
104 MCDT_DAC_FIFO_AF,
105 MCDT_DAC_FIFO_AE
106};
107
108struct sprd_mcdt_dev {
109 struct device *dev;
110 void __iomem *base;
111 spinlock_t lock;
112 struct sprd_mcdt_chan chan[MCDT_CHANNEL_NUM];
113};
114
115static LIST_HEAD(sprd_mcdt_chan_list);
116static DEFINE_MUTEX(sprd_mcdt_list_mutex);
117
118static void sprd_mcdt_update(struct sprd_mcdt_dev *mcdt, u32 reg, u32 val,
119 u32 mask)
120{
121 u32 orig = readl_relaxed(mcdt->base + reg);
122 u32 tmp;
123
124 tmp = (orig & ~mask) | val;
125 writel_relaxed(tmp, mcdt->base + reg);
126}
127
128static void sprd_mcdt_dac_set_watermark(struct sprd_mcdt_dev *mcdt, u8 channel,
129 u32 full, u32 empty)
130{
131 u32 reg = MCDT_DAC0_WTMK + channel * 4;
132 u32 water_mark =
133 (empty << MCDT_CH_FIFO_AE_SHIFT) & MCDT_CH_FIFO_AE_MASK;
134
135 water_mark |= full & MCDT_CH_FIFO_AF_MASK;
136 sprd_mcdt_update(mcdt, reg, water_mark,
137 MCDT_CH_FIFO_AE_MASK | MCDT_CH_FIFO_AF_MASK);
138}
139
140static void sprd_mcdt_adc_set_watermark(struct sprd_mcdt_dev *mcdt, u8 channel,
141 u32 full, u32 empty)
142{
143 u32 reg = MCDT_ADC0_WTMK + channel * 4;
144 u32 water_mark =
145 (empty << MCDT_CH_FIFO_AE_SHIFT) & MCDT_CH_FIFO_AE_MASK;
146
147 water_mark |= full & MCDT_CH_FIFO_AF_MASK;
148 sprd_mcdt_update(mcdt, reg, water_mark,
149 MCDT_CH_FIFO_AE_MASK | MCDT_CH_FIFO_AF_MASK);
150}
151
152static void sprd_mcdt_dac_dma_enable(struct sprd_mcdt_dev *mcdt, u8 channel,
153 bool enable)
154{
155 u32 shift = MCDT_DAC_DMA_SHIFT + channel;
156
157 if (enable)
158 sprd_mcdt_update(mcdt, MCDT_DMA_EN, BIT(shift), BIT(shift));
159 else
160 sprd_mcdt_update(mcdt, MCDT_DMA_EN, 0, BIT(shift));
161}
162
163static void sprd_mcdt_adc_dma_enable(struct sprd_mcdt_dev *mcdt, u8 channel,
164 bool enable)
165{
166 if (enable)
167 sprd_mcdt_update(mcdt, MCDT_DMA_EN, BIT(channel), BIT(channel));
168 else
169 sprd_mcdt_update(mcdt, MCDT_DMA_EN, 0, BIT(channel));
170}
171
172static void sprd_mcdt_ap_int_enable(struct sprd_mcdt_dev *mcdt, u8 channel,
173 bool enable)
174{
175 if (enable)
176 sprd_mcdt_update(mcdt, MCDT_INT_MSK_CFG0, BIT(channel),
177 BIT(channel));
178 else
179 sprd_mcdt_update(mcdt, MCDT_INT_MSK_CFG0, 0, BIT(channel));
180}
181
182static void sprd_mcdt_dac_write_fifo(struct sprd_mcdt_dev *mcdt, u8 channel,
183 u32 val)
184{
185 u32 reg = MCDT_CH0_TXD + channel * 4;
186
187 writel_relaxed(val, mcdt->base + reg);
188}
189
190static void sprd_mcdt_adc_read_fifo(struct sprd_mcdt_dev *mcdt, u8 channel,
191 u32 *val)
192{
193 u32 reg = MCDT_CH0_RXD + channel * 4;
194
195 *val = readl_relaxed(mcdt->base + reg);
196}
197
198static void sprd_mcdt_dac_dma_chn_select(struct sprd_mcdt_dev *mcdt, u8 channel,
199 enum sprd_mcdt_dma_chan dma_chan)
200{
201 switch (dma_chan) {
202 case SPRD_MCDT_DMA_CH0:
203 sprd_mcdt_update(mcdt, MCDT_DMA_CFG0,
204 channel << MCDT_DMA_CH0_SEL_SHIFT,
205 MCDT_DMA_CH0_SEL_MASK);
206 break;
207
208 case SPRD_MCDT_DMA_CH1:
209 sprd_mcdt_update(mcdt, MCDT_DMA_CFG0,
210 channel << MCDT_DMA_CH1_SEL_SHIFT,
211 MCDT_DMA_CH1_SEL_MASK);
212 break;
213
214 case SPRD_MCDT_DMA_CH2:
215 sprd_mcdt_update(mcdt, MCDT_DMA_CFG0,
216 channel << MCDT_DMA_CH2_SEL_SHIFT,
217 MCDT_DMA_CH2_SEL_MASK);
218 break;
219
220 case SPRD_MCDT_DMA_CH3:
221 sprd_mcdt_update(mcdt, MCDT_DMA_CFG0,
222 channel << MCDT_DMA_CH3_SEL_SHIFT,
223 MCDT_DMA_CH3_SEL_MASK);
224 break;
225
226 case SPRD_MCDT_DMA_CH4:
227 sprd_mcdt_update(mcdt, MCDT_DMA_CFG0,
228 channel << MCDT_DMA_CH4_SEL_SHIFT,
229 MCDT_DMA_CH4_SEL_MASK);
230 break;
231 }
232}
233
234static void sprd_mcdt_adc_dma_chn_select(struct sprd_mcdt_dev *mcdt, u8 channel,
235 enum sprd_mcdt_dma_chan dma_chan)
236{
237 switch (dma_chan) {
238 case SPRD_MCDT_DMA_CH0:
239 sprd_mcdt_update(mcdt, MCDT_DMA_CFG1,
240 channel << MCDT_DMA_CH0_SEL_SHIFT,
241 MCDT_DMA_CH0_SEL_MASK);
242 break;
243
244 case SPRD_MCDT_DMA_CH1:
245 sprd_mcdt_update(mcdt, MCDT_DMA_CFG1,
246 channel << MCDT_DMA_CH1_SEL_SHIFT,
247 MCDT_DMA_CH1_SEL_MASK);
248 break;
249
250 case SPRD_MCDT_DMA_CH2:
251 sprd_mcdt_update(mcdt, MCDT_DMA_CFG1,
252 channel << MCDT_DMA_CH2_SEL_SHIFT,
253 MCDT_DMA_CH2_SEL_MASK);
254 break;
255
256 case SPRD_MCDT_DMA_CH3:
257 sprd_mcdt_update(mcdt, MCDT_DMA_CFG1,
258 channel << MCDT_DMA_CH3_SEL_SHIFT,
259 MCDT_DMA_CH3_SEL_MASK);
260 break;
261
262 case SPRD_MCDT_DMA_CH4:
263 sprd_mcdt_update(mcdt, MCDT_DMA_CFG1,
264 channel << MCDT_DMA_CH4_SEL_SHIFT,
265 MCDT_DMA_CH4_SEL_MASK);
266 break;
267 }
268}
269
270static u32 sprd_mcdt_dma_ack_shift(u8 channel)
271{
272 switch (channel) {
273 default:
274 case 0:
275 case 8:
276 return 0;
277 case 1:
278 case 9:
279 return 4;
280 case 2:
281 return 8;
282 case 3:
283 return 12;
284 case 4:
285 return 16;
286 case 5:
287 return 20;
288 case 6:
289 return 24;
290 case 7:
291 return 28;
292 }
293}
294
295static void sprd_mcdt_dac_dma_ack_select(struct sprd_mcdt_dev *mcdt, u8 channel,
296 enum sprd_mcdt_dma_chan dma_chan)
297{
298 u32 reg, shift = sprd_mcdt_dma_ack_shift(channel), ack = dma_chan;
299
300 switch (channel) {
301 case 0 ... 7:
302 reg = MCDT_DMA_CFG2;
303 break;
304
305 case 8 ... 9:
306 reg = MCDT_DMA_CFG3;
307 break;
308
309 default:
310 return;
311 }
312
313 sprd_mcdt_update(mcdt, reg, ack << shift,
314 MCDT_DMA_ACK_SEL_MASK << shift);
315}
316
317static void sprd_mcdt_adc_dma_ack_select(struct sprd_mcdt_dev *mcdt, u8 channel,
318 enum sprd_mcdt_dma_chan dma_chan)
319{
320 u32 reg, shift = sprd_mcdt_dma_ack_shift(channel), ack = dma_chan;
321
322 switch (channel) {
323 case 0 ... 7:
324 reg = MCDT_DMA_CFG4;
325 break;
326
327 case 8 ... 9:
328 reg = MCDT_DMA_CFG5;
329 break;
330
331 default:
332 return;
333 }
334
335 sprd_mcdt_update(mcdt, reg, ack << shift,
336 MCDT_DMA_ACK_SEL_MASK << shift);
337}
338
339static bool sprd_mcdt_chan_fifo_sts(struct sprd_mcdt_dev *mcdt, u8 channel,
340 enum sprd_mcdt_fifo_sts fifo_sts)
341{
342 u32 reg, shift;
343
344 switch (channel) {
345 case 0 ... 3:
346 reg = MCDT_CH_FIFO_ST0;
347 break;
348 case 4 ... 7:
349 reg = MCDT_CH_FIFO_ST1;
350 break;
351 case 8 ... 9:
352 reg = MCDT_CH_FIFO_ST2;
353 break;
354 default:
355 return false;
356 }
357
358 switch (channel) {
359 case 0:
360 case 4:
361 case 8:
362 shift = fifo_sts;
363 break;
364
365 case 1:
366 case 5:
367 case 9:
368 shift = 8 + fifo_sts;
369 break;
370
371 case 2:
372 case 6:
373 shift = 16 + fifo_sts;
374 break;
375
376 case 3:
377 case 7:
378 shift = 24 + fifo_sts;
379 break;
380
381 default:
382 return false;
383 }
384
385 return !!(readl_relaxed(mcdt->base + reg) & BIT(shift));
386}
387
388static void sprd_mcdt_dac_fifo_clear(struct sprd_mcdt_dev *mcdt, u8 channel)
389{
390 sprd_mcdt_update(mcdt, MCDT_FIFO_CLR, BIT(channel), BIT(channel));
391}
392
393static void sprd_mcdt_adc_fifo_clear(struct sprd_mcdt_dev *mcdt, u8 channel)
394{
395 u32 shift = MCDT_ADC_FIFO_SHIFT + channel;
396
397 sprd_mcdt_update(mcdt, MCDT_FIFO_CLR, BIT(shift), BIT(shift));
398}
399
400static u32 sprd_mcdt_dac_fifo_avail(struct sprd_mcdt_dev *mcdt, u8 channel)
401{
402 u32 reg = MCDT_DAC0_FIFO_ADDR_ST + channel * 8;
403 u32 r_addr = (readl_relaxed(mcdt->base + reg) >>
404 MCDT_CH_FIFO_ADDR_SHIFT) & MCDT_CH_FIFO_ADDR_MASK;
405 u32 w_addr = readl_relaxed(mcdt->base + reg) & MCDT_CH_FIFO_ADDR_MASK;
406
407 if (w_addr >= r_addr)
408 return 4 * (MCDT_FIFO_LENGTH - w_addr + r_addr);
409 else
410 return 4 * (r_addr - w_addr);
411}
412
413static u32 sprd_mcdt_adc_fifo_avail(struct sprd_mcdt_dev *mcdt, u8 channel)
414{
415 u32 reg = MCDT_ADC0_FIFO_ADDR_ST + channel * 8;
416 u32 r_addr = (readl_relaxed(mcdt->base + reg) >>
417 MCDT_CH_FIFO_ADDR_SHIFT) & MCDT_CH_FIFO_ADDR_MASK;
418 u32 w_addr = readl_relaxed(mcdt->base + reg) & MCDT_CH_FIFO_ADDR_MASK;
419
420 if (w_addr >= r_addr)
421 return 4 * (w_addr - r_addr);
422 else
423 return 4 * (MCDT_FIFO_LENGTH - r_addr + w_addr);
424}
425
426static u32 sprd_mcdt_int_type_shift(u8 channel,
427 enum sprd_mcdt_fifo_int int_type)
428{
429 switch (channel) {
430 case 0:
431 case 4:
432 case 8:
433 return int_type;
434
435 case 1:
436 case 5:
437 case 9:
438 return 8 + int_type;
439
440 case 2:
441 case 6:
442 return 16 + int_type;
443
444 case 3:
445 case 7:
446 return 24 + int_type;
447
448 default:
449 return 0;
450 }
451}
452
453static void sprd_mcdt_chan_int_en(struct sprd_mcdt_dev *mcdt, u8 channel,
454 enum sprd_mcdt_fifo_int int_type, bool enable)
455{
456 u32 reg, shift = sprd_mcdt_int_type_shift(channel, int_type);
457
458 switch (channel) {
459 case 0 ... 3:
460 reg = MCDT_INT_EN0;
461 break;
462 case 4 ... 7:
463 reg = MCDT_INT_EN1;
464 break;
465 case 8 ... 9:
466 reg = MCDT_INT_EN2;
467 break;
468 default:
469 return;
470 }
471
472 if (enable)
473 sprd_mcdt_update(mcdt, reg, BIT(shift), BIT(shift));
474 else
475 sprd_mcdt_update(mcdt, reg, 0, BIT(shift));
476}
477
478static void sprd_mcdt_chan_int_clear(struct sprd_mcdt_dev *mcdt, u8 channel,
479 enum sprd_mcdt_fifo_int int_type)
480{
481 u32 reg, shift = sprd_mcdt_int_type_shift(channel, int_type);
482
483 switch (channel) {
484 case 0 ... 3:
485 reg = MCDT_INT_CLR0;
486 break;
487 case 4 ... 7:
488 reg = MCDT_INT_CLR1;
489 break;
490 case 8 ... 9:
491 reg = MCDT_INT_CLR2;
492 break;
493 default:
494 return;
495 }
496
497 sprd_mcdt_update(mcdt, reg, BIT(shift), BIT(shift));
498}
499
500static bool sprd_mcdt_chan_int_sts(struct sprd_mcdt_dev *mcdt, u8 channel,
501 enum sprd_mcdt_fifo_int int_type)
502{
503 u32 reg, shift = sprd_mcdt_int_type_shift(channel, int_type);
504
505 switch (channel) {
506 case 0 ... 3:
507 reg = MCDT_INT_MSK1;
508 break;
509 case 4 ... 7:
510 reg = MCDT_INT_MSK2;
511 break;
512 case 8 ... 9:
513 reg = MCDT_INT_MSK3;
514 break;
515 default:
516 return false;
517 }
518
519 return !!(readl_relaxed(mcdt->base + reg) & BIT(shift));
520}
521
522static irqreturn_t sprd_mcdt_irq_handler(int irq, void *dev_id)
523{
524 struct sprd_mcdt_dev *mcdt = (struct sprd_mcdt_dev *)dev_id;
525 int i;
526
527 spin_lock(&mcdt->lock);
528
529 for (i = 0; i < MCDT_ADC_CHANNEL_NUM; i++) {
530 if (sprd_mcdt_chan_int_sts(mcdt, i, MCDT_ADC_FIFO_AF_INT)) {
531 struct sprd_mcdt_chan *chan = &mcdt->chan[i];
532
533 sprd_mcdt_chan_int_clear(mcdt, i, MCDT_ADC_FIFO_AF_INT);
534 if (chan->cb)
535 chan->cb->notify(chan->cb->data);
536 }
537 }
538
539 for (i = 0; i < MCDT_DAC_CHANNEL_NUM; i++) {
540 if (sprd_mcdt_chan_int_sts(mcdt, i, MCDT_DAC_FIFO_AE_INT)) {
541 struct sprd_mcdt_chan *chan =
542 &mcdt->chan[i + MCDT_ADC_CHANNEL_NUM];
543
544 sprd_mcdt_chan_int_clear(mcdt, i, MCDT_DAC_FIFO_AE_INT);
545 if (chan->cb)
546 chan->cb->notify(chan->cb->data);
547 }
548 }
549
550 spin_unlock(&mcdt->lock);
551
552 return IRQ_HANDLED;
553}
554
555/**
556 * sprd_mcdt_chan_write - write data to the MCDT channel's fifo
557 * @chan: the MCDT channel
558 * @tx_buf: send buffer
559 * @size: data size
560 *
561 * Note: We can not write data to the channel fifo when enabling the DMA mode,
562 * otherwise the channel fifo data will be invalid.
563 *
564 * If there are not enough space of the channel fifo, it will return errors
565 * to users.
566 *
567 * Returns 0 on success, or an appropriate error code on failure.
568 */
569int sprd_mcdt_chan_write(struct sprd_mcdt_chan *chan, char *tx_buf, u32 size)
570{
571 struct sprd_mcdt_dev *mcdt = chan->mcdt;
572 unsigned long flags;
573 int avail, i = 0, words = size / 4;
574 u32 *buf = (u32 *)tx_buf;
575
576 spin_lock_irqsave(&mcdt->lock, flags);
577
578 if (chan->dma_enable) {
579 dev_err(mcdt->dev,
580 "Can not write data when DMA mode enabled\n");
581 spin_unlock_irqrestore(&mcdt->lock, flags);
582 return -EINVAL;
583 }
584
585 if (sprd_mcdt_chan_fifo_sts(mcdt, chan->id, MCDT_DAC_FIFO_REAL_FULL)) {
586 dev_err(mcdt->dev, "Channel fifo is full now\n");
587 spin_unlock_irqrestore(&mcdt->lock, flags);
588 return -EBUSY;
589 }
590
591 avail = sprd_mcdt_dac_fifo_avail(mcdt, chan->id);
592 if (size > avail) {
593 dev_err(mcdt->dev,
594 "Data size is larger than the available fifo size\n");
595 spin_unlock_irqrestore(&mcdt->lock, flags);
596 return -EBUSY;
597 }
598
599 while (i++ < words)
600 sprd_mcdt_dac_write_fifo(mcdt, chan->id, *buf++);
601
602 spin_unlock_irqrestore(&mcdt->lock, flags);
603 return 0;
604}
605EXPORT_SYMBOL_GPL(sprd_mcdt_chan_write);
606
607/**
608 * sprd_mcdt_chan_read - read data from the MCDT channel's fifo
609 * @chan: the MCDT channel
610 * @rx_buf: receive buffer
611 * @size: data size
612 *
613 * Note: We can not read data from the channel fifo when enabling the DMA mode,
614 * otherwise the reading data will be invalid.
615 *
616 * Usually user need start to read data once receiving the fifo full interrupt.
617 *
618 * Returns data size of reading successfully, or an error code on failure.
619 */
620int sprd_mcdt_chan_read(struct sprd_mcdt_chan *chan, char *rx_buf, u32 size)
621{
622 struct sprd_mcdt_dev *mcdt = chan->mcdt;
623 unsigned long flags;
624 int i = 0, avail, words = size / 4;
625 u32 *buf = (u32 *)rx_buf;
626
627 spin_lock_irqsave(&mcdt->lock, flags);
628
629 if (chan->dma_enable) {
630 dev_err(mcdt->dev, "Can not read data when DMA mode enabled\n");
631 spin_unlock_irqrestore(&mcdt->lock, flags);
632 return -EINVAL;
633 }
634
635 if (sprd_mcdt_chan_fifo_sts(mcdt, chan->id, MCDT_ADC_FIFO_REAL_EMPTY)) {
636 dev_err(mcdt->dev, "Channel fifo is empty\n");
637 spin_unlock_irqrestore(&mcdt->lock, flags);
638 return -EBUSY;
639 }
640
641 avail = sprd_mcdt_adc_fifo_avail(mcdt, chan->id);
642 if (size > avail)
643 words = avail / 4;
644
645 while (i++ < words)
646 sprd_mcdt_adc_read_fifo(mcdt, chan->id, buf++);
647
648 spin_unlock_irqrestore(&mcdt->lock, flags);
649 return words * 4;
650}
651EXPORT_SYMBOL_GPL(sprd_mcdt_chan_read);
652
653/**
654 * sprd_mcdt_chan_int_enable - enable the interrupt mode for the MCDT channel
655 * @chan: the MCDT channel
656 * @water_mark: water mark to trigger a interrupt
657 * @cb: callback when a interrupt happened
658 *
659 * Now it only can enable fifo almost full interrupt for ADC channel and fifo
660 * almost empty interrupt for DAC channel. Morevoer for interrupt mode, user
661 * should use sprd_mcdt_chan_read() or sprd_mcdt_chan_write() to read or write
662 * data manually.
663 *
664 * For ADC channel, user can start to read data once receiving one fifo full
665 * interrupt. For DAC channel, user can start to write data once receiving one
666 * fifo empty interrupt or just call sprd_mcdt_chan_write() to write data
667 * directly.
668 *
669 * Returns 0 on success, or an error code on failure.
670 */
671int sprd_mcdt_chan_int_enable(struct sprd_mcdt_chan *chan, u32 water_mark,
672 struct sprd_mcdt_chan_callback *cb)
673{
674 struct sprd_mcdt_dev *mcdt = chan->mcdt;
675 unsigned long flags;
676 int ret = 0;
677
678 spin_lock_irqsave(&mcdt->lock, flags);
679
680 if (chan->dma_enable || chan->int_enable) {
681 dev_err(mcdt->dev, "Failed to set interrupt mode.\n");
682 spin_unlock_irqrestore(&mcdt->lock, flags);
683 return -EINVAL;
684 }
685
686 switch (chan->type) {
687 case SPRD_MCDT_ADC_CHAN:
688 sprd_mcdt_adc_fifo_clear(mcdt, chan->id);
689 sprd_mcdt_adc_set_watermark(mcdt, chan->id, water_mark,
690 MCDT_FIFO_LENGTH - 1);
691 sprd_mcdt_chan_int_en(mcdt, chan->id,
692 MCDT_ADC_FIFO_AF_INT, true);
693 sprd_mcdt_ap_int_enable(mcdt, chan->id, true);
694 break;
695
696 case SPRD_MCDT_DAC_CHAN:
697 sprd_mcdt_dac_fifo_clear(mcdt, chan->id);
698 sprd_mcdt_dac_set_watermark(mcdt, chan->id,
699 MCDT_FIFO_LENGTH - 1, water_mark);
700 sprd_mcdt_chan_int_en(mcdt, chan->id,
701 MCDT_DAC_FIFO_AE_INT, true);
702 sprd_mcdt_ap_int_enable(mcdt, chan->id, true);
703 break;
704
705 default:
706 dev_err(mcdt->dev, "Unsupported channel type\n");
707 ret = -EINVAL;
708 }
709
710 if (!ret) {
711 chan->cb = cb;
712 chan->int_enable = true;
713 }
714
715 spin_unlock_irqrestore(&mcdt->lock, flags);
716
717 return ret;
718}
719EXPORT_SYMBOL_GPL(sprd_mcdt_chan_int_enable);
720
721/**
722 * sprd_mcdt_chan_int_disable - disable the interrupt mode for the MCDT channel
723 * @chan: the MCDT channel
724 */
725void sprd_mcdt_chan_int_disable(struct sprd_mcdt_chan *chan)
726{
727 struct sprd_mcdt_dev *mcdt = chan->mcdt;
728 unsigned long flags;
729
730 spin_lock_irqsave(&mcdt->lock, flags);
731
732 if (!chan->int_enable) {
733 spin_unlock_irqrestore(&mcdt->lock, flags);
734 return;
735 }
736
737 switch (chan->type) {
738 case SPRD_MCDT_ADC_CHAN:
739 sprd_mcdt_chan_int_en(mcdt, chan->id,
740 MCDT_ADC_FIFO_AF_INT, false);
741 sprd_mcdt_chan_int_clear(mcdt, chan->id, MCDT_ADC_FIFO_AF_INT);
742 sprd_mcdt_ap_int_enable(mcdt, chan->id, false);
743 break;
744
745 case SPRD_MCDT_DAC_CHAN:
746 sprd_mcdt_chan_int_en(mcdt, chan->id,
747 MCDT_DAC_FIFO_AE_INT, false);
748 sprd_mcdt_chan_int_clear(mcdt, chan->id, MCDT_DAC_FIFO_AE_INT);
749 sprd_mcdt_ap_int_enable(mcdt, chan->id, false);
750 break;
751
752 default:
753 break;
754 }
755
756 chan->int_enable = false;
757 spin_unlock_irqrestore(&mcdt->lock, flags);
758}
759EXPORT_SYMBOL_GPL(sprd_mcdt_chan_int_disable);
760
761/**
762 * sprd_mcdt_chan_dma_enable - enable the DMA mode for the MCDT channel
763 * @chan: the MCDT channel
764 * @dma_chan: specify which DMA channel will be used for this MCDT channel
765 * @water_mark: water mark to trigger a DMA request
766 *
767 * Enable the DMA mode for the MCDT channel, that means we can use DMA to
768 * transfer data to the channel fifo and do not need reading/writing data
769 * manually.
770 *
771 * Returns 0 on success, or an error code on failure.
772 */
773int sprd_mcdt_chan_dma_enable(struct sprd_mcdt_chan *chan,
774 enum sprd_mcdt_dma_chan dma_chan,
775 u32 water_mark)
776{
777 struct sprd_mcdt_dev *mcdt = chan->mcdt;
778 unsigned long flags;
779 int ret = 0;
780
781 spin_lock_irqsave(&mcdt->lock, flags);
782
783 if (chan->dma_enable || chan->int_enable ||
784 dma_chan > SPRD_MCDT_DMA_CH4) {
785 dev_err(mcdt->dev, "Failed to set DMA mode\n");
786 spin_unlock_irqrestore(&mcdt->lock, flags);
787 return -EINVAL;
788 }
789
790 switch (chan->type) {
791 case SPRD_MCDT_ADC_CHAN:
792 sprd_mcdt_adc_fifo_clear(mcdt, chan->id);
793 sprd_mcdt_adc_set_watermark(mcdt, chan->id,
794 water_mark, MCDT_FIFO_LENGTH - 1);
795 sprd_mcdt_adc_dma_enable(mcdt, chan->id, true);
796 sprd_mcdt_adc_dma_chn_select(mcdt, chan->id, dma_chan);
797 sprd_mcdt_adc_dma_ack_select(mcdt, chan->id, dma_chan);
798 break;
799
800 case SPRD_MCDT_DAC_CHAN:
801 sprd_mcdt_dac_fifo_clear(mcdt, chan->id);
802 sprd_mcdt_dac_set_watermark(mcdt, chan->id,
803 MCDT_FIFO_LENGTH - 1, water_mark);
804 sprd_mcdt_dac_dma_enable(mcdt, chan->id, true);
805 sprd_mcdt_dac_dma_chn_select(mcdt, chan->id, dma_chan);
806 sprd_mcdt_dac_dma_ack_select(mcdt, chan->id, dma_chan);
807 break;
808
809 default:
810 dev_err(mcdt->dev, "Unsupported channel type\n");
811 ret = -EINVAL;
812 }
813
814 if (!ret)
815 chan->dma_enable = true;
816
817 spin_unlock_irqrestore(&mcdt->lock, flags);
818
819 return ret;
820}
821EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_enable);
822
823/**
824 * sprd_mcdt_chan_dma_disable - disable the DMA mode for the MCDT channel
825 * @chan: the MCDT channel
826 */
827void sprd_mcdt_chan_dma_disable(struct sprd_mcdt_chan *chan)
828{
829 struct sprd_mcdt_dev *mcdt = chan->mcdt;
830 unsigned long flags;
831
832 spin_lock_irqsave(&mcdt->lock, flags);
833
834 if (!chan->dma_enable) {
835 spin_unlock_irqrestore(&mcdt->lock, flags);
836 return;
837 }
838
839 switch (chan->type) {
840 case SPRD_MCDT_ADC_CHAN:
841 sprd_mcdt_adc_dma_enable(mcdt, chan->id, false);
842 sprd_mcdt_adc_fifo_clear(mcdt, chan->id);
843 break;
844
845 case SPRD_MCDT_DAC_CHAN:
846 sprd_mcdt_dac_dma_enable(mcdt, chan->id, false);
847 sprd_mcdt_dac_fifo_clear(mcdt, chan->id);
848 break;
849
850 default:
851 break;
852 }
853
854 chan->dma_enable = false;
855 spin_unlock_irqrestore(&mcdt->lock, flags);
856}
857EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_disable);
858
859/**
860 * sprd_mcdt_request_chan - request one MCDT channel
861 * @channel: channel id
862 * @type: channel type, it can be one ADC channel or DAC channel
863 *
864 * Rreturn NULL if no available channel.
865 */
866struct sprd_mcdt_chan *sprd_mcdt_request_chan(u8 channel,
867 enum sprd_mcdt_channel_type type)
868{
869 struct sprd_mcdt_chan *temp, *chan = NULL;
870
871 mutex_lock(&sprd_mcdt_list_mutex);
872
873 list_for_each_entry(temp, &sprd_mcdt_chan_list, list) {
874 if (temp->type == type && temp->id == channel) {
875 chan = temp;
876 break;
877 }
878 }
879
880 if (chan)
881 list_del(&chan->list);
882
883 mutex_unlock(&sprd_mcdt_list_mutex);
884
885 return chan;
886}
887EXPORT_SYMBOL_GPL(sprd_mcdt_request_chan);
888
889/**
890 * sprd_mcdt_free_chan - free one MCDT channel
891 * @chan: the channel to be freed
892 */
893void sprd_mcdt_free_chan(struct sprd_mcdt_chan *chan)
894{
895 struct sprd_mcdt_chan *temp;
896
897 sprd_mcdt_chan_dma_disable(chan);
898 sprd_mcdt_chan_int_disable(chan);
899
900 mutex_lock(&sprd_mcdt_list_mutex);
901
902 list_for_each_entry(temp, &sprd_mcdt_chan_list, list) {
903 if (temp == chan) {
904 mutex_unlock(&sprd_mcdt_list_mutex);
905 return;
906 }
907 }
908
909 list_add_tail(&chan->list, &sprd_mcdt_chan_list);
910 mutex_unlock(&sprd_mcdt_list_mutex);
911}
912EXPORT_SYMBOL_GPL(sprd_mcdt_free_chan);
913
914static void sprd_mcdt_init_chans(struct sprd_mcdt_dev *mcdt,
915 struct resource *res)
916{
917 int i;
918
919 for (i = 0; i < MCDT_CHANNEL_NUM; i++) {
920 struct sprd_mcdt_chan *chan = &mcdt->chan[i];
921
922 if (i < MCDT_ADC_CHANNEL_NUM) {
923 chan->id = i;
924 chan->type = SPRD_MCDT_ADC_CHAN;
925 chan->fifo_phys = res->start + MCDT_CH0_RXD + i * 4;
926 } else {
927 chan->id = i - MCDT_ADC_CHANNEL_NUM;
928 chan->type = SPRD_MCDT_DAC_CHAN;
929 chan->fifo_phys = res->start + MCDT_CH0_TXD +
930 (i - MCDT_ADC_CHANNEL_NUM) * 4;
931 }
932
933 chan->mcdt = mcdt;
934 INIT_LIST_HEAD(&chan->list);
935
936 mutex_lock(&sprd_mcdt_list_mutex);
937 list_add_tail(&chan->list, &sprd_mcdt_chan_list);
938 mutex_unlock(&sprd_mcdt_list_mutex);
939 }
940}
941
942static int sprd_mcdt_probe(struct platform_device *pdev)
943{
944 struct sprd_mcdt_dev *mcdt;
945 struct resource *res;
946 int ret, irq;
947
948 mcdt = devm_kzalloc(&pdev->dev, sizeof(*mcdt), GFP_KERNEL);
949 if (!mcdt)
950 return -ENOMEM;
951
952 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
953 mcdt->base = devm_ioremap_resource(&pdev->dev, res);
954 if (IS_ERR(mcdt->base))
955 return PTR_ERR(mcdt->base);
956
957 mcdt->dev = &pdev->dev;
958 spin_lock_init(&mcdt->lock);
959 platform_set_drvdata(pdev, mcdt);
960
961 irq = platform_get_irq(pdev, 0);
962 if (irq < 0) {
963 dev_err(&pdev->dev, "Failed to get MCDT interrupt\n");
964 return irq;
965 }
966
967 ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler,
968 0, "sprd-mcdt", mcdt);
969 if (ret) {
970 dev_err(&pdev->dev, "Failed to request MCDT IRQ\n");
971 return ret;
972 }
973
974 sprd_mcdt_init_chans(mcdt, res);
975
976 return 0;
977}
978
979static int sprd_mcdt_remove(struct platform_device *pdev)
980{
981 struct sprd_mcdt_chan *chan, *temp;
982
983 mutex_lock(&sprd_mcdt_list_mutex);
984
985 list_for_each_entry_safe(chan, temp, &sprd_mcdt_chan_list, list)
986 list_del(&chan->list);
987
988 mutex_unlock(&sprd_mcdt_list_mutex);
989
990 return 0;
991}
992
993static const struct of_device_id sprd_mcdt_of_match[] = {
994 { .compatible = "sprd,sc9860-mcdt", },
995 { }
996};
997MODULE_DEVICE_TABLE(of, sprd_mcdt_of_match);
998
999static struct platform_driver sprd_mcdt_driver = {
1000 .probe = sprd_mcdt_probe,
1001 .remove = sprd_mcdt_remove,
1002 .driver = {
1003 .name = "sprd-mcdt",
1004 .of_match_table = sprd_mcdt_of_match,
1005 },
1006};
1007
1008module_platform_driver(sprd_mcdt_driver);
1009
1010MODULE_DESCRIPTION("Spreadtrum Multi-Channel Data Transfer Driver");
1011MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sprd/sprd-mcdt.h b/sound/soc/sprd/sprd-mcdt.h
new file mode 100644
index 000000000000..9cc7e207ac76
--- /dev/null
+++ b/sound/soc/sprd/sprd-mcdt.h
@@ -0,0 +1,107 @@
1// SPDX-License-Identifier: GPL-2.0
2
3#ifndef __SPRD_MCDT_H
4#define __SPRD_MCDT_H
5
6enum sprd_mcdt_channel_type {
7 SPRD_MCDT_DAC_CHAN,
8 SPRD_MCDT_ADC_CHAN,
9 SPRD_MCDT_UNKNOWN_CHAN,
10};
11
12enum sprd_mcdt_dma_chan {
13 SPRD_MCDT_DMA_CH0,
14 SPRD_MCDT_DMA_CH1,
15 SPRD_MCDT_DMA_CH2,
16 SPRD_MCDT_DMA_CH3,
17 SPRD_MCDT_DMA_CH4,
18};
19
20struct sprd_mcdt_chan_callback {
21 void (*notify)(void *data);
22 void *data;
23};
24
25/**
26 * struct sprd_mcdt_chan - this struct represents a single channel instance
27 * @mcdt: the mcdt controller
28 * @id: channel id
29 * @fifo_phys: channel fifo physical address which is used for DMA transfer
30 * @type: channel type
31 * @cb: channel fifo interrupt's callback interface to notify the fifo events
32 * @dma_enable: indicate if use DMA mode to transfer data
33 * @int_enable: indicate if use interrupt mode to notify users to read or
34 * write data manually
35 * @list: used to link into the global list
36 *
37 * Note: users should not modify any members of this structure.
38 */
39struct sprd_mcdt_chan {
40 struct sprd_mcdt_dev *mcdt;
41 u8 id;
42 unsigned long fifo_phys;
43 enum sprd_mcdt_channel_type type;
44 enum sprd_mcdt_dma_chan dma_chan;
45 struct sprd_mcdt_chan_callback *cb;
46 bool dma_enable;
47 bool int_enable;
48 struct list_head list;
49};
50
51#ifdef CONFIG_SND_SOC_SPRD_MCDT
52struct sprd_mcdt_chan *sprd_mcdt_request_chan(u8 channel,
53 enum sprd_mcdt_channel_type type);
54void sprd_mcdt_free_chan(struct sprd_mcdt_chan *chan);
55
56int sprd_mcdt_chan_write(struct sprd_mcdt_chan *chan, char *tx_buf, u32 size);
57int sprd_mcdt_chan_read(struct sprd_mcdt_chan *chan, char *rx_buf, u32 size);
58int sprd_mcdt_chan_int_enable(struct sprd_mcdt_chan *chan, u32 water_mark,
59 struct sprd_mcdt_chan_callback *cb);
60void sprd_mcdt_chan_int_disable(struct sprd_mcdt_chan *chan);
61
62int sprd_mcdt_chan_dma_enable(struct sprd_mcdt_chan *chan,
63 enum sprd_mcdt_dma_chan dma_chan, u32 water_mark);
64void sprd_mcdt_chan_dma_disable(struct sprd_mcdt_chan *chan);
65
66#else
67
68struct sprd_mcdt_chan *sprd_mcdt_request_chan(u8 channel,
69 enum sprd_mcdt_channel_type type)
70{
71 return NULL;
72}
73
74void sprd_mcdt_free_chan(struct sprd_mcdt_chan *chan)
75{ }
76
77int sprd_mcdt_chan_write(struct sprd_mcdt_chan *chan, char *tx_buf, u32 size)
78{
79 return -EINVAL;
80}
81
82int sprd_mcdt_chan_read(struct sprd_mcdt_chan *chan, char *rx_buf, u32 size)
83{
84 return 0;
85}
86
87int sprd_mcdt_chan_int_enable(struct sprd_mcdt_chan *chan, u32 water_mark,
88 struct sprd_mcdt_chan_callback *cb)
89{
90 return -EINVAL;
91}
92
93void sprd_mcdt_chan_int_disable(struct sprd_mcdt_chan *chan)
94{ }
95
96int sprd_mcdt_chan_dma_enable(struct sprd_mcdt_chan *chan,
97 enum sprd_mcdt_dma_chan dma_chan, u32 water_mark)
98{
99 return -EINVAL;
100}
101
102void sprd_mcdt_chan_dma_disable(struct sprd_mcdt_chan *chan)
103{ }
104
105#endif
106
107#endif /* __SPRD_MCDT_H */
diff --git a/sound/soc/sprd/sprd-pcm-compress.c b/sound/soc/sprd/sprd-pcm-compress.c
new file mode 100644
index 000000000000..6cddf551bc11
--- /dev/null
+++ b/sound/soc/sprd/sprd-pcm-compress.c
@@ -0,0 +1,674 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2019 Spreadtrum Communications Inc.
3
4#include <linux/dma-mapping.h>
5#include <linux/dmaengine.h>
6#include <linux/dma/sprd-dma.h>
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <sound/pcm.h>
10#include <sound/pcm_params.h>
11#include <sound/soc.h>
12#include <sound/compress_driver.h>
13
14#include "sprd-pcm-dma.h"
15
16#define SPRD_COMPR_DMA_CHANS 2
17
18/* Default values if userspace does not set */
19#define SPRD_COMPR_MIN_FRAGMENT_SIZE SZ_8K
20#define SPRD_COMPR_MAX_FRAGMENT_SIZE SZ_128K
21#define SPRD_COMPR_MIN_NUM_FRAGMENTS 4
22#define SPRD_COMPR_MAX_NUM_FRAGMENTS 64
23
24/* DSP FIFO size */
25#define SPRD_COMPR_MCDT_EMPTY_WMK 0
26#define SPRD_COMPR_MCDT_FIFO_SIZE 512
27
28/* Stage 0 IRAM buffer size definition */
29#define SPRD_COMPR_IRAM_BUF_SIZE SZ_32K
30#define SPRD_COMPR_IRAM_INFO_SIZE (sizeof(struct sprd_compr_playinfo))
31#define SPRD_COMPR_IRAM_LINKLIST_SIZE (1024 - SPRD_COMPR_IRAM_INFO_SIZE)
32#define SPRD_COMPR_IRAM_SIZE (SPRD_COMPR_IRAM_BUF_SIZE + \
33 SPRD_COMPR_IRAM_INFO_SIZE + \
34 SPRD_COMPR_IRAM_LINKLIST_SIZE)
35
36/* Stage 1 DDR buffer size definition */
37#define SPRD_COMPR_AREA_BUF_SIZE SZ_2M
38#define SPRD_COMPR_AREA_LINKLIST_SIZE 1024
39#define SPRD_COMPR_AREA_SIZE (SPRD_COMPR_AREA_BUF_SIZE + \
40 SPRD_COMPR_AREA_LINKLIST_SIZE)
41
42struct sprd_compr_dma {
43 struct dma_chan *chan;
44 struct dma_async_tx_descriptor *desc;
45 dma_cookie_t cookie;
46 dma_addr_t phys;
47 void *virt;
48 int trans_len;
49};
50
51/*
52 * The Spreadtrum Audio compress offload mode will use 2-stage DMA transfer to
53 * save power. That means we can request 2 dma channels, one for source channel,
54 * and another one for destination channel. Once the source channel's transaction
55 * is done, it will trigger the destination channel's transaction automatically
56 * by hardware signal.
57 *
58 * For 2-stage DMA transfer, we can allocate 2 buffers: IRAM buffer (always
59 * power-on) and DDR buffer. The source channel will transfer data from IRAM
60 * buffer to the DSP fifo to decoding/encoding, once IRAM buffer is empty by
61 * transferring done, the destination channel will start to transfer data from
62 * DDR buffer to IRAM buffer.
63 *
64 * Since the DSP fifo is only 512B, IRAM buffer is allocated by 32K, and DDR
65 * buffer is larger to 2M. That means only the IRAM 32k data is transferred
66 * done, we can wake up the AP system to transfer data from DDR to IRAM, and
67 * other time the AP system can be suspended to save power.
68 */
69struct sprd_compr_stream {
70 struct snd_compr_stream *cstream;
71 struct sprd_compr_ops *compr_ops;
72 struct sprd_compr_dma dma[SPRD_COMPR_DMA_CHANS];
73
74 /* DMA engine channel number */
75 int num_channels;
76
77 /* Stage 0 IRAM buffer */
78 struct snd_dma_buffer iram_buffer;
79 /* Stage 1 DDR buffer */
80 struct snd_dma_buffer compr_buffer;
81
82 /* DSP play information IRAM buffer */
83 dma_addr_t info_phys;
84 void *info_area;
85 int info_size;
86
87 /* Data size copied to IRAM buffer */
88 int copied_total;
89 /* Total received data size from userspace */
90 int received_total;
91 /* Stage 0 IRAM buffer received data size */
92 int received_stage0;
93 /* Stage 1 DDR buffer received data size */
94 int received_stage1;
95 /* Stage 1 DDR buffer pointer */
96 int stage1_pointer;
97};
98
99static int sprd_platform_compr_trigger(struct snd_compr_stream *cstream,
100 int cmd);
101
102static void sprd_platform_compr_drain_notify(void *arg)
103{
104 struct snd_compr_stream *cstream = arg;
105 struct snd_compr_runtime *runtime = cstream->runtime;
106 struct sprd_compr_stream *stream = runtime->private_data;
107
108 memset(stream->info_area, 0, sizeof(struct sprd_compr_playinfo));
109
110 snd_compr_drain_notify(cstream);
111}
112
113static void sprd_platform_compr_dma_complete(void *data)
114{
115 struct snd_compr_stream *cstream = data;
116 struct snd_compr_runtime *runtime = cstream->runtime;
117 struct sprd_compr_stream *stream = runtime->private_data;
118 struct sprd_compr_dma *dma = &stream->dma[1];
119
120 /* Update data size copied to IRAM buffer */
121 stream->copied_total += dma->trans_len;
122 if (stream->copied_total > stream->received_total)
123 stream->copied_total = stream->received_total;
124
125 snd_compr_fragment_elapsed(cstream);
126}
127
128static int sprd_platform_compr_dma_config(struct snd_compr_stream *cstream,
129 struct snd_compr_params *params,
130 int channel)
131{
132 struct snd_compr_runtime *runtime = cstream->runtime;
133 struct sprd_compr_stream *stream = runtime->private_data;
134 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
135 struct snd_soc_component *component =
136 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
137 struct device *dev = component->dev;
138 struct sprd_compr_data *data = snd_soc_dai_get_drvdata(rtd->cpu_dai);
139 struct sprd_pcm_dma_params *dma_params = data->dma_params;
140 struct sprd_compr_dma *dma = &stream->dma[channel];
141 struct dma_slave_config config = { };
142 struct sprd_dma_linklist link = { };
143 enum dma_transfer_direction dir;
144 struct scatterlist *sg, *sgt;
145 enum dma_slave_buswidth bus_width;
146 int period, period_cnt, sg_num = 2;
147 dma_addr_t src_addr, dst_addr;
148 unsigned long flags;
149 int ret, j;
150
151 if (!dma_params) {
152 dev_err(dev, "no dma parameters setting\n");
153 return -EINVAL;
154 }
155
156 dma->chan = dma_request_slave_channel(dev,
157 dma_params->chan_name[channel]);
158 if (!dma->chan) {
159 dev_err(dev, "failed to request dma channel\n");
160 return -ENODEV;
161 }
162
163 sgt = sg = devm_kcalloc(dev, sg_num, sizeof(*sg), GFP_KERNEL);
164 if (!sg) {
165 ret = -ENOMEM;
166 goto sg_err;
167 }
168
169 switch (channel) {
170 case 0:
171 bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
172 period = (SPRD_COMPR_MCDT_FIFO_SIZE - SPRD_COMPR_MCDT_EMPTY_WMK) * 4;
173 period_cnt = params->buffer.fragment_size / period;
174 src_addr = stream->iram_buffer.addr;
175 dst_addr = dma_params->dev_phys[channel];
176 flags = SPRD_DMA_FLAGS(SPRD_DMA_SRC_CHN1,
177 SPRD_DMA_TRANS_DONE_TRG,
178 SPRD_DMA_FRAG_REQ,
179 SPRD_DMA_TRANS_INT);
180 break;
181
182 case 1:
183 bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
184 period = params->buffer.fragment_size;
185 period_cnt = params->buffer.fragments;
186 src_addr = stream->compr_buffer.addr;
187 dst_addr = stream->iram_buffer.addr;
188 flags = SPRD_DMA_FLAGS(SPRD_DMA_DST_CHN1,
189 SPRD_DMA_TRANS_DONE_TRG,
190 SPRD_DMA_FRAG_REQ,
191 SPRD_DMA_TRANS_INT);
192 break;
193
194 default:
195 ret = -EINVAL;
196 goto config_err;
197 }
198
199 dma->trans_len = period * period_cnt;
200
201 config.src_maxburst = period;
202 config.src_addr_width = bus_width;
203 config.dst_addr_width = bus_width;
204 if (cstream->direction == SND_COMPRESS_PLAYBACK) {
205 config.src_addr = src_addr;
206 config.dst_addr = dst_addr;
207 dir = DMA_MEM_TO_DEV;
208 } else {
209 config.src_addr = dst_addr;
210 config.dst_addr = src_addr;
211 dir = DMA_DEV_TO_MEM;
212 }
213
214 sg_init_table(sgt, sg_num);
215 for (j = 0; j < sg_num; j++, sgt++) {
216 sg_dma_len(sgt) = dma->trans_len;
217 sg_dma_address(sgt) = dst_addr;
218 }
219
220 /*
221 * Configure the link-list address for the DMA engine link-list
222 * mode.
223 */
224 link.virt_addr = (unsigned long)dma->virt;
225 link.phy_addr = dma->phys;
226
227 ret = dmaengine_slave_config(dma->chan, &config);
228 if (ret) {
229 dev_err(dev,
230 "failed to set slave configuration: %d\n", ret);
231 goto config_err;
232 }
233
234 /*
235 * We configure the DMA request mode, interrupt mode, channel
236 * mode and channel trigger mode by the flags.
237 */
238 dma->desc = dma->chan->device->device_prep_slave_sg(dma->chan, sg,
239 sg_num, dir,
240 flags, &link);
241 if (!dma->desc) {
242 dev_err(dev, "failed to prepare slave sg\n");
243 ret = -ENOMEM;
244 goto config_err;
245 }
246
247 /* Only channel 1 transfer can wake up the AP system. */
248 if (!params->no_wake_mode && channel == 1) {
249 dma->desc->callback = sprd_platform_compr_dma_complete;
250 dma->desc->callback_param = cstream;
251 }
252
253 devm_kfree(dev, sg);
254
255 return 0;
256
257config_err:
258 devm_kfree(dev, sg);
259sg_err:
260 dma_release_channel(dma->chan);
261 return ret;
262}
263
264static int sprd_platform_compr_set_params(struct snd_compr_stream *cstream,
265 struct snd_compr_params *params)
266{
267 struct snd_compr_runtime *runtime = cstream->runtime;
268 struct sprd_compr_stream *stream = runtime->private_data;
269 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
270 struct snd_soc_component *component =
271 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
272 struct device *dev = component->dev;
273 struct sprd_compr_params compr_params = { };
274 int ret;
275
276 /*
277 * Configure the DMA engine 2-stage transfer mode. Channel 1 set as the
278 * destination channel, and channel 0 set as the source channel, that
279 * means once the source channel's transaction is done, it will trigger
280 * the destination channel's transaction automatically.
281 */
282 ret = sprd_platform_compr_dma_config(cstream, params, 1);
283 if (ret) {
284 dev_err(dev, "failed to config stage 1 DMA: %d\n", ret);
285 return ret;
286 }
287
288 ret = sprd_platform_compr_dma_config(cstream, params, 0);
289 if (ret) {
290 dev_err(dev, "failed to config stage 0 DMA: %d\n", ret);
291 goto config_err;
292 }
293
294 compr_params.direction = cstream->direction;
295 compr_params.sample_rate = params->codec.sample_rate;
296 compr_params.channels = stream->num_channels;
297 compr_params.info_phys = stream->info_phys;
298 compr_params.info_size = stream->info_size;
299 compr_params.rate = params->codec.bit_rate;
300 compr_params.format = params->codec.id;
301
302 ret = stream->compr_ops->set_params(cstream->direction, &compr_params);
303 if (ret) {
304 dev_err(dev, "failed to set parameters: %d\n", ret);
305 goto params_err;
306 }
307
308 return 0;
309
310params_err:
311 dma_release_channel(stream->dma[0].chan);
312config_err:
313 dma_release_channel(stream->dma[1].chan);
314 return ret;
315}
316
317static int sprd_platform_compr_open(struct snd_compr_stream *cstream)
318{
319 struct snd_compr_runtime *runtime = cstream->runtime;
320 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
321 struct snd_soc_component *component =
322 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
323 struct device *dev = component->dev;
324 struct sprd_compr_data *data = snd_soc_dai_get_drvdata(rtd->cpu_dai);
325 struct sprd_compr_stream *stream;
326 struct sprd_compr_callback cb;
327 int stream_id = cstream->direction, ret;
328
329 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
330 if (ret)
331 return ret;
332
333 stream = devm_kzalloc(dev, sizeof(*stream), GFP_KERNEL);
334 if (!stream)
335 return -ENOMEM;
336
337 stream->cstream = cstream;
338 stream->num_channels = 2;
339 stream->compr_ops = data->ops;
340
341 /*
342 * Allocate the stage 0 IRAM buffer size, including the DMA 0
343 * link-list size and play information of DSP address size.
344 */
345 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_IRAM, dev,
346 SPRD_COMPR_IRAM_SIZE, &stream->iram_buffer);
347 if (ret < 0)
348 goto err_iram;
349
350 /* Use to save link-list configuration for DMA 0. */
351 stream->dma[0].virt = stream->iram_buffer.area + SPRD_COMPR_IRAM_SIZE;
352 stream->dma[0].phys = stream->iram_buffer.addr + SPRD_COMPR_IRAM_SIZE;
353
354 /* Use to update the current data offset of DSP. */
355 stream->info_phys = stream->iram_buffer.addr + SPRD_COMPR_IRAM_SIZE +
356 SPRD_COMPR_IRAM_LINKLIST_SIZE;
357 stream->info_area = stream->iram_buffer.area + SPRD_COMPR_IRAM_SIZE +
358 SPRD_COMPR_IRAM_LINKLIST_SIZE;
359 stream->info_size = SPRD_COMPR_IRAM_INFO_SIZE;
360
361 /*
362 * Allocate the stage 1 DDR buffer size, including the DMA 1 link-list
363 * size.
364 */
365 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev,
366 SPRD_COMPR_AREA_SIZE, &stream->compr_buffer);
367 if (ret < 0)
368 goto err_compr;
369
370 /* Use to save link-list configuration for DMA 1. */
371 stream->dma[1].virt = stream->compr_buffer.area + SPRD_COMPR_AREA_SIZE;
372 stream->dma[1].phys = stream->compr_buffer.addr + SPRD_COMPR_AREA_SIZE;
373
374 cb.drain_notify = sprd_platform_compr_drain_notify;
375 cb.drain_data = cstream;
376 ret = stream->compr_ops->open(stream_id, &cb);
377 if (ret) {
378 dev_err(dev, "failed to open compress platform: %d\n", ret);
379 goto err_open;
380 }
381
382 runtime->private_data = stream;
383 return 0;
384
385err_open:
386 snd_dma_free_pages(&stream->compr_buffer);
387err_compr:
388 snd_dma_free_pages(&stream->iram_buffer);
389err_iram:
390 devm_kfree(dev, stream);
391
392 return ret;
393}
394
395static int sprd_platform_compr_free(struct snd_compr_stream *cstream)
396{
397 struct snd_compr_runtime *runtime = cstream->runtime;
398 struct sprd_compr_stream *stream = runtime->private_data;
399 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
400 struct snd_soc_component *component =
401 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
402 struct device *dev = component->dev;
403 int stream_id = cstream->direction, i;
404
405 for (i = 0; i < stream->num_channels; i++) {
406 struct sprd_compr_dma *dma = &stream->dma[i];
407
408 if (dma->chan) {
409 dma_release_channel(dma->chan);
410 dma->chan = NULL;
411 }
412 }
413
414 snd_dma_free_pages(&stream->compr_buffer);
415 snd_dma_free_pages(&stream->iram_buffer);
416
417 stream->compr_ops->close(stream_id);
418
419 devm_kfree(dev, stream);
420 return 0;
421}
422
423static int sprd_platform_compr_trigger(struct snd_compr_stream *cstream,
424 int cmd)
425{
426 struct snd_compr_runtime *runtime = cstream->runtime;
427 struct sprd_compr_stream *stream = runtime->private_data;
428 struct snd_soc_pcm_runtime *rtd = cstream->private_data;
429 struct snd_soc_component *component =
430 snd_soc_rtdcom_lookup(rtd, DRV_NAME);
431 struct device *dev = component->dev;
432 int channels = stream->num_channels, ret = 0, i;
433 int stream_id = cstream->direction;
434
435 if (cstream->direction != SND_COMPRESS_PLAYBACK) {
436 dev_err(dev, "unsupported compress direction\n");
437 return -EINVAL;
438 }
439
440 switch (cmd) {
441 case SNDRV_PCM_TRIGGER_START:
442 for (i = channels - 1; i >= 0; i--) {
443 struct sprd_compr_dma *dma = &stream->dma[i];
444
445 if (!dma->desc)
446 continue;
447
448 dma->cookie = dmaengine_submit(dma->desc);
449 ret = dma_submit_error(dma->cookie);
450 if (ret) {
451 dev_err(dev, "failed to submit request: %d\n",
452 ret);
453 return ret;
454 }
455 }
456
457 for (i = channels - 1; i >= 0; i--) {
458 struct sprd_compr_dma *dma = &stream->dma[i];
459
460 if (dma->chan)
461 dma_async_issue_pending(dma->chan);
462 }
463
464 ret = stream->compr_ops->start(stream_id);
465 break;
466
467 case SNDRV_PCM_TRIGGER_STOP:
468 for (i = channels - 1; i >= 0; i--) {
469 struct sprd_compr_dma *dma = &stream->dma[i];
470
471 if (dma->chan)
472 dmaengine_terminate_async(dma->chan);
473 }
474
475 stream->copied_total = 0;
476 stream->stage1_pointer = 0;
477 stream->received_total = 0;
478 stream->received_stage0 = 0;
479 stream->received_stage1 = 0;
480
481 ret = stream->compr_ops->stop(stream_id);
482 break;
483
484 case SNDRV_PCM_TRIGGER_SUSPEND:
485 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
486 for (i = channels - 1; i >= 0; i--) {
487 struct sprd_compr_dma *dma = &stream->dma[i];
488
489 if (dma->chan)
490 dmaengine_pause(dma->chan);
491 }
492
493 ret = stream->compr_ops->pause(stream_id);
494 break;
495
496 case SNDRV_PCM_TRIGGER_RESUME:
497 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
498 for (i = channels - 1; i >= 0; i--) {
499 struct sprd_compr_dma *dma = &stream->dma[i];
500
501 if (dma->chan)
502 dmaengine_resume(dma->chan);
503 }
504
505 ret = stream->compr_ops->pause_release(stream_id);
506 break;
507
508 case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
509 case SND_COMPR_TRIGGER_DRAIN:
510 ret = stream->compr_ops->drain(stream->received_total);
511 break;
512
513 default:
514 ret = -EINVAL;
515 break;
516 }
517
518 return ret;
519}
520
521static int sprd_platform_compr_pointer(struct snd_compr_stream *cstream,
522 struct snd_compr_tstamp *tstamp)
523{
524 struct snd_compr_runtime *runtime = cstream->runtime;
525 struct sprd_compr_stream *stream = runtime->private_data;
526 struct sprd_compr_playinfo *info =
527 (struct sprd_compr_playinfo *)stream->info_area;
528
529 tstamp->copied_total = stream->copied_total;
530 tstamp->pcm_io_frames = info->current_data_offset;
531
532 return 0;
533}
534
535static int sprd_platform_compr_copy(struct snd_compr_stream *cstream,
536 char __user *buf, size_t count)
537{
538 struct snd_compr_runtime *runtime = cstream->runtime;
539 struct sprd_compr_stream *stream = runtime->private_data;
540 int avail_bytes, data_count = count;
541 void *dst;
542
543 /*
544 * We usually set fragment size as 32K, and the stage 0 IRAM buffer
545 * size is 32K too. So if now the received data size of the stage 0
546 * IRAM buffer is less than 32K, that means we have some available
547 * spaces for the stage 0 IRAM buffer.
548 */
549 if (stream->received_stage0 < runtime->fragment_size) {
550 avail_bytes = runtime->fragment_size - stream->received_stage0;
551 dst = stream->iram_buffer.area + stream->received_stage0;
552
553 if (avail_bytes >= data_count) {
554 /*
555 * Copy data to the stage 0 IRAM buffer directly if
556 * spaces are enough.
557 */
558 if (copy_from_user(dst, buf, data_count))
559 return -EFAULT;
560
561 stream->received_stage0 += data_count;
562 stream->copied_total += data_count;
563 goto copy_done;
564 } else {
565 /*
566 * If the data count is larger than the available spaces
567 * of the the stage 0 IRAM buffer, we should copy one
568 * partial data to the stage 0 IRAM buffer, and copy
569 * the left to the stage 1 DDR buffer.
570 */
571 if (copy_from_user(dst, buf, avail_bytes))
572 return -EFAULT;
573
574 data_count -= avail_bytes;
575 stream->received_stage0 += avail_bytes;
576 stream->copied_total += avail_bytes;
577 buf += avail_bytes;
578 }
579 }
580
581 /*
582 * Copy data to the stage 1 DDR buffer if no spaces for the stage 0 IRAM
583 * buffer.
584 */
585 dst = stream->compr_buffer.area + stream->stage1_pointer;
586 if (data_count < stream->compr_buffer.bytes - stream->stage1_pointer) {
587 if (copy_from_user(dst, buf, data_count))
588 return -EFAULT;
589
590 stream->stage1_pointer += data_count;
591 } else {
592 avail_bytes = stream->compr_buffer.bytes - stream->stage1_pointer;
593
594 if (copy_from_user(dst, buf, avail_bytes))
595 return -EFAULT;
596
597 if (copy_from_user(stream->compr_buffer.area, buf + avail_bytes,
598 data_count - avail_bytes))
599 return -EFAULT;
600
601 stream->stage1_pointer = data_count - avail_bytes;
602 }
603
604 stream->received_stage1 += data_count;
605
606copy_done:
607 /* Update the copied data size. */
608 stream->received_total += count;
609 return count;
610}
611
612static int sprd_platform_compr_get_caps(struct snd_compr_stream *cstream,
613 struct snd_compr_caps *caps)
614{
615 caps->direction = cstream->direction;
616 caps->min_fragment_size = SPRD_COMPR_MIN_FRAGMENT_SIZE;
617 caps->max_fragment_size = SPRD_COMPR_MAX_FRAGMENT_SIZE;
618 caps->min_fragments = SPRD_COMPR_MIN_NUM_FRAGMENTS;
619 caps->max_fragments = SPRD_COMPR_MAX_NUM_FRAGMENTS;
620 caps->num_codecs = 2;
621 caps->codecs[0] = SND_AUDIOCODEC_MP3;
622 caps->codecs[1] = SND_AUDIOCODEC_AAC;
623
624 return 0;
625}
626
627static int
628sprd_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
629 struct snd_compr_codec_caps *codec)
630{
631 switch (codec->codec) {
632 case SND_AUDIOCODEC_MP3:
633 codec->num_descriptors = 2;
634 codec->descriptor[0].max_ch = 2;
635 codec->descriptor[0].bit_rate[0] = 320;
636 codec->descriptor[0].bit_rate[1] = 128;
637 codec->descriptor[0].num_bitrates = 2;
638 codec->descriptor[0].profiles = 0;
639 codec->descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO;
640 codec->descriptor[0].formats = 0;
641 break;
642
643 case SND_AUDIOCODEC_AAC:
644 codec->num_descriptors = 2;
645 codec->descriptor[1].max_ch = 2;
646 codec->descriptor[1].bit_rate[0] = 320;
647 codec->descriptor[1].bit_rate[1] = 128;
648 codec->descriptor[1].num_bitrates = 2;
649 codec->descriptor[1].profiles = 0;
650 codec->descriptor[1].modes = 0;
651 codec->descriptor[1].formats = 0;
652 break;
653
654 default:
655 return -EINVAL;
656 }
657
658 return 0;
659}
660
661const struct snd_compr_ops sprd_platform_compr_ops = {
662 .open = sprd_platform_compr_open,
663 .free = sprd_platform_compr_free,
664 .set_params = sprd_platform_compr_set_params,
665 .trigger = sprd_platform_compr_trigger,
666 .pointer = sprd_platform_compr_pointer,
667 .copy = sprd_platform_compr_copy,
668 .get_caps = sprd_platform_compr_get_caps,
669 .get_codec_caps = sprd_platform_compr_get_codec_caps,
670};
671
672MODULE_DESCRIPTION("Spreadtrum ASoC Compress Platform Driver");
673MODULE_LICENSE("GPL v2");
674MODULE_ALIAS("platform:compress-platform");
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index cbb27c4abeba..d38ebbbbf169 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -6,6 +6,7 @@
6#include <linux/dma/sprd-dma.h> 6#include <linux/dma/sprd-dma.h>
7#include <linux/kernel.h> 7#include <linux/kernel.h>
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/of_reserved_mem.h>
9#include <linux/platform_device.h> 10#include <linux/platform_device.h>
10#include <sound/pcm.h> 11#include <sound/pcm.h>
11#include <sound/pcm_params.h> 12#include <sound/pcm_params.h>
@@ -13,7 +14,6 @@
13 14
14#include "sprd-pcm-dma.h" 15#include "sprd-pcm-dma.h"
15 16
16#define DRV_NAME "sprd_pcm_dma"
17#define SPRD_PCM_DMA_LINKLIST_SIZE 64 17#define SPRD_PCM_DMA_LINKLIST_SIZE 64
18#define SPRD_PCM_DMA_BRUST_LEN 640 18#define SPRD_PCM_DMA_BRUST_LEN 640
19 19
@@ -524,14 +524,21 @@ static void sprd_pcm_free(struct snd_pcm *pcm)
524static const struct snd_soc_component_driver sprd_soc_component = { 524static const struct snd_soc_component_driver sprd_soc_component = {
525 .name = DRV_NAME, 525 .name = DRV_NAME,
526 .ops = &sprd_pcm_ops, 526 .ops = &sprd_pcm_ops,
527 .compr_ops = &sprd_platform_compr_ops,
527 .pcm_new = sprd_pcm_new, 528 .pcm_new = sprd_pcm_new,
528 .pcm_free = sprd_pcm_free, 529 .pcm_free = sprd_pcm_free,
529}; 530};
530 531
531static int sprd_soc_platform_probe(struct platform_device *pdev) 532static int sprd_soc_platform_probe(struct platform_device *pdev)
532{ 533{
534 struct device_node *np = pdev->dev.of_node;
533 int ret; 535 int ret;
534 536
537 ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
538 if (ret)
539 dev_warn(&pdev->dev,
540 "no reserved DMA memory for audio platform device\n");
541
535 ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component, 542 ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component,
536 NULL, 0); 543 NULL, 0);
537 if (ret) 544 if (ret)
diff --git a/sound/soc/sprd/sprd-pcm-dma.h b/sound/soc/sprd/sprd-pcm-dma.h
index d85a34f1461d..08e9fdba82f1 100644
--- a/sound/soc/sprd/sprd-pcm-dma.h
+++ b/sound/soc/sprd/sprd-pcm-dma.h
@@ -3,8 +3,11 @@
3#ifndef __SPRD_PCM_DMA_H 3#ifndef __SPRD_PCM_DMA_H
4#define __SPRD_PCM_DMA_H 4#define __SPRD_PCM_DMA_H
5 5
6#define DRV_NAME "sprd_pcm_dma"
6#define SPRD_PCM_CHANNEL_MAX 2 7#define SPRD_PCM_CHANNEL_MAX 2
7 8
9extern const struct snd_compr_ops sprd_platform_compr_ops;
10
8struct sprd_pcm_dma_params { 11struct sprd_pcm_dma_params {
9 dma_addr_t dev_phys[SPRD_PCM_CHANNEL_MAX]; 12 dma_addr_t dev_phys[SPRD_PCM_CHANNEL_MAX];
10 u32 datawidth[SPRD_PCM_CHANNEL_MAX]; 13 u32 datawidth[SPRD_PCM_CHANNEL_MAX];
@@ -12,4 +15,44 @@ struct sprd_pcm_dma_params {
12 const char *chan_name[SPRD_PCM_CHANNEL_MAX]; 15 const char *chan_name[SPRD_PCM_CHANNEL_MAX];
13}; 16};
14 17
18struct sprd_compr_playinfo {
19 int total_time;
20 int current_time;
21 int total_data_length;
22 int current_data_offset;
23};
24
25struct sprd_compr_params {
26 u32 direction;
27 u32 rate;
28 u32 sample_rate;
29 u32 channels;
30 u32 format;
31 u32 period;
32 u32 periods;
33 u32 info_phys;
34 u32 info_size;
35};
36
37struct sprd_compr_callback {
38 void (*drain_notify)(void *data);
39 void *drain_data;
40};
41
42struct sprd_compr_ops {
43 int (*open)(int str_id, struct sprd_compr_callback *cb);
44 int (*close)(int str_id);
45 int (*start)(int str_id);
46 int (*stop)(int str_id);
47 int (*pause)(int str_id);
48 int (*pause_release)(int str_id);
49 int (*drain)(int received_total);
50 int (*set_params)(int str_id, struct sprd_compr_params *params);
51};
52
53struct sprd_compr_data {
54 struct sprd_compr_ops *ops;
55 struct sprd_pcm_dma_params *dma_params;
56};
57
15#endif /* __SPRD_PCM_DMA_H */ 58#endif /* __SPRD_PCM_DMA_H */
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 78bed9734713..cc517e007039 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -44,7 +44,7 @@ struct stm32_adfsdm_priv {
44 44
45static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = { 45static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
46 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 46 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
47 SNDRV_PCM_INFO_PAUSE, 47 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE,
48 .formats = SNDRV_PCM_FMTBIT_S32_LE, 48 .formats = SNDRV_PCM_FMTBIT_S32_LE,
49 49
50 .rate_min = 8000, 50 .rate_min = 8000,
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 8968458eec62..8ee697ff1f86 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -179,7 +179,6 @@ enum i2s_datlen {
179 I2S_I2SMOD_DATLEN_32, 179 I2S_I2SMOD_DATLEN_32,
180}; 180};
181 181
182#define STM32_I2S_DAI_NAME_SIZE 20
183#define STM32_I2S_FIFO_SIZE 16 182#define STM32_I2S_FIFO_SIZE 16
184 183
185#define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) 184#define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER)
@@ -202,7 +201,6 @@ enum i2s_datlen {
202 * @phys_addr: I2S registers physical base address 201 * @phys_addr: I2S registers physical base address
203 * @lock_fd: lock to manage race conditions in full duplex mode 202 * @lock_fd: lock to manage race conditions in full duplex mode
204 * @irq_lock: prevent race condition with IRQ 203 * @irq_lock: prevent race condition with IRQ
205 * @dais_name: DAI name
206 * @mclk_rate: master clock frequency (Hz) 204 * @mclk_rate: master clock frequency (Hz)
207 * @fmt: DAI protocol 205 * @fmt: DAI protocol
208 * @refcount: keep count of opened streams on I2S 206 * @refcount: keep count of opened streams on I2S
@@ -224,7 +222,6 @@ struct stm32_i2s_data {
224 dma_addr_t phys_addr; 222 dma_addr_t phys_addr;
225 spinlock_t lock_fd; /* Manage race conditions for full duplex */ 223 spinlock_t lock_fd; /* Manage race conditions for full duplex */
226 spinlock_t irq_lock; /* used to prevent race condition with IRQ */ 224 spinlock_t irq_lock; /* used to prevent race condition with IRQ */
227 char dais_name[STM32_I2S_DAI_NAME_SIZE];
228 unsigned int mclk_rate; 225 unsigned int mclk_rate;
229 unsigned int fmt; 226 unsigned int fmt;
230 int refcount; 227 int refcount;
@@ -495,12 +492,6 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai,
495 unsigned int fthlv; 492 unsigned int fthlv;
496 int ret; 493 int ret;
497 494
498 if ((params_channels(params) == 1) &&
499 ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A)) {
500 dev_err(cpu_dai->dev, "Mono mode supported only by DSP_A\n");
501 return -EINVAL;
502 }
503
504 switch (format) { 495 switch (format) {
505 case 16: 496 case 16:
506 cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16); 497 cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16);
@@ -550,6 +541,10 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream,
550 i2s->substream = substream; 541 i2s->substream = substream;
551 spin_unlock_irqrestore(&i2s->irq_lock, flags); 542 spin_unlock_irqrestore(&i2s->irq_lock, flags);
552 543
544 if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_DSP_A)
545 snd_pcm_hw_constraint_single(substream->runtime,
546 SNDRV_PCM_HW_PARAM_CHANNELS, 2);
547
553 ret = clk_prepare_enable(i2s->i2sclk); 548 ret = clk_prepare_enable(i2s->i2sclk);
554 if (ret < 0) { 549 if (ret < 0) {
555 dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret); 550 dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret);
@@ -592,7 +587,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
592 case SNDRV_PCM_TRIGGER_RESUME: 587 case SNDRV_PCM_TRIGGER_RESUME:
593 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 588 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
594 /* Enable i2s */ 589 /* Enable i2s */
595 dev_dbg(cpu_dai->dev, "start I2S\n"); 590 dev_dbg(cpu_dai->dev, "start I2S %s\n",
591 playback_flg ? "playback" : "capture");
596 592
597 cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; 593 cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN;
598 regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, 594 regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG,
@@ -637,6 +633,9 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
637 case SNDRV_PCM_TRIGGER_STOP: 633 case SNDRV_PCM_TRIGGER_STOP:
638 case SNDRV_PCM_TRIGGER_SUSPEND: 634 case SNDRV_PCM_TRIGGER_SUSPEND:
639 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 635 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
636 dev_dbg(cpu_dai->dev, "stop I2S %s\n",
637 playback_flg ? "playback" : "capture");
638
640 if (playback_flg) 639 if (playback_flg)
641 regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, 640 regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG,
642 I2S_IER_UDRIE, 641 I2S_IER_UDRIE,
@@ -653,8 +652,6 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
653 break; 652 break;
654 } 653 }
655 654
656 dev_dbg(cpu_dai->dev, "stop I2S\n");
657
658 ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, 655 ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG,
659 I2S_CR1_SPE, 0); 656 I2S_CR1_SPE, 0);
660 if (ret < 0) { 657 if (ret < 0) {
@@ -734,7 +731,8 @@ static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = {
734static const struct snd_pcm_hardware stm32_i2s_pcm_hw = { 731static const struct snd_pcm_hardware stm32_i2s_pcm_hw = {
735 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, 732 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
736 .buffer_bytes_max = 8 * PAGE_SIZE, 733 .buffer_bytes_max = 8 * PAGE_SIZE,
737 .period_bytes_max = 2048, 734 .period_bytes_min = 1024,
735 .period_bytes_max = 4 * PAGE_SIZE,
738 .periods_min = 2, 736 .periods_min = 2,
739 .periods_max = 8, 737 .periods_max = 8,
740}; 738};
@@ -770,12 +768,8 @@ static int stm32_i2s_dais_init(struct platform_device *pdev,
770 if (!dai_ptr) 768 if (!dai_ptr)
771 return -ENOMEM; 769 return -ENOMEM;
772 770
773 snprintf(i2s->dais_name, STM32_I2S_DAI_NAME_SIZE,
774 "%s", dev_name(&pdev->dev));
775
776 dai_ptr->probe = stm32_i2s_dai_probe; 771 dai_ptr->probe = stm32_i2s_dai_probe;
777 dai_ptr->ops = &stm32_i2s_pcm_dai_ops; 772 dai_ptr->ops = &stm32_i2s_pcm_dai_ops;
778 dai_ptr->name = i2s->dais_name;
779 dai_ptr->id = 1; 773 dai_ptr->id = 1;
780 stm32_i2s_dai_init(&dai_ptr->playback, "playback"); 774 stm32_i2s_dai_init(&dai_ptr->playback, "playback");
781 stm32_i2s_dai_init(&dai_ptr->capture, "capture"); 775 stm32_i2s_dai_init(&dai_ptr->capture, "capture");
@@ -845,8 +839,9 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
845 /* Get irqs */ 839 /* Get irqs */
846 irq = platform_get_irq(pdev, 0); 840 irq = platform_get_irq(pdev, 0);
847 if (irq < 0) { 841 if (irq < 0) {
848 dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); 842 if (irq != -EPROBE_DEFER)
849 return -ENOENT; 843 dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
844 return irq;
850 } 845 }
851 846
852 ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT, 847 ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, IRQF_ONESHOT,
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index d68d62f12df5..7550d5f08be3 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -21,6 +21,7 @@
21#include <linux/delay.h> 21#include <linux/delay.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/of_platform.h> 23#include <linux/of_platform.h>
24#include <linux/pinctrl/consumer.h>
24#include <linux/reset.h> 25#include <linux/reset.h>
25 26
26#include <sound/dmaengine_pcm.h> 27#include <sound/dmaengine_pcm.h>
@@ -44,20 +45,41 @@ static const struct of_device_id stm32_sai_ids[] = {
44 {} 45 {}
45}; 46};
46 47
47static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci) 48static int stm32_sai_pclk_disable(struct device *dev)
49{
50 struct stm32_sai_data *sai = dev_get_drvdata(dev);
51
52 clk_disable_unprepare(sai->pclk);
53
54 return 0;
55}
56
57static int stm32_sai_pclk_enable(struct device *dev)
48{ 58{
59 struct stm32_sai_data *sai = dev_get_drvdata(dev);
49 int ret; 60 int ret;
50 61
51 /* Enable peripheral clock to allow GCR register access */
52 ret = clk_prepare_enable(sai->pclk); 62 ret = clk_prepare_enable(sai->pclk);
53 if (ret) { 63 if (ret) {
54 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret); 64 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
55 return ret; 65 return ret;
56 } 66 }
57 67
68 return 0;
69}
70
71static int stm32_sai_sync_conf_client(struct stm32_sai_data *sai, int synci)
72{
73 int ret;
74
75 /* Enable peripheral clock to allow GCR register access */
76 ret = stm32_sai_pclk_enable(&sai->pdev->dev);
77 if (ret)
78 return ret;
79
58 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base); 80 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCIN_MASK, (synci - 1)), sai->base);
59 81
60 clk_disable_unprepare(sai->pclk); 82 stm32_sai_pclk_disable(&sai->pdev->dev);
61 83
62 return 0; 84 return 0;
63} 85}
@@ -68,11 +90,9 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
68 int ret; 90 int ret;
69 91
70 /* Enable peripheral clock to allow GCR register access */ 92 /* Enable peripheral clock to allow GCR register access */
71 ret = clk_prepare_enable(sai->pclk); 93 ret = stm32_sai_pclk_enable(&sai->pdev->dev);
72 if (ret) { 94 if (ret)
73 dev_err(&sai->pdev->dev, "failed to enable clock: %d\n", ret);
74 return ret; 95 return ret;
75 }
76 96
77 dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n", 97 dev_dbg(&sai->pdev->dev, "Set %pOFn%s as synchro provider\n",
78 sai->pdev->dev.of_node, 98 sai->pdev->dev.of_node,
@@ -83,13 +103,13 @@ static int stm32_sai_sync_conf_provider(struct stm32_sai_data *sai, int synco)
83 dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n", 103 dev_err(&sai->pdev->dev, "%pOFn%s already set as sync provider\n",
84 sai->pdev->dev.of_node, 104 sai->pdev->dev.of_node,
85 prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B"); 105 prev_synco == STM_SAI_SYNC_OUT_A ? "A" : "B");
86 clk_disable_unprepare(sai->pclk); 106 stm32_sai_pclk_disable(&sai->pdev->dev);
87 return -EINVAL; 107 return -EINVAL;
88 } 108 }
89 109
90 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base); 110 writel_relaxed(FIELD_PREP(SAI_GCR_SYNCOUT_MASK, synco), sai->base);
91 111
92 clk_disable_unprepare(sai->pclk); 112 stm32_sai_pclk_disable(&sai->pdev->dev);
93 113
94 return 0; 114 return 0;
95} 115}
@@ -195,12 +215,54 @@ static int stm32_sai_probe(struct platform_device *pdev)
195 return devm_of_platform_populate(&pdev->dev); 215 return devm_of_platform_populate(&pdev->dev);
196} 216}
197 217
218#ifdef CONFIG_PM_SLEEP
219/*
220 * When pins are shared by two sai sub instances, pins have to be defined
221 * in sai parent node. In this case, pins state is not managed by alsa fw.
222 * These pins are managed in suspend/resume callbacks.
223 */
224static int stm32_sai_suspend(struct device *dev)
225{
226 struct stm32_sai_data *sai = dev_get_drvdata(dev);
227 int ret;
228
229 ret = stm32_sai_pclk_enable(dev);
230 if (ret)
231 return ret;
232
233 sai->gcr = readl_relaxed(sai->base);
234 stm32_sai_pclk_disable(dev);
235
236 return pinctrl_pm_select_sleep_state(dev);
237}
238
239static int stm32_sai_resume(struct device *dev)
240{
241 struct stm32_sai_data *sai = dev_get_drvdata(dev);
242 int ret;
243
244 ret = stm32_sai_pclk_enable(dev);
245 if (ret)
246 return ret;
247
248 writel_relaxed(sai->gcr, sai->base);
249 stm32_sai_pclk_disable(dev);
250
251 return pinctrl_pm_select_default_state(dev);
252}
253#endif /* CONFIG_PM_SLEEP */
254
255static const struct dev_pm_ops stm32_sai_pm_ops = {
256 SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume)
257};
258
198MODULE_DEVICE_TABLE(of, stm32_sai_ids); 259MODULE_DEVICE_TABLE(of, stm32_sai_ids);
199 260
200static struct platform_driver stm32_sai_driver = { 261static struct platform_driver stm32_sai_driver = {
201 .driver = { 262 .driver = {
202 .name = "st,stm32-sai", 263 .name = "st,stm32-sai",
203 .of_match_table = stm32_sai_ids, 264 .of_match_table = stm32_sai_ids,
265 .pm = &stm32_sai_pm_ops,
204 }, 266 },
205 .probe = stm32_sai_probe, 267 .probe = stm32_sai_probe,
206}; 268};
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
index 08de899c766b..9c36a393ab7b 100644
--- a/sound/soc/stm/stm32_sai.h
+++ b/sound/soc/stm/stm32_sai.h
@@ -268,6 +268,7 @@ struct stm32_sai_conf {
268 * @version: SOC version 268 * @version: SOC version
269 * @irq: SAI interrupt line 269 * @irq: SAI interrupt line
270 * @set_sync: pointer to synchro mode configuration callback 270 * @set_sync: pointer to synchro mode configuration callback
271 * @gcr: SAI Global Configuration Register
271 */ 272 */
272struct stm32_sai_data { 273struct stm32_sai_data {
273 struct platform_device *pdev; 274 struct platform_device *pdev;
@@ -279,4 +280,5 @@ struct stm32_sai_data {
279 int irq; 280 int irq;
280 int (*set_sync)(struct stm32_sai_data *sai, 281 int (*set_sync)(struct stm32_sai_data *sai,
281 struct device_node *np_provider, int synco, int synci); 282 struct device_node *np_provider, int synco, int synci);
283 u32 gcr;
282}; 284};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index d7045aa520de..2a74ce7c9440 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -110,7 +110,7 @@ struct stm32_sai_sub_data {
110 struct regmap *regmap; 110 struct regmap *regmap;
111 const struct regmap_config *regmap_config; 111 const struct regmap_config *regmap_config;
112 struct snd_dmaengine_dai_dma_data dma_params; 112 struct snd_dmaengine_dai_dma_data dma_params;
113 struct snd_soc_dai_driver *cpu_dai_drv; 113 struct snd_soc_dai_driver cpu_dai_drv;
114 struct snd_soc_dai *cpu_dai; 114 struct snd_soc_dai *cpu_dai;
115 struct snd_pcm_substream *substream; 115 struct snd_pcm_substream *substream;
116 struct stm32_sai_data *pdata; 116 struct stm32_sai_data *pdata;
@@ -169,6 +169,7 @@ static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg)
169{ 169{
170 switch (reg) { 170 switch (reg) {
171 case STM_SAI_DR_REGX: 171 case STM_SAI_DR_REGX:
172 case STM_SAI_SR_REGX:
172 return true; 173 return true;
173 default: 174 default:
174 return false; 175 return false;
@@ -183,7 +184,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
183 case STM_SAI_FRCR_REGX: 184 case STM_SAI_FRCR_REGX:
184 case STM_SAI_SLOTR_REGX: 185 case STM_SAI_SLOTR_REGX:
185 case STM_SAI_IMR_REGX: 186 case STM_SAI_IMR_REGX:
186 case STM_SAI_SR_REGX:
187 case STM_SAI_CLRFR_REGX: 187 case STM_SAI_CLRFR_REGX:
188 case STM_SAI_DR_REGX: 188 case STM_SAI_DR_REGX:
189 case STM_SAI_PDMCR_REGX: 189 case STM_SAI_PDMCR_REGX:
@@ -203,6 +203,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
203 .volatile_reg = stm32_sai_sub_volatile_reg, 203 .volatile_reg = stm32_sai_sub_volatile_reg,
204 .writeable_reg = stm32_sai_sub_writeable_reg, 204 .writeable_reg = stm32_sai_sub_writeable_reg,
205 .fast_io = true, 205 .fast_io = true,
206 .cache_type = REGCACHE_FLAT,
206}; 207};
207 208
208static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { 209static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
@@ -214,6 +215,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
214 .volatile_reg = stm32_sai_sub_volatile_reg, 215 .volatile_reg = stm32_sai_sub_volatile_reg,
215 .writeable_reg = stm32_sai_sub_writeable_reg, 216 .writeable_reg = stm32_sai_sub_writeable_reg,
216 .fast_io = true, 217 .fast_io = true,
218 .cache_type = REGCACHE_FLAT,
217}; 219};
218 220
219static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, 221static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol,
@@ -461,8 +463,8 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
461 if (!flags) 463 if (!flags)
462 return IRQ_NONE; 464 return IRQ_NONE;
463 465
464 regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, 466 regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
465 SAI_XCLRFR_MASK); 467 SAI_XCLRFR_MASK);
466 468
467 if (!sai->substream) { 469 if (!sai->substream) {
468 dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr); 470 dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
@@ -728,9 +730,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream,
728 } 730 }
729 731
730 /* Enable ITs */ 732 /* Enable ITs */
731 733 regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX,
732 regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, 734 SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
733 SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
734 735
735 imr = SAI_XIMR_OVRUDRIE; 736 imr = SAI_XIMR_OVRUDRIE;
736 if (STM_SAI_IS_CAPTURE(sai)) { 737 if (STM_SAI_IS_CAPTURE(sai)) {
@@ -762,10 +763,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
762 * SAI fifo threshold is set to half fifo, to keep enough space 763 * SAI fifo threshold is set to half fifo, to keep enough space
763 * for DMA incoming bursts. 764 * for DMA incoming bursts.
764 */ 765 */
765 regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX, 766 regmap_write_bits(sai->regmap, STM_SAI_CR2_REGX,
766 SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, 767 SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
767 SAI_XCR2_FFLUSH | 768 SAI_XCR2_FFLUSH |
768 SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); 769 SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
769 770
770 /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ 771 /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/
771 if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { 772 if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
@@ -1233,8 +1234,7 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
1233 .periods_max = 8, 1234 .periods_max = 8,
1234}; 1235};
1235 1236
1236static struct snd_soc_dai_driver stm32_sai_playback_dai[] = { 1237static struct snd_soc_dai_driver stm32_sai_playback_dai = {
1237{
1238 .probe = stm32_sai_dai_probe, 1238 .probe = stm32_sai_dai_probe,
1239 .pcm_new = stm32_sai_pcm_new, 1239 .pcm_new = stm32_sai_pcm_new,
1240 .id = 1, /* avoid call to fmt_single_name() */ 1240 .id = 1, /* avoid call to fmt_single_name() */
@@ -1251,11 +1251,9 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai[] = {
1251 SNDRV_PCM_FMTBIT_S32_LE, 1251 SNDRV_PCM_FMTBIT_S32_LE,
1252 }, 1252 },
1253 .ops = &stm32_sai_pcm_dai_ops, 1253 .ops = &stm32_sai_pcm_dai_ops,
1254 }
1255}; 1254};
1256 1255
1257static struct snd_soc_dai_driver stm32_sai_capture_dai[] = { 1256static struct snd_soc_dai_driver stm32_sai_capture_dai = {
1258{
1259 .probe = stm32_sai_dai_probe, 1257 .probe = stm32_sai_dai_probe,
1260 .id = 1, /* avoid call to fmt_single_name() */ 1258 .id = 1, /* avoid call to fmt_single_name() */
1261 .capture = { 1259 .capture = {
@@ -1271,7 +1269,6 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai[] = {
1271 SNDRV_PCM_FMTBIT_S32_LE, 1269 SNDRV_PCM_FMTBIT_S32_LE,
1272 }, 1270 },
1273 .ops = &stm32_sai_pcm_dai_ops, 1271 .ops = &stm32_sai_pcm_dai_ops,
1274 }
1275}; 1272};
1276 1273
1277static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { 1274static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
@@ -1440,29 +1437,6 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
1440 return 0; 1437 return 0;
1441} 1438}
1442 1439
1443static int stm32_sai_sub_dais_init(struct platform_device *pdev,
1444 struct stm32_sai_sub_data *sai)
1445{
1446 sai->cpu_dai_drv = devm_kzalloc(&pdev->dev,
1447 sizeof(struct snd_soc_dai_driver),
1448 GFP_KERNEL);
1449 if (!sai->cpu_dai_drv)
1450 return -ENOMEM;
1451
1452 if (STM_SAI_IS_PLAYBACK(sai)) {
1453 memcpy(sai->cpu_dai_drv, &stm32_sai_playback_dai,
1454 sizeof(stm32_sai_playback_dai));
1455 sai->cpu_dai_drv->playback.stream_name = sai->cpu_dai_drv->name;
1456 } else {
1457 memcpy(sai->cpu_dai_drv, &stm32_sai_capture_dai,
1458 sizeof(stm32_sai_capture_dai));
1459 sai->cpu_dai_drv->capture.stream_name = sai->cpu_dai_drv->name;
1460 }
1461 sai->cpu_dai_drv->name = dev_name(&pdev->dev);
1462
1463 return 0;
1464}
1465
1466static int stm32_sai_sub_probe(struct platform_device *pdev) 1440static int stm32_sai_sub_probe(struct platform_device *pdev)
1467{ 1441{
1468 struct stm32_sai_sub_data *sai; 1442 struct stm32_sai_sub_data *sai;
@@ -1494,9 +1468,11 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
1494 if (ret) 1468 if (ret)
1495 return ret; 1469 return ret;
1496 1470
1497 ret = stm32_sai_sub_dais_init(pdev, sai); 1471 if (STM_SAI_IS_PLAYBACK(sai))
1498 if (ret) 1472 sai->cpu_dai_drv = stm32_sai_playback_dai;
1499 return ret; 1473 else
1474 sai->cpu_dai_drv = stm32_sai_capture_dai;
1475 sai->cpu_dai_drv.name = dev_name(&pdev->dev);
1500 1476
1501 ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr, 1477 ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr,
1502 IRQF_SHARED, dev_name(&pdev->dev), sai); 1478 IRQF_SHARED, dev_name(&pdev->dev), sai);
@@ -1506,7 +1482,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
1506 } 1482 }
1507 1483
1508 ret = devm_snd_soc_register_component(&pdev->dev, &stm32_component, 1484 ret = devm_snd_soc_register_component(&pdev->dev, &stm32_component,
1509 sai->cpu_dai_drv, 1); 1485 &sai->cpu_dai_drv, 1);
1510 if (ret) 1486 if (ret)
1511 return ret; 1487 return ret;
1512 1488
@@ -1522,10 +1498,34 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
1522 return 0; 1498 return 0;
1523} 1499}
1524 1500
1501#ifdef CONFIG_PM_SLEEP
1502static int stm32_sai_sub_suspend(struct device *dev)
1503{
1504 struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
1505
1506 regcache_cache_only(sai->regmap, true);
1507 regcache_mark_dirty(sai->regmap);
1508 return 0;
1509}
1510
1511static int stm32_sai_sub_resume(struct device *dev)
1512{
1513 struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
1514
1515 regcache_cache_only(sai->regmap, false);
1516 return regcache_sync(sai->regmap);
1517}
1518#endif /* CONFIG_PM_SLEEP */
1519
1520static const struct dev_pm_ops stm32_sai_sub_pm_ops = {
1521 SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume)
1522};
1523
1525static struct platform_driver stm32_sai_sub_driver = { 1524static struct platform_driver stm32_sai_sub_driver = {
1526 .driver = { 1525 .driver = {
1527 .name = "st,stm32-sai-sub", 1526 .name = "st,stm32-sai-sub",
1528 .of_match_table = stm32_sai_sub_ids, 1527 .of_match_table = stm32_sai_sub_ids,
1528 .pm = &stm32_sai_sub_pm_ops,
1529 }, 1529 },
1530 .probe = stm32_sai_sub_probe, 1530 .probe = stm32_sai_sub_probe,
1531}; 1531};
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 373df4f24be1..3d64200edbb5 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -21,6 +21,7 @@
21#include <linux/delay.h> 21#include <linux/delay.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/of_platform.h> 23#include <linux/of_platform.h>
24#include <linux/pinctrl/consumer.h>
24#include <linux/regmap.h> 25#include <linux/regmap.h>
25#include <linux/reset.h> 26#include <linux/reset.h>
26 27
@@ -471,6 +472,8 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx)
471 memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); 472 memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB);
472 memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); 473 memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB);
473 474
475 pinctrl_pm_select_default_state(&spdifrx->pdev->dev);
476
474 ret = stm32_spdifrx_dma_ctrl_start(spdifrx); 477 ret = stm32_spdifrx_dma_ctrl_start(spdifrx);
475 if (ret < 0) 478 if (ret < 0)
476 return ret; 479 return ret;
@@ -493,7 +496,7 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx)
493 if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, 496 if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion,
494 msecs_to_jiffies(100)) 497 msecs_to_jiffies(100))
495 <= 0) { 498 <= 0) {
496 dev_err(&spdifrx->pdev->dev, "Failed to get control data\n"); 499 dev_dbg(&spdifrx->pdev->dev, "Failed to get control data\n");
497 ret = -EAGAIN; 500 ret = -EAGAIN;
498 } 501 }
499 502
@@ -502,6 +505,7 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx)
502 505
503end: 506end:
504 clk_disable_unprepare(spdifrx->kclk); 507 clk_disable_unprepare(spdifrx->kclk);
508 pinctrl_pm_select_sleep_state(&spdifrx->pdev->dev);
505 509
506 return ret; 510 return ret;
507} 511}
@@ -611,10 +615,15 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg)
611 615
612static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) 616static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg)
613{ 617{
614 if (reg == STM32_SPDIFRX_DR) 618 switch (reg) {
619 case STM32_SPDIFRX_DR:
620 case STM32_SPDIFRX_CSR:
621 case STM32_SPDIFRX_SR:
622 case STM32_SPDIFRX_DIR:
615 return true; 623 return true;
616 624 default:
617 return false; 625 return false;
626 }
618} 627}
619 628
620static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) 629static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg)
@@ -638,6 +647,7 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = {
638 .volatile_reg = stm32_spdifrx_volatile_reg, 647 .volatile_reg = stm32_spdifrx_volatile_reg,
639 .writeable_reg = stm32_spdifrx_writeable_reg, 648 .writeable_reg = stm32_spdifrx_writeable_reg,
640 .fast_io = true, 649 .fast_io = true,
650 .cache_type = REGCACHE_FLAT,
641}; 651};
642 652
643static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) 653static irqreturn_t stm32_spdifrx_isr(int irq, void *devid)
@@ -835,7 +845,8 @@ static struct snd_soc_dai_driver stm32_spdifrx_dai[] = {
835static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { 845static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = {
836 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, 846 .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
837 .buffer_bytes_max = 8 * PAGE_SIZE, 847 .buffer_bytes_max = 8 * PAGE_SIZE,
838 .period_bytes_max = 2048, /* MDMA constraint */ 848 .period_bytes_min = 1024,
849 .period_bytes_max = 4 * PAGE_SIZE,
839 .periods_min = 2, 850 .periods_min = 2,
840 .periods_max = 8, 851 .periods_max = 8,
841}; 852};
@@ -983,10 +994,36 @@ static int stm32_spdifrx_remove(struct platform_device *pdev)
983 994
984MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); 995MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids);
985 996
997#ifdef CONFIG_PM_SLEEP
998static int stm32_spdifrx_suspend(struct device *dev)
999{
1000 struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev);
1001
1002 regcache_cache_only(spdifrx->regmap, true);
1003 regcache_mark_dirty(spdifrx->regmap);
1004
1005 return 0;
1006}
1007
1008static int stm32_spdifrx_resume(struct device *dev)
1009{
1010 struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev);
1011
1012 regcache_cache_only(spdifrx->regmap, false);
1013
1014 return regcache_sync(spdifrx->regmap);
1015}
1016#endif /* CONFIG_PM_SLEEP */
1017
1018static const struct dev_pm_ops stm32_spdifrx_pm_ops = {
1019 SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume)
1020};
1021
986static struct platform_driver stm32_spdifrx_driver = { 1022static struct platform_driver stm32_spdifrx_driver = {
987 .driver = { 1023 .driver = {
988 .name = "st,stm32-spdifrx", 1024 .name = "st,stm32-spdifrx",
989 .of_match_table = stm32_spdifrx_ids, 1025 .of_match_table = stm32_spdifrx_ids,
1026 .pm = &stm32_spdifrx_pm_ops,
990 }, 1027 },
991 .probe = stm32_spdifrx_probe, 1028 .probe = stm32_spdifrx_probe,
992 .remove = stm32_spdifrx_remove, 1029 .remove = stm32_spdifrx_remove,
diff --git a/sound/soc/ti/Kconfig b/sound/soc/ti/Kconfig
index 4bf3c15d4e51..ee7c202c69b7 100644
--- a/sound/soc/ti/Kconfig
+++ b/sound/soc/ti/Kconfig
@@ -21,8 +21,8 @@ config SND_SOC_DAVINCI_ASP
21 21
22config SND_SOC_DAVINCI_MCASP 22config SND_SOC_DAVINCI_MCASP
23 tristate "Multichannel Audio Serial Port (McASP) support" 23 tristate "Multichannel Audio Serial Port (McASP) support"
24 select SND_SOC_TI_EDMA_PCM if TI_EDMA 24 select SND_SOC_TI_EDMA_PCM
25 select SND_SOC_TI_SDMA_PCM if DMA_OMAP 25 select SND_SOC_TI_SDMA_PCM
26 help 26 help
27 Say Y or M here if you want to have support for McASP IP found in 27 Say Y or M here if you want to have support for McASP IP found in
28 various Texas Instruments SoCs like: 28 various Texas Instruments SoCs like:
diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c
index 4dce494dfbd3..b9611db14c86 100644
--- a/sound/soc/ti/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
@@ -200,7 +200,7 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
200 return 0; 200 return 0;
201} 201}
202 202
203static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum, 203static SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum,
204 ams_delta_audio_mode); 204 ams_delta_audio_mode);
205 205
206static const struct snd_kcontrol_new ams_delta_audio_controls[] = { 206static const struct snd_kcontrol_new ams_delta_audio_controls[] = {
diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c
index a3a67a8f0f54..9fbc759fdefe 100644
--- a/sound/soc/ti/davinci-mcasp.c
+++ b/sound/soc/ti/davinci-mcasp.c
@@ -45,6 +45,7 @@
45 45
46#define MCASP_MAX_AFIFO_DEPTH 64 46#define MCASP_MAX_AFIFO_DEPTH 64
47 47
48#ifdef CONFIG_PM
48static u32 context_regs[] = { 49static u32 context_regs[] = {
49 DAVINCI_MCASP_TXFMCTL_REG, 50 DAVINCI_MCASP_TXFMCTL_REG,
50 DAVINCI_MCASP_RXFMCTL_REG, 51 DAVINCI_MCASP_RXFMCTL_REG,
@@ -68,6 +69,7 @@ struct davinci_mcasp_context {
68 u32 *xrsr_regs; /* for serializer configuration */ 69 u32 *xrsr_regs; /* for serializer configuration */
69 bool pm_state; 70 bool pm_state;
70}; 71};
72#endif
71 73
72struct davinci_mcasp_ruledata { 74struct davinci_mcasp_ruledata {
73 struct davinci_mcasp *mcasp; 75 struct davinci_mcasp *mcasp;
diff --git a/sound/soc/ti/edma-pcm.c b/sound/soc/ti/edma-pcm.c
index 59e588abe54b..fdffb801b185 100644
--- a/sound/soc/ti/edma-pcm.c
+++ b/sound/soc/ti/edma-pcm.c
@@ -23,7 +23,6 @@
23#include <sound/pcm_params.h> 23#include <sound/pcm_params.h>
24#include <sound/soc.h> 24#include <sound/soc.h>
25#include <sound/dmaengine_pcm.h> 25#include <sound/dmaengine_pcm.h>
26#include <linux/edma.h>
27 26
28#include "edma-pcm.h" 27#include "edma-pcm.h"
29 28
@@ -43,14 +42,12 @@ static const struct snd_pcm_hardware edma_pcm_hardware = {
43static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = { 42static const struct snd_dmaengine_pcm_config edma_dmaengine_pcm_config = {
44 .pcm_hardware = &edma_pcm_hardware, 43 .pcm_hardware = &edma_pcm_hardware,
45 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 44 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
46 .compat_filter_fn = edma_filter_fn,
47 .prealloc_buffer_size = 128 * 1024, 45 .prealloc_buffer_size = 128 * 1024,
48}; 46};
49 47
50int edma_pcm_platform_register(struct device *dev) 48int edma_pcm_platform_register(struct device *dev)
51{ 49{
52 return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config, 50 return devm_snd_dmaengine_pcm_register(dev, &edma_dmaengine_pcm_config, 0);
53 SND_DMAENGINE_PCM_FLAG_COMPAT);
54} 51}
55EXPORT_SYMBOL_GPL(edma_pcm_platform_register); 52EXPORT_SYMBOL_GPL(edma_pcm_platform_register);
56 53
diff --git a/sound/soc/ti/sdma-pcm.c b/sound/soc/ti/sdma-pcm.c
index 21a9c2499d48..a236350beb10 100644
--- a/sound/soc/ti/sdma-pcm.c
+++ b/sound/soc/ti/sdma-pcm.c
@@ -11,7 +11,6 @@
11#include <sound/pcm_params.h> 11#include <sound/pcm_params.h>
12#include <sound/soc.h> 12#include <sound/soc.h>
13#include <sound/dmaengine_pcm.h> 13#include <sound/dmaengine_pcm.h>
14#include <linux/omap-dmaengine.h>
15 14
16#include "sdma-pcm.h" 15#include "sdma-pcm.h"
17 16
@@ -31,7 +30,6 @@ static const struct snd_pcm_hardware sdma_pcm_hardware = {
31static const struct snd_dmaengine_pcm_config sdma_dmaengine_pcm_config = { 30static const struct snd_dmaengine_pcm_config sdma_dmaengine_pcm_config = {
32 .pcm_hardware = &sdma_pcm_hardware, 31 .pcm_hardware = &sdma_pcm_hardware,
33 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 32 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
34 .compat_filter_fn = omap_dma_filter_fn,
35 .prealloc_buffer_size = 128 * 1024, 33 .prealloc_buffer_size = 128 * 1024,
36}; 34};
37 35
@@ -39,13 +37,12 @@ int sdma_pcm_platform_register(struct device *dev,
39 char *txdmachan, char *rxdmachan) 37 char *txdmachan, char *rxdmachan)
40{ 38{
41 struct snd_dmaengine_pcm_config *config; 39 struct snd_dmaengine_pcm_config *config;
42 unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; 40 unsigned int flags = 0;
43 41
44 /* Standard names for the directions: 'tx' and 'rx' */ 42 /* Standard names for the directions: 'tx' and 'rx' */
45 if (!txdmachan && !rxdmachan) 43 if (!txdmachan && !rxdmachan)
46 return devm_snd_dmaengine_pcm_register(dev, 44 return devm_snd_dmaengine_pcm_register(dev,
47 &sdma_dmaengine_pcm_config, 45 &sdma_dmaengine_pcm_config, 0);
48 flags);
49 46
50 config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL); 47 config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
51 if (!config) 48 if (!config)
@@ -65,7 +62,7 @@ int sdma_pcm_platform_register(struct device *dev,
65 config->chan_names[0] = txdmachan; 62 config->chan_names[0] = txdmachan;
66 config->chan_names[1] = rxdmachan; 63 config->chan_names[1] = rxdmachan;
67 64
68 return devm_snd_dmaengine_pcm_register(dev, config, flags); 65 return devm_snd_dmaengine_pcm_register(dev, config, 0);
69} 66}
70EXPORT_SYMBOL_GPL(sdma_pcm_platform_register); 67EXPORT_SYMBOL_GPL(sdma_pcm_platform_register);
71 68
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index d9fcae071b47..fae48d108b97 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -39,6 +39,11 @@ snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg)
39 if (copy_from_user(&patch, arg, sizeof(patch))) 39 if (copy_from_user(&patch, arg, sizeof(patch)))
40 return -EFAULT; 40 return -EFAULT;
41 41
42 if (patch.key == GUS_PATCH)
43 return snd_soundfont_load_guspatch(emu->sflist, arg,
44 patch.len + sizeof(patch),
45 TMP_CLIENT_ID);
46
42 if (patch.type >= SNDRV_SFNT_LOAD_INFO && 47 if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
43 patch.type <= SNDRV_SFNT_PROBE_DATA) { 48 patch.type <= SNDRV_SFNT_PROBE_DATA) {
44 err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID); 49 err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID);
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 31a4ea94830e..9b5d70104489 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -856,6 +856,8 @@ calc_gus_envelope_time(int rate, int start, int end)
856 int r, p, t; 856 int r, p, t;
857 r = (3 - ((rate >> 6) & 3)) * 3; 857 r = (3 - ((rate >> 6) & 3)) * 3;
858 p = rate & 0x3f; 858 p = rate & 0x3f;
859 if (!p)
860 p = 1;
859 t = end - start; 861 t = end - start;
860 if (t < 0) t = -t; 862 if (t < 0) t = -t;
861 if (13 > r) 863 if (13 > r)
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index ecbe5f3beda5..e28368d8eba2 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -54,8 +54,8 @@ struct usb_line6_toneport {
54 /* Firmware version (x 100) */ 54 /* Firmware version (x 100) */
55 u8 firmware_version; 55 u8 firmware_version;
56 56
57 /* Timer for delayed PCM startup */ 57 /* Work for delayed PCM startup */
58 struct timer_list timer; 58 struct delayed_work pcm_work;
59 59
60 /* Device type */ 60 /* Device type */
61 enum line6_device_type type; 61 enum line6_device_type type;
@@ -241,9 +241,10 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
241 return 1; 241 return 1;
242} 242}
243 243
244static void toneport_start_pcm(struct timer_list *t) 244static void toneport_start_pcm(struct work_struct *work)
245{ 245{
246 struct usb_line6_toneport *toneport = from_timer(toneport, t, timer); 246 struct usb_line6_toneport *toneport =
247 container_of(work, struct usb_line6_toneport, pcm_work.work);
247 struct usb_line6 *line6 = &toneport->line6; 248 struct usb_line6 *line6 = &toneport->line6;
248 249
249 line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true); 250 line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);
@@ -393,7 +394,8 @@ static int toneport_setup(struct usb_line6_toneport *toneport)
393 if (toneport_has_led(toneport)) 394 if (toneport_has_led(toneport))
394 toneport_update_led(toneport); 395 toneport_update_led(toneport);
395 396
396 mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); 397 schedule_delayed_work(&toneport->pcm_work,
398 msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));
397 return 0; 399 return 0;
398} 400}
399 401
@@ -405,7 +407,7 @@ static void line6_toneport_disconnect(struct usb_line6 *line6)
405 struct usb_line6_toneport *toneport = 407 struct usb_line6_toneport *toneport =
406 (struct usb_line6_toneport *)line6; 408 (struct usb_line6_toneport *)line6;
407 409
408 del_timer_sync(&toneport->timer); 410 cancel_delayed_work_sync(&toneport->pcm_work);
409 411
410 if (toneport_has_led(toneport)) 412 if (toneport_has_led(toneport))
411 toneport_remove_leds(toneport); 413 toneport_remove_leds(toneport);
@@ -422,7 +424,7 @@ static int toneport_init(struct usb_line6 *line6,
422 struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; 424 struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
423 425
424 toneport->type = id->driver_info; 426 toneport->type = id->driver_info;
425 timer_setup(&toneport->timer, toneport_start_pcm, 0); 427 INIT_DELAYED_WORK(&toneport->pcm_work, toneport_start_pcm);
426 428
427 line6->disconnect = line6_toneport_disconnect; 429 line6->disconnect = line6_toneport_disconnect;
428 430
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 73d7dff425c1..e003b5e7b01a 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -2675,6 +2675,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
2675 kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); 2675 kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
2676 if (! kctl) { 2676 if (! kctl) {
2677 usb_audio_err(state->chip, "cannot malloc kcontrol\n"); 2677 usb_audio_err(state->chip, "cannot malloc kcontrol\n");
2678 for (i = 0; i < desc->bNrInPins; i++)
2679 kfree(namelist[i]);
2678 kfree(namelist); 2680 kfree(namelist);
2679 kfree(cval); 2681 kfree(cval);
2680 return -ENOMEM; 2682 return -ENOMEM;
@@ -3490,7 +3492,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
3490 if (err < 0) 3492 if (err < 0)
3491 goto _error; 3493 goto _error;
3492 3494
3493 snd_usb_mixer_apply_create_quirk(mixer); 3495 err = snd_usb_mixer_apply_create_quirk(mixer);
3496 if (err < 0)
3497 goto _error;
3494 3498
3495 err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops); 3499 err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops);
3496 if (err < 0) 3500 if (err < 0)
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 8cbca137ee6f..5600143ff660 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2770,6 +2770,90 @@ YAMAHA_DEVICE(0x7010, "UB99"),
2770 .type = QUIRK_MIDI_NOVATION 2770 .type = QUIRK_MIDI_NOVATION
2771 } 2771 }
2772}, 2772},
2773{
2774 /*
2775 * Focusrite Scarlett Solo 2nd generation
2776 * Reports that playback should use Synch: Synchronous
2777 * while still providing a feedback endpoint. Synchronous causes
2778 * snapping on some sample rates.
2779 * Force it to use Synch: Asynchronous.
2780 */
2781 USB_DEVICE(0x1235, 0x8205),
2782 .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
2783 .ifnum = QUIRK_ANY_INTERFACE,
2784 .type = QUIRK_COMPOSITE,
2785 .data = (const struct snd_usb_audio_quirk[]) {
2786 {
2787 .ifnum = 1,
2788 .type = QUIRK_AUDIO_FIXED_ENDPOINT,
2789 .data = & (const struct audioformat) {
2790 .formats = SNDRV_PCM_FMTBIT_S32_LE,
2791 .channels = 2,
2792 .iface = 1,
2793 .altsetting = 1,
2794 .altset_idx = 1,
2795 .attributes = 0,
2796 .endpoint = 0x01,
2797 .ep_attr = USB_ENDPOINT_XFER_ISOC |
2798 USB_ENDPOINT_SYNC_ASYNC,
2799 .protocol = UAC_VERSION_2,
2800 .rates = SNDRV_PCM_RATE_44100 |
2801 SNDRV_PCM_RATE_48000 |
2802 SNDRV_PCM_RATE_88200 |
2803 SNDRV_PCM_RATE_96000 |
2804 SNDRV_PCM_RATE_176400 |
2805 SNDRV_PCM_RATE_192000,
2806 .rate_min = 44100,
2807 .rate_max = 192000,
2808 .nr_rates = 6,
2809 .rate_table = (unsigned int[]) {
2810 44100, 48000, 88200,
2811 96000, 176400, 192000
2812 },
2813 .clock = 41
2814 }
2815 },
2816 {
2817 .ifnum = 2,
2818 .type = QUIRK_AUDIO_FIXED_ENDPOINT,
2819 .data = & (const struct audioformat) {
2820 .formats = SNDRV_PCM_FMTBIT_S32_LE,
2821 .channels = 2,
2822 .iface = 2,
2823 .altsetting = 1,
2824 .altset_idx = 1,
2825 .attributes = 0,
2826 .endpoint = 0x82,
2827 .ep_attr = USB_ENDPOINT_XFER_ISOC |
2828 USB_ENDPOINT_SYNC_ASYNC |
2829 USB_ENDPOINT_USAGE_IMPLICIT_FB,
2830 .protocol = UAC_VERSION_2,
2831 .rates = SNDRV_PCM_RATE_44100 |
2832 SNDRV_PCM_RATE_48000 |
2833 SNDRV_PCM_RATE_88200 |
2834 SNDRV_PCM_RATE_96000 |
2835 SNDRV_PCM_RATE_176400 |
2836 SNDRV_PCM_RATE_192000,
2837 .rate_min = 44100,
2838 .rate_max = 192000,
2839 .nr_rates = 6,
2840 .rate_table = (unsigned int[]) {
2841 44100, 48000, 88200,
2842 96000, 176400, 192000
2843 },
2844 .clock = 41
2845 }
2846 },
2847 {
2848 .ifnum = 3,
2849 .type = QUIRK_IGNORE_INTERFACE
2850 },
2851 {
2852 .ifnum = -1
2853 }
2854 }
2855 }
2856},
2773 2857
2774/* Access Music devices */ 2858/* Access Music devices */
2775{ 2859{
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index c1dd9a7b48df..bfe1108416cf 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -75,7 +75,8 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v
75 75
76 if (!us428->us428ctls_sharedmem) { 76 if (!us428->us428ctls_sharedmem) {
77 init_waitqueue_head(&us428->us428ctls_wait_queue_head); 77 init_waitqueue_head(&us428->us428ctls_wait_queue_head);
78 if(!(us428->us428ctls_sharedmem = snd_malloc_pages(sizeof(struct us428ctls_sharedmem), GFP_KERNEL))) 78 us428->us428ctls_sharedmem = alloc_pages_exact(sizeof(struct us428ctls_sharedmem), GFP_KERNEL);
79 if (!us428->us428ctls_sharedmem)
79 return -ENOMEM; 80 return -ENOMEM;
80 memset(us428->us428ctls_sharedmem, -1, sizeof(struct us428ctls_sharedmem)); 81 memset(us428->us428ctls_sharedmem, -1, sizeof(struct us428ctls_sharedmem));
81 us428->us428ctls_sharedmem->CtlSnapShotLast = -2; 82 us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c
index 221adf68bd0c..51d73111263a 100644
--- a/sound/usb/usx2y/usb_stream.c
+++ b/sound/usb/usx2y/usb_stream.c
@@ -155,9 +155,9 @@ void usb_stream_free(struct usb_stream_kernel *sk)
155 if (!s) 155 if (!s)
156 return; 156 return;
157 157
158 free_pages((unsigned long)sk->write_page, get_order(s->write_size)); 158 free_pages_exact(sk->write_page, s->write_size);
159 sk->write_page = NULL; 159 sk->write_page = NULL;
160 free_pages((unsigned long)s, get_order(s->read_size)); 160 free_pages_exact(s, s->read_size);
161 sk->s = NULL; 161 sk->s = NULL;
162} 162}
163 163
@@ -172,7 +172,6 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
172 int read_size = sizeof(struct usb_stream); 172 int read_size = sizeof(struct usb_stream);
173 int write_size; 173 int write_size;
174 int usb_frames = dev->speed == USB_SPEED_HIGH ? 8000 : 1000; 174 int usb_frames = dev->speed == USB_SPEED_HIGH ? 8000 : 1000;
175 int pg;
176 175
177 in_pipe = usb_rcvisocpipe(dev, in_endpoint); 176 in_pipe = usb_rcvisocpipe(dev, in_endpoint);
178 out_pipe = usb_sndisocpipe(dev, out_endpoint); 177 out_pipe = usb_sndisocpipe(dev, out_endpoint);
@@ -202,11 +201,10 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
202 goto out; 201 goto out;
203 } 202 }
204 203
205 pg = get_order(read_size); 204 sk->s = alloc_pages_exact(read_size,
206 sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO| 205 GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
207 __GFP_NOWARN, pg);
208 if (!sk->s) { 206 if (!sk->s) {
209 snd_printk(KERN_WARNING "couldn't __get_free_pages()\n"); 207 pr_warn("us122l: couldn't allocate read buffer\n");
210 goto out; 208 goto out;
211 } 209 }
212 sk->s->cfg.version = USB_STREAM_INTERFACE_VERSION; 210 sk->s->cfg.version = USB_STREAM_INTERFACE_VERSION;
@@ -221,13 +219,11 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
221 sk->s->period_size = frame_size * period_frames; 219 sk->s->period_size = frame_size * period_frames;
222 220
223 sk->s->write_size = write_size; 221 sk->s->write_size = write_size;
224 pg = get_order(write_size);
225 222
226 sk->write_page = 223 sk->write_page = alloc_pages_exact(write_size,
227 (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO| 224 GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
228 __GFP_NOWARN, pg);
229 if (!sk->write_page) { 225 if (!sk->write_page) {
230 snd_printk(KERN_WARNING "couldn't __get_free_pages()\n"); 226 pr_warn("us122l: couldn't allocate write buffer\n");
231 usb_stream_free(sk); 227 usb_stream_free(sk);
232 return NULL; 228 return NULL;
233 } 229 }
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index da4a5a541512..e8687b3bd3c8 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -293,10 +293,8 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y)
293 if (! (usX2Y->In04urb = usb_alloc_urb(0, GFP_KERNEL))) 293 if (! (usX2Y->In04urb = usb_alloc_urb(0, GFP_KERNEL)))
294 return -ENOMEM; 294 return -ENOMEM;
295 295
296 if (! (usX2Y->In04Buf = kmalloc(21, GFP_KERNEL))) { 296 if (! (usX2Y->In04Buf = kmalloc(21, GFP_KERNEL)))
297 usb_free_urb(usX2Y->In04urb);
298 return -ENOMEM; 297 return -ENOMEM;
299 }
300 298
301 init_waitqueue_head(&usX2Y->In04WaitQueue); 299 init_waitqueue_head(&usX2Y->In04WaitQueue);
302 usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), 300 usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4),
@@ -437,7 +435,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card)
437 kfree(usX2Y(card)->In04Buf); 435 kfree(usX2Y(card)->In04Buf);
438 usb_free_urb(usX2Y(card)->In04urb); 436 usb_free_urb(usX2Y(card)->In04urb);
439 if (usX2Y(card)->us428ctls_sharedmem) 437 if (usX2Y(card)->us428ctls_sharedmem)
440 snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem)); 438 free_pages_exact(usX2Y(card)->us428ctls_sharedmem,
439 sizeof(*usX2Y(card)->us428ctls_sharedmem));
441 if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) 440 if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS)
442 snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; 441 snd_usX2Y_card_used[usX2Y(card)->card_index] = 0;
443} 442}
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 714cf50d4a4c..ace8185c3f6d 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -488,7 +488,9 @@ static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
488 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream); 488 snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
489 489
490 if (NULL == usX2Y->hwdep_pcm_shm) { 490 if (NULL == usX2Y->hwdep_pcm_shm) {
491 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL))) 491 usX2Y->hwdep_pcm_shm = alloc_pages_exact(sizeof(struct snd_usX2Y_hwdep_pcm_shm),
492 GFP_KERNEL);
493 if (!usX2Y->hwdep_pcm_shm)
492 return -ENOMEM; 494 return -ENOMEM;
493 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 495 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
494 } 496 }
@@ -700,7 +702,7 @@ static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
700{ 702{
701 struct usX2Ydev *usX2Y = hwdep->private_data; 703 struct usX2Ydev *usX2Y = hwdep->private_data;
702 if (NULL != usX2Y->hwdep_pcm_shm) 704 if (NULL != usX2Y->hwdep_pcm_shm)
703 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 705 free_pages_exact(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
704} 706}
705 707
706 708