Merge tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Aug 2022 17:19:51 +0000 (10:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Aug 2022 17:19:51 +0000 (10:19 -0700)
Pull sound updates from Takashi Iwai:
 "As the diffstat shows, we've had lots of developments in a wide range
  at this time; the majority of changes are about ASoC, including
  subsystem-wide cleanups, continued SOF / Intel updates and a bunch of
  new drivers (as usual), while there have been some significant (but
  almost invisible) improvements in ALSA core side, too.

  Below are some highlights:

  Core:

   - Faster lookups of control elements with Xarray; normal user won't
     notice, but on the devices with tons of control elements, it can be
     visibly faster

   - Support for input validation for controls; this will harden for
     badly written drivers in general with a slight overhead

   - Deferred async signal handling for working around the potential
     deadlocks

   - Cleanup / refactoring raw MIDI locking code

  ASoC:

   - Restructing of the set_fmt() callbacks for making things clearer in
     situations like CODEC to CODEC links

   - Clean up and modernizing the DAI naming scheme setups

   - Merge of more of the Intel AVS driver stack, including some board
     integrations

   - New version 4 mechanism for communication with SOF DSPs

   - Suppoort for dynamically selecting the PLL to use at runtime on
     i.MX platforms

   - Improvements for CODEC to CODEC support in the generic cards

   - Support for AMD Jadeite and various machines, AMD RPL, Intel
     MetorLake DSPs, Mediatek MT8186 DSPs and MT6366, nVidia Tegra
     MDDRC, OPE and PEQ, NXP TFA9890, Qualcomm SDM845, WCD9335 and
     WAS883x, and Texas Instruments TAS2780

  HD- and USB-audio:

   - Continued improvement for CS35L41 (sub)codec support

   - More quirks for various devices (HP, Lenovo, Dell, Clevo)"

* tag 'sound-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (778 commits)
  ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxx
  ALSA: line6: Replace sprintf() with sysfs_emit()
  ALSA: hda: Replace sprintf() with sysfs_emit()
  ALSA: pcm: Replace sprintf() with sysfs_emit()
  ALSA: core: Replace scnprintf() with sysfs_emit()
  ALSA: control-led: Replace sprintf() with sysfs_emit()
  ALSA: aoa: Replace sprintf() with sysfs_emit()
  ALSA: ac97: Replace sprintf() with sysfs_emit()
  ALSA: hda/realtek: Add quirk for Clevo NV45PZ
  ALSA: hda/realtek: Add quirk for Lenovo Yoga9 14IAP7
  ALSA: control: Use deferred fasync helper
  ALSA: pcm: Use deferred fasync helper
  ALSA: timer: Use deferred fasync helper
  ALSA: core: Add async signal helpers
  ASoC: q6asm: use kcalloc() instead of kzalloc()
  ACPI: scan: Add CLSA0101 Laptop Support
  ALSA: hda: cs35l41: Support CLSA0101
  ALSA: hda: cs35l41: Use the CS35L41 HDA internal define
  ASoC: dt-bindings: use spi-peripheral-props.yaml
  ASoC: codecs: va-macro: use fsgen as clock
  ...

797 files changed:
Documentation/devicetree/bindings/dsp/mediatek,mt8186-dsp.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/dsp/mediatek,mt8195-dsp.yaml
Documentation/devicetree/bindings/sound/adi,adau1977.yaml
Documentation/devicetree/bindings/sound/adi,max98396.yaml
Documentation/devicetree/bindings/sound/allwinner,sun50i-a64-codec-analog.yaml
Documentation/devicetree/bindings/sound/atmel,sama5d2-classd.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel,sama5d2-i2s.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel,sama5d2-pdmic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel-classd.txt [deleted file]
Documentation/devicetree/bindings/sound/atmel-i2s.txt [deleted file]
Documentation/devicetree/bindings/sound/atmel-pdmic.txt [deleted file]
Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
Documentation/devicetree/bindings/sound/designware-i2s.txt [deleted file]
Documentation/devicetree/bindings/sound/fsl,micfil.txt [deleted file]
Documentation/devicetree/bindings/sound/fsl,micfil.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,mqs.txt
Documentation/devicetree/bindings/sound/fsl,spdif.yaml
Documentation/devicetree/bindings/sound/fsl-sai.txt
Documentation/devicetree/bindings/sound/mt6358.txt
Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nau8821.txt
Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml
Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
Documentation/devicetree/bindings/sound/qcom,sdm845.txt [deleted file]
Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml
Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rockchip-i2s.yaml
Documentation/devicetree/bindings/sound/sgtl5000.yaml
Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
Documentation/process/kernel-docs.rst
Documentation/sound/soc/codec.rst
Documentation/sound/soc/platform.rst
MAINTAINERS
drivers/acpi/scan.c
drivers/acpi/utils.c
drivers/firmware/cirrus/cs_dsp.c
drivers/firmware/mtk-adsp-ipc.c
drivers/gpu/drm/bridge/sii902x.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/media/i2c/tda1997x.c
drivers/soundwire/intel.c
include/dt-bindings/sound/qcom,wcd9335.h [new file with mode: 0644]
include/linux/acpi.h
include/linux/firmware/cirrus/cs_dsp.h
include/linux/soundwire/sdw_intel.h
include/sound/control.h
include/sound/core.h
include/sound/cs35l41.h
include/sound/dmaengine_pcm.h
include/sound/hda_codec.h
include/sound/hdaudio.h
include/sound/hdmi-codec.h
include/sound/madera-pdata.h
include/sound/pcm.h
include/sound/rawmidi.h
include/sound/simple_card_utils.h
include/sound/soc-acpi-intel-match.h
include/sound/soc-card.h
include/sound/soc-component.h
include/sound/soc-dai.h
include/sound/soc.h
include/sound/sof.h
include/sound/sof/dai-amd.h
include/sound/sof/dai-intel.h
include/sound/sof/dai.h
include/sound/sof/ipc4/header.h
include/sound/sof/stream.h
include/uapi/sound/compress_offload.h
include/uapi/sound/compress_params.h
include/uapi/sound/sof/abi.h
include/uapi/sound/sof/header.h
include/uapi/sound/sof/tokens.h
sound/ac97/bus.c
sound/aoa/soundbus/sysfs.c
sound/core/Kconfig
sound/core/compress_offload.c
sound/core/control.c
sound/core/control_led.c
sound/core/device.c
sound/core/info.c
sound/core/init.c
sound/core/isadma.c
sound/core/memalloc.c
sound/core/misc.c
sound/core/pcm.c
sound/core/pcm_dmaengine.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/timer.c
sound/core/vmaster.c
sound/hda/ext/hdac_ext_controller.c
sound/hda/hdac_bus.c
sound/hda/hdac_controller.c
sound/hda/hdac_sysfs.c
sound/hda/intel-dsp-config.c
sound/hda/trace.h
sound/isa/wavefront/wavefront_synth.c
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/emu10k1/memory.c
sound/pci/ens1370.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/cs35l41_hda.c
sound/pci/hda/cs35l41_hda.h
sound/pci/hda/cs35l41_hda_i2c.c
sound/pci/hda/cs35l41_hda_spi.c
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_component.h
sound/pci/hda/hda_cs_dsp_ctl.c [new file with mode: 0644]
sound/pci/hda/hda_cs_dsp_ctl.h [new file with mode: 0644]
sound/pci/hda/hda_sysfs.c
sound/pci/hda/patch_cs8409-tables.c
sound/pci/hda/patch_cs8409.h
sound/pci/hda/patch_realtek.c
sound/soc/Makefile
sound/soc/adi/axi-i2s.c
sound/soc/adi/axi-spdif.c
sound/soc/amd/Kconfig
sound/soc/amd/Makefile
sound/soc/amd/acp-config.c
sound/soc/amd/acp-es8336.c [new file with mode: 0644]
sound/soc/amd/acp-pcm-dma.c
sound/soc/amd/acp.h
sound/soc/amd/acp/Kconfig
sound/soc/amd/acp/Makefile
sound/soc/amd/acp/acp-i2s.c
sound/soc/amd/acp/acp-legacy-mach.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/amd/acp/acp-mach.h
sound/soc/amd/acp/acp-pci.c
sound/soc/amd/acp/acp-pdm.c
sound/soc/amd/acp/acp-platform.c
sound/soc/amd/acp/acp-rembrandt.c [new file with mode: 0644]
sound/soc/amd/acp/acp-renoir.c
sound/soc/amd/acp/acp-sof-mach.c
sound/soc/amd/acp/amd.h
sound/soc/amd/acp/chip_offset_byte.h
sound/soc/amd/mach-config.h
sound/soc/amd/raven/acp3x-i2s.c
sound/soc/amd/renoir/acp3x-pdm-dma.c
sound/soc/amd/rpl/Makefile [new file with mode: 0644]
sound/soc/amd/rpl/rpl-pci-acp6x.c [new file with mode: 0644]
sound/soc/amd/rpl/rpl_acp6x.h [new file with mode: 0644]
sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h [new file with mode: 0644]
sound/soc/amd/vangogh/acp5x-i2s.c
sound/soc/amd/vangogh/acp5x-mach.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/amd/yc/acp6x-pdm-dma.c
sound/soc/amd/yc/pci-acp6x.c
sound/soc/atmel/atmel-classd.c
sound/soc/atmel/atmel-i2s.c
sound/soc/atmel/atmel-pdmic.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/mchp-i2s-mcc.c
sound/soc/atmel/mchp-pdmc.c
sound/soc/atmel/mchp-spdifrx.c
sound/soc/atmel/mchp-spdiftx.c
sound/soc/atmel/mikroe-proto.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/i2sc.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/bcm/bcm2835-i2s.c
sound/soc/bcm/bcm63xx-i2s-whistler.c
sound/soc/bcm/cygnus-ssp.c
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ab8500-codec.h
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adau1761.c
sound/soc/codecs/adau1781.c
sound/soc/codecs/adau1977.c
sound/soc/codecs/adau7002.c
sound/soc/codecs/adau7118.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ads117x.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4118.c
sound/soc/codecs/ak4375.c
sound/soc/codecs/ak4458.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4554.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/ak5386.c
sound/soc/codecs/ak5558.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/bd28623.c
sound/soc/codecs/bt-sco.c
sound/soc/codecs/cpcap.c
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cros_ec_codec.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs35l33.c
sound/soc/codecs/cs35l34.c
sound/soc/codecs/cs35l35.c
sound/soc/codecs/cs35l36.c
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l41-spi.c
sound/soc/codecs/cs35l41.c
sound/soc/codecs/cs35l45-i2c.c
sound/soc/codecs/cs35l45.c
sound/soc/codecs/cs35l45.h
sound/soc/codecs/cs4234.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l42.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/cs43130.c
sound/soc/codecs/cs4341.c
sound/soc/codecs/cs4349.c
sound/soc/codecs/cs47l15.c
sound/soc/codecs/cs47l24.c
sound/soc/codecs/cs47l35.c
sound/soc/codecs/cs47l85.c
sound/soc/codecs/cs47l90.c
sound/soc/codecs/cs47l92.c
sound/soc/codecs/cs53l30.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/cx2072x.c
sound/soc/codecs/da7210.c
sound/soc/codecs/da7213.c
sound/soc/codecs/da7218.c
sound/soc/codecs/da7219.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/dmic.c
sound/soc/codecs/es7134.c
sound/soc/codecs/es7241.c
sound/soc/codecs/es8316.c
sound/soc/codecs/es8328.c
sound/soc/codecs/gtm601.c
sound/soc/codecs/hda-dai.c [new file with mode: 0644]
sound/soc/codecs/hda.c [new file with mode: 0644]
sound/soc/codecs/hda.h [new file with mode: 0644]
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/ics43432.c
sound/soc/codecs/inno_rk3036.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/lochnagar-sc.c
sound/soc/codecs/lpass-va-macro.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max98357a.c
sound/soc/codecs/max98371.c
sound/soc/codecs/max98373-i2c.c
sound/soc/codecs/max98373.c
sound/soc/codecs/max98390.c
sound/soc/codecs/max98396.c
sound/soc/codecs/max98396.h
sound/soc/codecs/max9850.c
sound/soc/codecs/max98520.c
sound/soc/codecs/max9860.c
sound/soc/codecs/max9867.c
sound/soc/codecs/max98925.c
sound/soc/codecs/max98926.c
sound/soc/codecs/max98927.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/ml26124.c
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/codecs/msm8916-wcd-digital.c
sound/soc/codecs/mt6358.c
sound/soc/codecs/mt6359-accdet.c
sound/soc/codecs/mt6359.c
sound/soc/codecs/nau8315.c
sound/soc/codecs/nau8540.c
sound/soc/codecs/nau8810.c
sound/soc/codecs/nau8821.c
sound/soc/codecs/nau8821.h
sound/soc/codecs/nau8822.c
sound/soc/codecs/nau8822.h
sound/soc/codecs/nau8824.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/pcm1681.c
sound/soc/codecs/pcm1789.c
sound/soc/codecs/pcm179x.c
sound/soc/codecs/pcm186x.c
sound/soc/codecs/pcm3008.c
sound/soc/codecs/pcm3168a.c
sound/soc/codecs/pcm5102a.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rk3328_codec.c
sound/soc/codecs/rk817_codec.c
sound/soc/codecs/rt1011.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/rt1015p.c
sound/soc/codecs/rt1016.c
sound/soc/codecs/rt1019.c
sound/soc/codecs/rt1305.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt1308.c
sound/soc/codecs/rt1316-sdw.c
sound/soc/codecs/rt274.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt286.h
sound/soc/codecs/rt298.c
sound/soc/codecs/rt298.h
sound/soc/codecs/rt5514.c
sound/soc/codecs/rt5616.c
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5659.c
sound/soc/codecs/rt5660.c
sound/soc/codecs/rt5663.c
sound/soc/codecs/rt5665.c
sound/soc/codecs/rt5668.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682s.c
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdca.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt715-sdca.c
sound/soc/codecs/rt715.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/si476x.c
sound/soc/codecs/spdif_receiver.c
sound/soc/codecs/spdif_transmitter.c
sound/soc/codecs/ssm2518.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm4567.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta350.c
sound/soc/codecs/sta529.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/sti-sas.c
sound/soc/codecs/tas2552.c
sound/soc/codecs/tas2562.c
sound/soc/codecs/tas2764.c
sound/soc/codecs/tas2770.c
sound/soc/codecs/tas2780.c [new file with mode: 0644]
sound/soc/codecs/tas2780.h [new file with mode: 0644]
sound/soc/codecs/tas5086.c
sound/soc/codecs/tas571x.c
sound/soc/codecs/tas5720.c
sound/soc/codecs/tas5805m.c
sound/soc/codecs/tas6424.c
sound/soc/codecs/tfa9879.c
sound/soc/codecs/tfa989x.c
sound/soc/codecs/tlv320adc3xxx.c
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tscs42xx.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda1334.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wcd-mbhc-v2.c
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm1250-ev1.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8524.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8727.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8782.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wsa881x.c
sound/soc/codecs/wsa883x.c [new file with mode: 0644]
sound/soc/codecs/zl38060.c
sound/soc/dwc/dwc-i2s.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_asrc_dma.c
sound/soc/fsl/fsl_aud2htx.c
sound/soc/fsl/fsl_audmix.c
sound/soc/fsl/fsl_easrc.c
sound/soc/fsl/fsl_easrc.h
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_micfil.h
sound/soc/fsl/fsl_mqs.c
sound/soc/fsl/fsl_rpmsg.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_utils.c
sound/soc/fsl/fsl_utils.h
sound/soc/fsl/fsl_xcvr.c
sound/soc/fsl/imx-audmix.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-card.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/generic/audio-graph-card.c
sound/soc/generic/audio-graph-card2-custom-sample.dtsi
sound/soc/generic/audio-graph-card2.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/test-component.c
sound/soc/hisilicon/hi6210-i2s.c
sound/soc/img/img-i2s-in.c
sound/soc/img/img-i2s-out.c
sound/soc/img/img-parallel-out.c
sound/soc/img/img-spdif-in.c
sound/soc/img/img-spdif-out.c
sound/soc/img/pistachio-internal-dac.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-atom-controls.c
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst_ipc.c
sound/soc/intel/avs/Makefile
sound/soc/intel/avs/boards/Kconfig [new file with mode: 0644]
sound/soc/intel/avs/boards/Makefile [new file with mode: 0644]
sound/soc/intel/avs/boards/da7219.c [new file with mode: 0644]
sound/soc/intel/avs/boards/dmic.c [new file with mode: 0644]
sound/soc/intel/avs/boards/hdaudio.c [new file with mode: 0644]
sound/soc/intel/avs/boards/i2s_test.c [new file with mode: 0644]
sound/soc/intel/avs/boards/max98357a.c [new file with mode: 0644]
sound/soc/intel/avs/boards/max98373.c [new file with mode: 0644]
sound/soc/intel/avs/boards/nau8825.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt274.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt286.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt298.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt5682.c [new file with mode: 0644]
sound/soc/intel/avs/boards/ssm4567.c [new file with mode: 0644]
sound/soc/intel/avs/cldma.c
sound/soc/intel/avs/core.c
sound/soc/intel/avs/dsp.c
sound/soc/intel/avs/ipc.c
sound/soc/intel/avs/loader.c
sound/soc/intel/avs/messages.c
sound/soc/intel/avs/path.c
sound/soc/intel/avs/pcm.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bdw-rt5650.c
sound/soc/intel/boards/bdw-rt5677.c
sound/soc/intel/boards/bdw_rt286.c [new file with mode: 0644]
sound/soc/intel/boards/broadwell.c [deleted file]
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bxt_rt298.c
sound/soc/intel/boards/bytcht_cx2072x.c
sound/soc/intel/boards/bytcht_da7213.c
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcht_nocodec.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5672.c
sound/soc/intel/boards/cml_rt1011_rt5682.c
sound/soc/intel/boards/glk_rt5682_max98357a.c
sound/soc/intel/boards/haswell.c [deleted file]
sound/soc/intel/boards/hda_dsp_common.c
sound/soc/intel/boards/hsw_rt5640.c [new file with mode: 0644]
sound/soc/intel/boards/kbl_da7219_max98357a.c
sound/soc/intel/boards/kbl_da7219_max98927.c
sound/soc/intel/boards/kbl_rt5663_max98927.c
sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
sound/soc/intel/boards/skl_hda_dsp_generic.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/boards/sof_cs42l42.c
sound/soc/intel/boards/sof_da7219_max98373.c
sound/soc/intel/boards/sof_es8336.c
sound/soc/intel/boards/sof_nau8825.c
sound/soc/intel/boards/sof_pcm512x.c
sound/soc/intel/boards/sof_realtek_common.c
sound/soc/intel/boards/sof_realtek_common.h
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/boards/sof_sdw_rt711.c
sound/soc/intel/boards/sof_sdw_rt711_sdca.c
sound/soc/intel/catpt/device.c
sound/soc/intel/catpt/pcm.c
sound/soc/intel/catpt/sysfs.c
sound/soc/intel/common/Makefile
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
sound/soc/intel/common/soc-acpi-intel-mtl-match.c [new file with mode: 0644]
sound/soc/intel/keembay/kmb_platform.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-topology.c
sound/soc/jz4740/Kconfig
sound/soc/jz4740/jz4740-i2s.c
sound/soc/mediatek/Kconfig
sound/soc/mediatek/Makefile
sound/soc/mediatek/common/Makefile
sound/soc/mediatek/common/mtk-dsp-sof-common.c [new file with mode: 0644]
sound/soc/mediatek/common/mtk-dsp-sof-common.h [new file with mode: 0644]
sound/soc/mediatek/common/mtk-soc-card.h [new file with mode: 0644]
sound/soc/mediatek/mt6797/mt6797-mt6351.c
sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
sound/soc/mediatek/mt8173/mt8173-rt5650.c
sound/soc/mediatek/mt8186/Makefile [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-clk.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-clk.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-common.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-control.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-gpio.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-gpio.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-afe-pcm.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-audsys-clk.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-audsys-clk.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-adda.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-hostless.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-i2s.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-pcm.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-src.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-dai-tdm.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-interconnection.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-misc-control.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-mt6366-common.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-mt6366-common.h [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c [new file with mode: 0644]
sound/soc/mediatek/mt8186/mt8186-reg.h [new file with mode: 0644]
sound/soc/mediatek/mt8195/mt8195-afe-clk.c
sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
sound/soc/mediatek/mt8195/mt8195-dai-pcm.c
sound/soc/mediatek/mt8195/mt8195-mt6359.c
sound/soc/meson/aiu-acodec-ctrl.c
sound/soc/meson/aiu-codec-ctrl.c
sound/soc/meson/aiu-encoder-i2s.c
sound/soc/meson/axg-frddr.c
sound/soc/meson/axg-pdm.c
sound/soc/meson/axg-spdifin.c
sound/soc/meson/axg-spdifout.c
sound/soc/meson/axg-tdm-interface.c
sound/soc/meson/axg-toddr.c
sound/soc/meson/g12a-toacodec.c
sound/soc/meson/g12a-tohdmitx.c
sound/soc/meson/meson-codec-glue.c
sound/soc/meson/t9015.c
sound/soc/mxs/mxs-saif.c
sound/soc/pxa/magician.c
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/qcom/apq8016_sbc.c
sound/soc/qcom/lpass-apq8016.c
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/qdsp6/audioreach.c
sound/soc/qcom/qdsp6/q6adm.c
sound/soc/qcom/qdsp6/q6afe.c
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/qcom/qdsp6/q6asm.c
sound/soc/qcom/sc7180.c
sound/soc/qcom/sc7280.c
sound/soc/qcom/sdm845.c
sound/soc/qcom/sm8250.c
sound/soc/rockchip/rk3288_hdmi_analog.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_i2s_tdm.c
sound/soc/rockchip/rockchip_pdm.c
sound/soc/rockchip/rockchip_spdif.c
sound/soc/samsung/Kconfig
sound/soc/samsung/aries_wm8994.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/pcm.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c-i2s-v2.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/snow.c
sound/soc/samsung/spdif.c
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ssiu.c
sound/soc/sh/rz-ssi.c
sound/soc/sh/siu_pcm.c
sound/soc/sh/ssi.c
sound/soc/soc-card.c
sound/soc/soc-core.c
sound/soc/soc-dai.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/soc-pcm.c
sound/soc/soc-topology-test.c
sound/soc/soc-topology.c
sound/soc/soc-utils.c
sound/soc/sof/Kconfig
sound/soc/sof/Makefile
sound/soc/sof/amd/Kconfig
sound/soc/sof/amd/acp-dsp-offset.h
sound/soc/sof/amd/acp.c
sound/soc/sof/amd/acp.h
sound/soc/sof/amd/pci-rn.c
sound/soc/sof/amd/renoir.c
sound/soc/sof/compress.c
sound/soc/sof/core.c
sound/soc/sof/debug.c
sound/soc/sof/imx/Kconfig
sound/soc/sof/intel/Kconfig
sound/soc/sof/intel/Makefile
sound/soc/sof/intel/apl.c
sound/soc/sof/intel/atom.c
sound/soc/sof/intel/bdw.c
sound/soc/sof/intel/byt.c
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/hda-dai.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-ipc.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-probes.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/hda.h
sound/soc/sof/intel/icl.c
sound/soc/sof/intel/mtl.c [new file with mode: 0644]
sound/soc/sof/intel/mtl.h [new file with mode: 0644]
sound/soc/sof/intel/pci-apl.c
sound/soc/sof/intel/pci-cnl.c
sound/soc/sof/intel/pci-icl.c
sound/soc/sof/intel/pci-mtl.c [new file with mode: 0644]
sound/soc/sof/intel/pci-tgl.c
sound/soc/sof/intel/shim.h
sound/soc/sof/intel/tgl.c
sound/soc/sof/ipc.c
sound/soc/sof/ipc3-dtrace.c
sound/soc/sof/ipc3-loader.c
sound/soc/sof/ipc3-pcm.c
sound/soc/sof/ipc3-topology.c
sound/soc/sof/ipc3.c
sound/soc/sof/ipc4-control.c [new file with mode: 0644]
sound/soc/sof/ipc4-pcm.c [new file with mode: 0644]
sound/soc/sof/ipc4-priv.h
sound/soc/sof/ipc4-topology.c [new file with mode: 0644]
sound/soc/sof/ipc4-topology.h [new file with mode: 0644]
sound/soc/sof/ipc4.c
sound/soc/sof/mediatek/Kconfig
sound/soc/sof/mediatek/adsp_helper.h
sound/soc/sof/mediatek/mt8186/mt8186-clk.c
sound/soc/sof/mediatek/mt8195/mt8195-clk.c
sound/soc/sof/mediatek/mt8195/mt8195-loader.c
sound/soc/sof/mediatek/mt8195/mt8195.c
sound/soc/sof/mediatek/mt8195/mt8195.h
sound/soc/sof/ops.h
sound/soc/sof/pcm.c
sound/soc/sof/sof-audio.h
sound/soc/sof/sof-client-ipc-msg-injector.c
sound/soc/sof/sof-client-probes.c
sound/soc/sof/sof-client-probes.h
sound/soc/sof/sof-client.c
sound/soc/sof/sof-priv.h
sound/soc/sof/topology.c
sound/soc/spear/spdif_in.c
sound/soc/spear/spdif_out.c
sound/soc/sti/sti_uniperif.c
sound/soc/stm/stm32_adfsdm.c
sound/soc/stm/stm32_i2s.c
sound/soc/stm/stm32_sai_sub.c
sound/soc/stm/stm32_spdifrx.c
sound/soc/sunxi/sun4i-codec.c
sound/soc/sunxi/sun4i-i2s.c
sound/soc/sunxi/sun4i-spdif.c
sound/soc/sunxi/sun50i-codec-analog.c
sound/soc/sunxi/sun8i-codec.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra20_das.c
sound/soc/tegra/tegra20_das.h [deleted file]
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra210_adx.c
sound/soc/tegra/tegra210_ahub.c
sound/soc/tegra/tegra210_i2s.c
sound/soc/tegra/tegra210_mbdrc.c [new file with mode: 0644]
sound/soc/tegra/tegra210_mbdrc.h [new file with mode: 0644]
sound/soc/tegra/tegra210_ope.c [new file with mode: 0644]
sound/soc/tegra/tegra210_ope.h [new file with mode: 0644]
sound/soc/tegra/tegra210_peq.c [new file with mode: 0644]
sound/soc/tegra/tegra210_peq.h [new file with mode: 0644]
sound/soc/tegra/tegra30_i2s.c
sound/soc/ti/davinci-i2s.c
sound/soc/ti/davinci-mcasp.c
sound/soc/ti/davinci-vcif.c
sound/soc/ti/omap-dmic.c
sound/soc/ti/omap-hdmi.c
sound/soc/ti/omap-mcbsp.c
sound/soc/ti/omap-mcpdm.c
sound/soc/uniphier/evea.c
sound/soc/ux500/mop500.c
sound/soc/ux500/mop500_ab8500.c
sound/soc/ux500/mop500_ab8500.h
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_dai.h
sound/soc/ux500/ux500_msp_i2s.c
sound/soc/ux500/ux500_msp_i2s.h
sound/soc/ux500/ux500_pcm.c
sound/soc/ux500/ux500_pcm.h
sound/soc/xilinx/xlnx_formatter_pcm.c
sound/soc/xilinx/xlnx_i2s.c
sound/soc/xilinx/xlnx_spdif.c
sound/soc/xtensa/xtfpga-i2s.c
sound/usb/6fire/pcm.c
sound/usb/bcd2000/bcd2000.c
sound/usb/endpoint.c
sound/usb/hiface/pcm.c
sound/usb/line6/pod.c
sound/usb/line6/podhd.c
sound/usb/mixer_quirks.c
sound/usb/quirks.c

diff --git a/Documentation/devicetree/bindings/dsp/mediatek,mt8186-dsp.yaml b/Documentation/devicetree/bindings/dsp/mediatek,mt8186-dsp.yaml
new file mode 100644 (file)
index 0000000..3e63f79
--- /dev/null
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dsp/mediatek,mt8186-dsp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek mt8186 DSP core
+
+maintainers:
+  - Tinghan Shen <tinghan.shen@mediatek.com>
+
+description: |
+  MediaTek mt8186 SoC contains a DSP core used for
+  advanced pre- and post- audio processing.
+
+properties:
+  compatible:
+    const: mediatek,mt8186-dsp
+
+  reg:
+    items:
+      - description: Address and size of the DSP config registers
+      - description: Address and size of the DSP SRAM
+      - description: Address and size of the DSP secure registers
+      - description: Address and size of the DSP bus registers
+
+  reg-names:
+    items:
+      - const: cfg
+      - const: sram
+      - const: sec
+      - const: bus
+
+  clocks:
+    items:
+      - description: mux for audio dsp clock
+      - description: mux for audio dsp local bus
+
+  clock-names:
+    items:
+      - const: audiodsp
+      - const: adsp_bus
+
+  power-domains:
+    maxItems: 1
+
+  mboxes:
+    items:
+      - description: mailbox for receiving audio DSP requests.
+      - description: mailbox for transmitting requests to audio DSP.
+
+  mbox-names:
+    items:
+      - const: rx
+      - const: tx
+
+  memory-region:
+    items:
+      - description: dma buffer between host and DSP.
+      - description: DSP system memory.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - clocks
+  - clock-names
+  - power-domains
+  - mbox-names
+  - mboxes
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/mt8186-clk.h>
+    dsp@10680000 {
+        compatible = "mediatek,mt8186-dsp";
+        reg = <0x10680000 0x2000>,
+              <0x10800000 0x100000>,
+              <0x1068b000 0x100>,
+              <0x1068f000 0x1000>;
+        reg-names = "cfg", "sram", "sec", "bus";
+        clocks = <&topckgen CLK_TOP_AUDIODSP>,
+                 <&topckgen CLK_TOP_ADSP_BUS>;
+        clock-names = "audiodsp",
+                      "adsp_bus";
+        power-domains = <&spm 6>;
+        mbox-names = "rx", "tx";
+        mboxes = <&adsp_mailbox0>, <&adsp_mailbox1>;
+    };
index b7e68b0dfa13e635600cb334828cdffb69145eb1..ca8d8661f8726bcd7975b6c3ef12211311976eeb 100644 (file)
@@ -50,13 +50,13 @@ properties:
 
   mboxes:
     items:
-      - description: ipc reply between host and audio DSP.
-      - description: ipc request between host and audio DSP.
+      - description: mailbox for receiving audio DSP requests.
+      - description: mailbox for transmitting requests to audio DSP.
 
   mbox-names:
     items:
-      - const: mbox0
-      - const: mbox1
+      - const: rx
+      - const: tx
 
   memory-region:
     items:
@@ -100,6 +100,6 @@ examples:
        memory-region = <&adsp_dma_mem_reserved>,
                        <&adsp_mem_reserved>;
        power-domains = <&spm 6>; //MT8195_POWER_DOMAIN_ADSP
-       mbox-names = "mbox0", "mbox1";
+       mbox-names = "rx", "tx";
        mboxes = <&adsp_mailbox0>, <&adsp_mailbox1>;
     };
index b80454ad97da6b9fd77f1c8bc470f89c30821d37..847b83398d3d19351d1f1869cd77c70071ebce6a 100644 (file)
@@ -32,8 +32,6 @@ properties:
   reset-gpios:
     maxItems: 1
 
-  spi-max-frequency: true
-
   AVDD-supply:
     description: Analog power support for the device.
 
@@ -52,7 +50,10 @@ required:
   - compatible
   - AVDD-supply
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index ec4c10c2598a8798e0522d79baf5152718a25668..8d2ef991db40fbf22c787df27e272c69c6bf4536 100644 (file)
@@ -24,6 +24,21 @@ properties:
     maxItems: 1
     description: I2C address of the device.
 
+  avdd-supply:
+    description: A 1.8V supply that powers up the AVDD pin.
+
+  dvdd-supply:
+    description: A 1.2V supply that powers up the DVDD pin.
+
+  dvddio-supply:
+    description: A 1.2V or 1.8V supply that powers up the VDDIO pin.
+
+  pvdd-supply:
+    description: A 3.0V to 20V supply that powers up the PVDD pin.
+
+  vbat-supply:
+    description: A 3.3V to 5.5V supply that powers up the VBAT pin.
+
   adi,vmon-slot-no:
     description: slot number of the voltage sense monitor
     $ref: "/schemas/types.yaml#/definitions/uint32"
@@ -36,13 +51,22 @@ properties:
     $ref: "/schemas/types.yaml#/definitions/uint32"
     minimum: 0
     maximum: 15
-    default: 0
+    default: 1
 
   adi,spkfb-slot-no:
     description: slot number of speaker DSP monitor
     $ref: "/schemas/types.yaml#/definitions/uint32"
     minimum: 0
     maximum: 15
+    default: 2
+
+  adi,bypass-slot-no:
+    description:
+      Selects the PCM data input channel that is routed to the speaker
+      audio processing bypass path.
+    $ref: "/schemas/types.yaml#/definitions/uint32"
+    minimum: 0
+    maximum: 15
     default: 0
 
   adi,interleave-mode:
@@ -72,6 +96,10 @@ examples:
         max98396: amplifier@39 {
             compatible = "adi,max98396";
             reg = <0x39>;
+            dvdd-supply = <&regulator_1v2>;
+            dvddio-supply = <&regulator_1v8>;
+            avdd-supply = <&regulator_1v8>;
+            pvdd-supply = <&regulator_pvdd>;
             adi,vmon-slot-no = <0>;
             adi,imon-slot-no = <1>;
             reset-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
index 3b764415c9abf7a696c7f965cbb36abfac4264d0..66859eb8f79ab1df66b486579a2273d030f771f0 100644 (file)
@@ -21,6 +21,11 @@ properties:
     description:
       Regulator for the headphone amplifier
 
+  allwinner,internal-bias-resistor:
+    description:
+      Enable the internal 2.2K bias resistor between HBIAS and MICDET pins
+    type: boolean
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/sound/atmel,sama5d2-classd.yaml b/Documentation/devicetree/bindings/sound/atmel,sama5d2-classd.yaml
new file mode 100644 (file)
index 0000000..43d0470
--- /dev/null
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/atmel,sama5d2-classd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel ClassD Amplifier
+
+maintainers:
+  - Nicolas Ferre <nicolas.ferre@microchip.com>
+  - Alexandre Belloni <alexandre.belloni@bootlin.com>
+  - Claudiu Beznea <claudiu.beznea@microchip.com>
+
+description:
+  The Audio Class D Amplifier (CLASSD) is a digital input, Pulse Width
+  Modulated (PWM) output stereo Class D amplifier.
+
+properties:
+  compatible:
+    const: atmel,sama5d2-classd
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  dmas:
+    maxItems: 1
+
+  dma-names:
+    const: tx
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: gclk
+
+  atmel,model:
+    $ref: /schemas/types.yaml#/definitions/string
+    default: CLASSD
+    description: The user-visible name of this sound complex.
+
+  atmel,pwm-type:
+    $ref: /schemas/types.yaml#/definitions/string
+    enum:
+      - single
+      - diff
+    default: single
+    description: PWM modulation type.
+
+  atmel,non-overlap-time:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 5
+      - 10
+      - 15
+      - 20
+    default: 10
+    description:
+      Set non-overlapping time, the unit is nanosecond(ns).
+      Non-overlapping will be disabled if not specified.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - dmas
+  - dma-names
+  - clock-names
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/dma/at91.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    classd: sound@fc048000 {
+        compatible = "atmel,sama5d2-classd";
+        reg = <0xfc048000 0x100>;
+        interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>;
+        dmas = <&dma0
+            (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+            | AT91_XDMAC_DT_PERID(47))>;
+        dma-names = "tx";
+        clocks = <&classd_clk>, <&classd_gclk>;
+        clock-names = "pclk", "gclk";
+        assigned-clocks = <&classd_gclk>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_classd_default>;
+        atmel,model = "classd @ SAMA5D2-Xplained";
+        atmel,pwm-type = "diff";
+        atmel,non-overlap-time = <10>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/atmel,sama5d2-i2s.yaml b/Documentation/devicetree/bindings/sound/atmel,sama5d2-i2s.yaml
new file mode 100644 (file)
index 0000000..0cd1ff8
--- /dev/null
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/atmel,sama5d2-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel I2S controller
+
+maintainers:
+  - Nicolas Ferre <nicolas.ferre@microchip.com>
+  - Alexandre Belloni <alexandre.belloni@bootlin.com>
+  - Claudiu Beznea <claudiu.beznea@microchip.com>
+
+description:
+  Atmel I2S (Inter-IC Sound Controller) bus is the standard
+  interface for connecting audio devices, such as audio codecs.
+
+properties:
+  compatible:
+    const: atmel,sama5d2-i2s
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Peripheral clock
+      - description: Generated clock (Optional)
+      - description: I2S mux clock (Optional). Set
+          with gclk when Master Mode is required.
+    minItems: 1
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: gclk
+      - const: muxclk
+    minItems: 1
+
+  dmas:
+    items:
+      - description: TX DMA Channel
+      - description: RX DMA Channel
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - dmas
+  - dma-names
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/dma/at91.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    i2s@f8050000 {
+        compatible = "atmel,sama5d2-i2s";
+        reg = <0xf8050000 0x300>;
+        interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
+        dmas = <&dma0
+                (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+                AT91_XDMAC_DT_PERID(31))>,
+               <&dma0
+                (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+                AT91_XDMAC_DT_PERID(32))>;
+        dma-names = "tx", "rx";
+        clocks = <&i2s0_clk>, <&i2s0_gclk>, <&i2s0muxck>;
+        clock-names = "pclk", "gclk", "muxclk";
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_i2s0_default>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/atmel,sama5d2-pdmic.yaml b/Documentation/devicetree/bindings/sound/atmel,sama5d2-pdmic.yaml
new file mode 100644 (file)
index 0000000..f320b56
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/atmel,sama5d2-pdmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atmel PDMIC decoder
+
+maintainers:
+  - Claudiu Beznea <claudiu.beznea@microchip.com>
+
+description:
+  Atmel Pulse Density Modulation Interface Controller
+  (PDMIC) peripheral is a mono PDM decoder module
+  that decodes an incoming PDM sample stream.
+
+properties:
+  compatible:
+    const: atmel,sama5d2-pdmic
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: peripheral clock
+      - description: generated clock
+
+  clock-names:
+    items:
+      - const: pclk
+      - const: gclk
+
+  dmas:
+    maxItems: 1
+
+  dma-names:
+    const: rx
+
+  atmel,mic-min-freq:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The minimal frequency that the microphone supports.
+
+  atmel,mic-max-freq:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The maximal frequency that the microphone supports.
+
+  atmel,model:
+    $ref: /schemas/types.yaml#/definitions/string
+    default: PDMIC
+    description: The user-visible name of this sound card.
+
+  atmel,mic-offset:
+    $ref: /schemas/types.yaml#/definitions/int32
+    default: 0
+    description: The offset that should be added.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - dmas
+  - dma-names
+  - clock-names
+  - clocks
+  - atmel,mic-min-freq
+  - atmel,mic-max-freq
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/dma/at91.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    pdmic: sound@f8018000 {
+        compatible = "atmel,sama5d2-pdmic";
+        reg = <0xf8018000 0x124>;
+        interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
+        dmas = <&dma0
+                (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+                | AT91_XDMAC_DT_PERID(50))>;
+        dma-names = "rx";
+        clocks = <&pdmic_clk>, <&pdmic_gclk>;
+        clock-names = "pclk", "gclk";
+        pinctrl-names = "default";
+        pinctrl-0 = <&pinctrl_pdmic_default>;
+        atmel,model = "PDMIC@sama5d2_xplained";
+        atmel,mic-min-freq = <1000000>;
+        atmel,mic-max-freq = <3246000>;
+        atmel,mic-offset = <0x0>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/atmel-classd.txt b/Documentation/devicetree/bindings/sound/atmel-classd.txt
deleted file mode 100644 (file)
index 8985510..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-* Atmel ClassD driver under ALSA SoC architecture
-
-Required properties:
-- compatible
-       Should be "atmel,sama5d2-classd".
-- reg
-       Should contain ClassD registers location and length.
-- interrupts
-       Should contain the IRQ line for the ClassD.
-- dmas
-       One DMA specifiers as described in atmel-dma.txt and dma.txt files.
-- dma-names
-       Must be "tx".
-- clock-names
-       Tuple listing input clock names.
-       Required elements: "pclk" and "gclk".
-- clocks
-       Please refer to clock-bindings.txt.
-- assigned-clocks
-       Should be <&classd_gclk>.
-
-Optional properties:
-- pinctrl-names, pinctrl-0
-       Please refer to pinctrl-bindings.txt.
-- atmel,model
-       The user-visible name of this sound complex.
-       The default value is "CLASSD".
-- atmel,pwm-type
-       PWM modulation type, "single" or "diff".
-       The default value is "single".
-- atmel,non-overlap-time
-       Set non-overlapping time, the unit is nanosecond(ns).
-       There are four values,
-       <5>, <10>, <15>, <20>, the default value is <10>.
-       Non-overlapping will be disabled if not specified.
-
-Example:
-classd: classd@fc048000 {
-               compatible = "atmel,sama5d2-classd";
-               reg = <0xfc048000 0x100>;
-               interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>;
-               dmas = <&dma0
-                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
-                       | AT91_XDMAC_DT_PERID(47))>;
-               dma-names = "tx";
-               clocks = <&classd_clk>, <&classd_gclk>;
-               clock-names = "pclk", "gclk";
-               assigned-clocks = <&classd_gclk>;
-
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_classd_default>;
-               atmel,model = "classd @ SAMA5D2-Xplained";
-               atmel,pwm-type = "diff";
-               atmel,non-overlap-time = <10>;
-};
diff --git a/Documentation/devicetree/bindings/sound/atmel-i2s.txt b/Documentation/devicetree/bindings/sound/atmel-i2s.txt
deleted file mode 100644 (file)
index 40549f4..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-* Atmel I2S controller
-
-Required properties:
-- compatible:     Should be "atmel,sama5d2-i2s".
-- reg:            Should be the physical base address of the controller and the
-                  length of memory mapped region.
-- interrupts:     Should contain the interrupt for the controller.
-- dmas:           Should be one per channel name listed in the dma-names property,
-                  as described in atmel-dma.txt and dma.txt files.
-- dma-names:      Two dmas have to be defined, "tx" and "rx".
-                  This IP also supports one shared channel for both rx and tx;
-                  if this mode is used, one "rx-tx" name must be used.
-- clocks:         Must contain an entry for each entry in clock-names.
-                  Please refer to clock-bindings.txt.
-- clock-names:    Should be one of each entry matching the clocks phandles list:
-                  - "pclk" (peripheral clock) Required.
-                  - "gclk" (generated clock) Optional (1).
-                  - "muxclk" (I2S mux clock) Optional (1).
-
-Optional properties:
-- pinctrl-0:      Should specify pin control groups used for this controller.
-- princtrl-names: Should contain only one value - "default".
-
-
-(1) : Only the peripheral clock is required. The generated clock and the I2S
-      mux clock are optional and should only be set together, when Master Mode
-      is required.
-
-Example:
-
-       i2s@f8050000 {
-               compatible = "atmel,sama5d2-i2s";
-               reg = <0xf8050000 0x300>;
-               interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
-               dmas = <&dma0
-                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
-                        AT91_XDMAC_DT_PERID(31))>,
-                      <&dma0
-                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
-                        AT91_XDMAC_DT_PERID(32))>;
-               dma-names = "tx", "rx";
-               clocks = <&i2s0_clk>, <&i2s0_gclk>, <&i2s0muxck>;
-               clock-names = "pclk", "gclk", "muxclk";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_i2s0_default>;
-       };
diff --git a/Documentation/devicetree/bindings/sound/atmel-pdmic.txt b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt
deleted file mode 100644 (file)
index e0875f1..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-* Atmel PDMIC driver under ALSA SoC architecture
-
-Required properties:
-- compatible
-       Should be "atmel,sama5d2-pdmic".
-- reg
-       Should contain PDMIC registers location and length.
-- interrupts
-       Should contain the IRQ line for the PDMIC.
-- dmas
-       One DMA specifiers as described in atmel-dma.txt and dma.txt files.
-- dma-names
-       Must be "rx".
-- clock-names
-       Required elements:
-       - "pclk"        peripheral clock
-       - "gclk"        generated clock
-- clocks
-       Must contain an entry for each required entry in clock-names.
-       Please refer to clock-bindings.txt.
-- atmel,mic-min-freq
-       The minimal frequency that the micphone supports.
-- atmel,mic-max-freq
-       The maximal frequency that the micphone supports.
-
-Optional properties:
-- pinctrl-names, pinctrl-0
-       Please refer to pinctrl-bindings.txt.
-- atmel,model
-       The user-visible name of this sound card.
-       The default value is "PDMIC".
-- atmel,mic-offset
-       The offset that should be added.
-       The range is from -32768 to 32767.
-       The default value is 0.
-
-Example:
-       pdmic@f8018000 {
-                               compatible = "atmel,sama5d2-pdmic";
-                               reg = <0xf8018000 0x124>;
-                               interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>;
-                               dmas = <&dma0
-                                       (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
-                                       | AT91_XDMAC_DT_PERID(50))>;
-                               dma-names = "rx";
-                               clocks = <&pdmic_clk>, <&pdmic_gclk>;
-                               clock-names = "pclk", "gclk";
-
-                               pinctrl-names = "default";
-                               pinctrl-0 = <&pinctrl_pdmic_default>;
-                               atmel,model = "PDMIC @ sama5d2_xplained";
-                               atmel,mic-min-freq = <1000000>;
-                               atmel,mic-max-freq = <3246000>;
-                               atmel,mic-offset = <0x0>;
-       };
index 0720857089a7d0b3464fdc57927b01a27b5394af..8facbce53db86adc5e25aa2a21f6fbf1b7552fd2 100644 (file)
@@ -16,7 +16,7 @@ Board connectors:
  * Line In Jack
 
 wm8731 pins:
-cf Documentation/devicetree/bindings/sound/wm8731.txt
+cf Documentation/devicetree/bindings/sound/wlf,wm8731.yaml
 
 Example:
 sound {
diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt
deleted file mode 100644 (file)
index 6a536d5..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-DesignWare I2S controller
-
-Required properties:
- - compatible : Must be "snps,designware-i2s"
- - reg : Must contain the I2S core's registers location and length
- - clocks : Pairs of phandle and specifier referencing the controller's
-   clocks. The controller expects one clock: the clock used as the sampling
-   rate reference clock sample.
- - clock-names : "i2sclk" for the sample rate reference clock.
- - dmas: Pairs of phandle and specifier for the DMA channels that are used by
-   the core. The core expects one or two dma channels: one for transmit and
-   one for receive.
- - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
-
-Optional properties:
- - interrupts: The interrupt line number for the I2S controller. Add this
-   parameter if the I2S controller that you are using does not support DMA.
-
-For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
-properties please check:
-       * resource-names.txt
-       * clock/clock-bindings.txt
-       * dma/dma.txt
-
-Example:
-
-       soc_i2s: i2s@7ff90000 {
-               compatible = "snps,designware-i2s";
-               reg = <0x0 0x7ff90000 0x0 0x1000>;
-               clocks = <&scpi_i2sclk 0>;
-               clock-names = "i2sclk";
-               #sound-dai-cells = <0>;
-               dmas = <&dma0 5>;
-               dma-names = "tx";
-       };
diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.txt b/Documentation/devicetree/bindings/sound/fsl,micfil.txt
deleted file mode 100644 (file)
index 1ea05d4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-NXP MICFIL Digital Audio Interface (MICFIL).
-
-The MICFIL digital interface provides a 16-bit audio signal from a PDM
-microphone bitstream in a configurable output sampling rate.
-
-Required properties:
-
-  - compatible         : Compatible list, contains "fsl,imx8mm-micfil"
-                         or "fsl,imx8mp-micfil"
-
-  - reg                        : Offset and length of the register set for the device.
-
-  - interrupts         : Contains the micfil interrupts.
-
-  - clocks             : Must contain an entry for each entry in clock-names.
-
-  - clock-names                : Must include the "ipg_clk" for register access and
-                         "ipg_clk_app" for internal micfil clock.
-
-  - dmas               : Generic dma devicetree binding as described in
-                         Documentation/devicetree/bindings/dma/dma.txt.
-
-Example:
-micfil: micfil@30080000 {
-       compatible = "fsl,imx8mm-micfil";
-       reg = <0x0 0x30080000 0x0 0x10000>;
-       interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
-                    <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
-       clocks = <&clk IMX8MM_CLK_PDM_IPG>,
-                <&clk IMX8MM_CLK_PDM_ROOT>;
-       clock-names = "ipg_clk", "ipg_clk_app";
-       dmas = <&sdma2 24 26 0x80000000>;
-};
diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
new file mode 100644 (file)
index 0000000..64d5775
--- /dev/null
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,micfil.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP MICFIL Digital Audio Interface (MICFIL)
+
+maintainers:
+  - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+description: |
+  The MICFIL digital interface provides a 16-bit or 24-bit audio signal
+  from a PDM microphone bitstream in a configurable output sampling rate.
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx8mm-micfil
+      - fsl,imx8mp-micfil
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: Digital Microphone interface interrupt
+      - description: Digital Microphone interface error interrupt
+      - description: voice activity detector event interrupt
+      - description: voice activity detector error interrupt
+
+  dmas:
+    items:
+      - description: DMA controller phandle and request line for RX
+
+  dma-names:
+    items:
+      - const: rx
+
+  clocks:
+    items:
+      - description: The ipg clock for register access
+      - description: internal micfil clock
+      - description: PLL clock source for 8kHz series
+      - description: PLL clock source for 11kHz series
+      - description: External clock 3
+    minItems: 2
+
+  clock-names:
+    items:
+      - const: ipg_clk
+      - const: ipg_clk_app
+      - const: pll8k
+      - const: pll11k
+      - const: clkext3
+    minItems: 2
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - dmas
+  - dma-names
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/imx8mm-clock.h>
+    micfil: audio-controller@30080000 {
+        compatible = "fsl,imx8mm-micfil";
+        reg = <0x30080000 0x10000>;
+        interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clk IMX8MM_CLK_PDM_IPG>,
+                 <&clk IMX8MM_CLK_PDM_ROOT>;
+        clock-names = "ipg_clk", "ipg_clk_app";
+        dmas = <&sdma2 24 25 0>;
+        dma-names = "rx";
+    };
index 40353fc30255b73bb265e1d2bd56b7fe0ff75935..d66284b8bef29b08217fb84a8ab58825a891c5a7 100644 (file)
@@ -2,7 +2,7 @@ fsl,mqs audio CODEC
 
 Required properties:
   - compatible : Must contain one of "fsl,imx6sx-mqs", "fsl,codec-mqs"
-               "fsl,imx8qm-mqs", "fsl,imx8qxp-mqs".
+               "fsl,imx8qm-mqs", "fsl,imx8qxp-mqs", "fsl,imx93-mqs".
   - clocks : A list of phandles + clock-specifiers, one for each entry in
             clock-names
   - clock-names : "mclk" - must required.
index f226ec13167ad0ad4440c3d15d9e7381db178f2f..1d64e8337aa4b2fe16fab4aa6b9d9b09e99a29c8 100644 (file)
@@ -58,6 +58,8 @@ properties:
           slave of the Shared Peripheral Bus and when two or more bus masters
           (CPU, DMA or DSP) try to access it. This property is optional depending
           on the SoC design.
+      - description: PLL clock source for 8kHz series rate, optional.
+      - description: PLL clock source for 11khz series rate, optional.
     minItems: 9
 
   clock-names:
@@ -72,6 +74,8 @@ properties:
       - const: rxtx6
       - const: rxtx7
       - const: spba
+      - const: pll8k
+      - const: pll11k
     minItems: 9
 
   big-endian:
index c71c5861d787e2e76c4c014d36ee0a185c47f13a..fbdefc3fade79ed33f4a9ff2090a71f18774b408 100644 (file)
@@ -21,6 +21,9 @@ Required properties:
   - clock-names                : Must include the "bus" for register access and
                          "mclk1", "mclk2", "mclk3" for bit clock and frame
                          clock providing.
+                          "pll8k", "pll11k" are optional, they are the clock
+                          source for root clock, one is for 8kHz series rates
+                          another one is for 11kHz series rates.
   - dmas               : Generic dma devicetree binding as described in
                          Documentation/devicetree/bindings/dma/dma.txt.
 
@@ -49,6 +52,14 @@ Required properties:
                          receive data by following their own bit clocks and
                          frame sync clocks separately.
 
+  - fsl,dataline        : configure the dataline. it has 3 value for each configuration
+                          first one means the type: I2S(1) or PDM(2)
+                          second one is dataline mask for 'rx'
+                          third one is dataline mask for 'tx'.
+                          for example: fsl,dataline = <1 0xff 0xff 2 0xff 0x11>;
+                          it means I2S type rx mask is 0xff, tx mask is 0xff, PDM type
+                          rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled).
+
 Optional properties:
 
   - big-endian         : Boolean property, required if all the SAI
index 59a73ffdf1d34d3fa67c9551896884be3c02a468..fbe9e55c68f59a05715a44821faf7f3145a22231 100644 (file)
@@ -7,7 +7,9 @@ Must be a child node of PMIC wrapper.
 
 Required properties:
 
-- compatible : "mediatek,mt6358-sound".
+- compatible - "string" - One of:
+    "mediatek,mt6358-sound"
+    "mediatek,mt6366-sound"
 - Avdd-supply : power source of AVDD
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml b/Documentation/devicetree/bindings/sound/mt8186-afe-pcm.yaml
new file mode 100644 (file)
index 0000000..88f82d0
--- /dev/null
@@ -0,0 +1,175 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8186-afe-pcm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek AFE PCM controller for mt8186
+
+maintainers:
+  - Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+properties:
+  compatible:
+    const: mediatek,mt8186-sound
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    const: audiosys
+
+  mediatek,apmixedsys:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of the mediatek apmixedsys controller
+
+  mediatek,infracfg:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of the mediatek infracfg controller
+
+  mediatek,topckgen:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of the mediatek topckgen controller
+
+  clocks:
+    items:
+      - description: audio infra sys clock
+      - description: audio infra 26M clock
+      - description: audio top mux
+      - description: audio intbus mux
+      - description: mainpll 136.5M clock
+      - description: faud1 mux
+      - description: apll1 clock
+      - description: faud2 mux
+      - description: apll2 clock
+      - description: audio engen1 mux
+      - description: apll1_d8 22.5792M clock
+      - description: audio engen2 mux
+      - description: apll2_d8 24.576M clock
+      - description: i2s0 mclk mux
+      - description: i2s1 mclk mux
+      - description: i2s2 mclk mux
+      - description: i2s4 mclk mux
+      - description: tdm mclk mux
+      - description: i2s0_mck divider
+      - description: i2s1_mck divider
+      - description: i2s2_mck divider
+      - description: i2s4_mck divider
+      - description: tdm_mck divider
+      - description: audio hires mux
+      - description: 26M clock
+
+  clock-names:
+    items:
+      - const: aud_infra_clk
+      - const: mtkaif_26m_clk
+      - const: top_mux_audio
+      - const: top_mux_audio_int
+      - const: top_mainpll_d2_d4
+      - const: top_mux_aud_1
+      - const: top_apll1_ck
+      - const: top_mux_aud_2
+      - const: top_apll2_ck
+      - const: top_mux_aud_eng1
+      - const: top_apll1_d8
+      - const: top_mux_aud_eng2
+      - const: top_apll2_d8
+      - const: top_i2s0_m_sel
+      - const: top_i2s1_m_sel
+      - const: top_i2s2_m_sel
+      - const: top_i2s4_m_sel
+      - const: top_tdm_m_sel
+      - const: top_apll12_div0
+      - const: top_apll12_div1
+      - const: top_apll12_div2
+      - const: top_apll12_div4
+      - const: top_apll12_div_tdm
+      - const: top_mux_audio_h
+      - const: top_clk26m_clk
+
+required:
+  - compatible
+  - interrupts
+  - resets
+  - reset-names
+  - mediatek,apmixedsys
+  - mediatek,infracfg
+  - mediatek,topckgen
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    afe: mt8186-afe-pcm@11210000 {
+        compatible = "mediatek,mt8186-sound";
+        reg = <0x11210000 0x2000>;
+        interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+        resets = <&watchdog 17>; //MT8186_TOPRGU_AUDIO_SW_RST
+        reset-names = "audiosys";
+        mediatek,apmixedsys = <&apmixedsys>;
+        mediatek,infracfg = <&infracfg>;
+        mediatek,topckgen = <&topckgen>;
+        clocks = <&infracfg_ao 44>, //CLK_INFRA_AO_AUDIO
+                 <&infracfg_ao 54>, //CLK_INFRA_AO_AUDIO_26M_BCLK
+                 <&topckgen 15>, //CLK_TOP_AUDIO
+                 <&topckgen 16>, //CLK_TOP_AUD_INTBUS
+                 <&topckgen 70>, //CLK_TOP_MAINPLL_D2_D4
+                 <&topckgen 17>, //CLK_TOP_AUD_1
+                 <&apmixedsys 12>, //CLK_APMIXED_APLL1
+                 <&topckgen 18>, //CLK_TOP_AUD_2
+                 <&apmixedsys 13>, //CLK_APMIXED_APLL2
+                 <&topckgen 19>, //CLK_TOP_AUD_ENGEN1
+                 <&topckgen 101>, //CLK_TOP_APLL1_D8
+                 <&topckgen 20>, //CLK_TOP_AUD_ENGEN2
+                 <&topckgen 104>, //CLK_TOP_APLL2_D8
+                 <&topckgen 63>, //CLK_TOP_APLL_I2S0_MCK_SEL
+                 <&topckgen 64>, //CLK_TOP_APLL_I2S1_MCK_SEL
+                 <&topckgen 65>, //CLK_TOP_APLL_I2S2_MCK_SEL
+                 <&topckgen 66>, //CLK_TOP_APLL_I2S4_MCK_SEL
+                 <&topckgen 67>, //CLK_TOP_APLL_TDMOUT_MCK_SEL
+                 <&topckgen 131>, //CLK_TOP_APLL12_CK_DIV0
+                 <&topckgen 132>, //CLK_TOP_APLL12_CK_DIV1
+                 <&topckgen 133>, //CLK_TOP_APLL12_CK_DIV2
+                 <&topckgen 134>, //CLK_TOP_APLL12_CK_DIV4
+                 <&topckgen 135>, //CLK_TOP_APLL12_CK_DIV_TDMOUT_M
+                 <&topckgen 44>, //CLK_TOP_AUDIO_H
+                 <&clk26m>;
+        clock-names = "aud_infra_clk",
+                      "mtkaif_26m_clk",
+                      "top_mux_audio",
+                      "top_mux_audio_int",
+                      "top_mainpll_d2_d4",
+                      "top_mux_aud_1",
+                      "top_apll1_ck",
+                      "top_mux_aud_2",
+                      "top_apll2_ck",
+                      "top_mux_aud_eng1",
+                      "top_apll1_d8",
+                      "top_mux_aud_eng2",
+                      "top_apll2_d8",
+                      "top_i2s0_m_sel",
+                      "top_i2s1_m_sel",
+                      "top_i2s2_m_sel",
+                      "top_i2s4_m_sel",
+                      "top_tdm_m_sel",
+                      "top_apll12_div0",
+                      "top_apll12_div1",
+                      "top_apll12_div2",
+                      "top_apll12_div4",
+                      "top_apll12_div_tdm",
+                      "top_mux_audio_h",
+                      "top_clk26m_clk";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-da7219-max98357.yaml
new file mode 100644 (file)
index 0000000..513cd28
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8186-mt6366-da7219-max98357.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT8186 with MT6366, DA7219 and MAX98357 ASoC sound card driver
+
+maintainers:
+  - Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+description:
+  This binding describes the MT8186 sound card.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8186-mt6366-da7219-max98357-sound
+
+  mediatek,platform:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of MT8186 ASoC platform.
+
+  headset-codec:
+    type: object
+    additionalProperties: false
+    properties:
+      sound-dai:
+        maxItems: 1
+    required:
+      - sound-dai
+
+  playback-codecs:
+    type: object
+    additionalProperties: false
+    properties:
+      sound-dai:
+        items:
+          - description: phandle of dp codec
+          - description: phandle of l channel speaker codec
+          - description: phandle of r channel speaker codec
+        minItems: 2
+    required:
+      - sound-dai
+
+additionalProperties: false
+
+required:
+  - compatible
+  - mediatek,platform
+  - headset-codec
+  - playback-codecs
+
+examples:
+  - |
+
+    sound: mt8186-sound {
+        compatible = "mediatek,mt8186-mt6366-da7219-max98357-sound";
+        mediatek,platform = <&afe>;
+        pinctrl-names = "aud_clk_mosi_off",
+                        "aud_clk_mosi_on";
+        pinctrl-0 = <&aud_clk_mosi_off>;
+        pinctrl-1 = <&aud_clk_mosi_on>;
+
+        headset-codec {
+            sound-dai = <&da7219>;
+        };
+
+        playback-codecs {
+            sound-dai = <&anx_bridge_dp>,
+                        <&max98357a>;
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml b/Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
new file mode 100644 (file)
index 0000000..059a762
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mt8186-mt6366-rt1019-rt5682s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT8186 with MT6366, RT1019 and RT5682S ASoC sound card driver
+
+maintainers:
+  - Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+description:
+  This binding describes the MT8186 sound card.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8186-mt6366-rt1019-rt5682s-sound
+
+  mediatek,platform:
+    $ref: "/schemas/types.yaml#/definitions/phandle"
+    description: The phandle of MT8186 ASoC platform.
+
+  headset-codec:
+    type: object
+    additionalProperties: false
+    properties:
+      sound-dai:
+        maxItems: 1
+    required:
+      - sound-dai
+
+  playback-codecs:
+    type: object
+    additionalProperties: false
+    properties:
+      sound-dai:
+        items:
+          - description: phandle of dp codec
+          - description: phandle of l channel speaker codec
+          - description: phandle of r channel speaker codec
+        minItems: 2
+    required:
+      - sound-dai
+
+additionalProperties: false
+
+required:
+  - compatible
+  - mediatek,platform
+  - headset-codec
+  - playback-codecs
+
+examples:
+  - |
+
+    sound: mt8186-sound {
+        compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound";
+        mediatek,platform = <&afe>;
+        pinctrl-names = "aud_clk_mosi_off",
+                        "aud_clk_mosi_on";
+        pinctrl-0 = <&aud_clk_mosi_off>;
+        pinctrl-1 = <&aud_clk_mosi_on>;
+
+        headset-codec {
+            sound-dai = <&rt5682s>;
+        };
+
+        playback-codecs {
+             sound-dai = <&it6505dptx>,
+                         <&rt1019p>;
+        };
+    };
+
+...
index 6c3baf7a5f21dfa55e5ea6dd018ac3dee30ee1bc..7c84e7c7327a70ca29de34e22caac632610fc22c 100644 (file)
@@ -34,7 +34,7 @@ Optional properties:
   - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
 
   - nuvoton,dmic-clk-threshold: the ADC threshold of DMIC clock.
-
+  - nuvoton,key_enable: Headset button detection switch.
 
 Example:
 
index 6df6f858038cce2427c295338d1a78b24828ed36..47b6e712e4fbcf4e5c2c39c2fb33b6b5d32bea43 100644 (file)
@@ -110,6 +110,10 @@ patternProperties:
     type: object
     $ref: nvidia,tegra186-asrc.yaml#
 
+  '^processing-engine@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-ope.yaml#
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-mbdrc.yaml
new file mode 100644 (file)
index 0000000..5b91986
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-mbdrc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 MBDRC
+
+description:
+  The Multi Band Dynamic Range Compressor (MBDRC) is part of Output
+  Processing Engine (OPE) which interfaces with Audio Hub (AHUB) via
+  Audio Client Interface (ACIF). MBDRC can be used as a traditional
+  single full band or a dual band or a multi band dynamic processor.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-mbdrc
+      - items:
+          - enum:
+              - nvidia,tegra234-mbdrc
+              - nvidia,tegra194-mbdrc
+              - nvidia,tegra186-mbdrc
+          - const: nvidia,tegra210-mbdrc
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    dynamic-range-compressor@702d8200 {
+        compatible = "nvidia,tegra210-mbdrc";
+        reg = <0x702d8200 0x200>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ope.yaml
new file mode 100644 (file)
index 0000000..9dc9ba5
--- /dev/null
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-ope.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 OPE
+
+description:
+  The Output Processing Engine (OPE) is one of the AHUB client. It has
+  PEQ (Parametric Equalizer) and MBDRC (Multi Band Dynamic Range Compressor)
+  sub blocks for data processing.
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+allOf:
+  - $ref: name-prefix.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-ope
+      - items:
+          - enum:
+              - nvidia,tegra234-ope
+              - nvidia,tegra194-ope
+              - nvidia,tegra186-ope
+          - const: nvidia,tegra210-ope
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+  sound-name-prefix:
+    pattern: "^OPE[1-9]$"
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF (Audio Client Interface) input port. This is connected
+          to corresponding ACIF output port on AHUB (Audio Hub).
+
+      port@1:
+        $ref: audio-graph-port.yaml#
+        unevaluatedProperties: false
+        description:
+          OPE ACIF output port. This is connected to corresponding ACIF
+          input port on AHUB.
+
+patternProperties:
+  '^equalizer@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-peq.yaml#
+
+  '^dynamic-range-compressor@[0-9a-f]+$':
+    type: object
+    $ref: nvidia,tegra210-mbdrc.yaml#
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    processing-engine@702d8000 {
+        compatible = "nvidia,tegra210-ope";
+        reg = <0x702d8000 0x100>;
+        sound-name-prefix = "OPE1";
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-peq.yaml
new file mode 100644 (file)
index 0000000..1e373c4
--- /dev/null
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nvidia,tegra210-peq.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tegra210 PEQ
+
+description:
+  The Parametric Equalizer (PEQ) is a cascade of biquad filters with
+  each filter tuned based on certain parameters. It can be used to
+  equalize the irregularities in the speaker frequency response.
+  PEQ sits inside Output Processing Engine (OPE) which interfaces
+  with Audio Hub (AHUB) via Audio Client Interface (ACIF).
+
+maintainers:
+  - Jon Hunter <jonathanh@nvidia.com>
+  - Mohan Kumar <mkumard@nvidia.com>
+  - Sameer Pujar <spujar@nvidia.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: nvidia,tegra210-peq
+      - items:
+          - enum:
+              - nvidia,tegra234-peq
+              - nvidia,tegra194-peq
+              - nvidia,tegra186-peq
+          - const: nvidia,tegra210-peq
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    equalizer@702d8100 {
+        compatible = "nvidia,tegra210-peq";
+        reg = <0x702d8100 0x100>;
+    };
+
+...
index b9b1dba40856d6fd1181be89a1d7fde58f61834d..7f2e68ff6d342517f09077f93d7f9fd66853a9be 100644 (file)
@@ -15,6 +15,7 @@ allOf:
 properties:
   compatible:
     enum:
+      - nxp,tfa9890
       - nxp,tfa9895
       - nxp,tfa9897
 
diff --git a/Documentation/devicetree/bindings/sound/qcom,sdm845.txt b/Documentation/devicetree/bindings/sound/qcom,sdm845.txt
deleted file mode 100644 (file)
index de4c604..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-* Qualcomm Technologies Inc. SDM845 ASoC sound card driver
-
-This binding describes the SDM845 sound card, which uses qdsp for audio.
-
-- compatible:
-       Usage: required
-       Value type: <stringlist>
-       Definition: must be one of this
-                       "qcom,sdm845-sndcard"
-                       "qcom,db845c-sndcard"
-                       "lenovo,yoga-c630-sndcard"
-
-- audio-routing:
-       Usage: Optional
-       Value type: <stringlist>
-       Definition:  A list of the connections between audio components.
-                 Each entry is a pair of strings, the first being the
-                 connection's sink, the second being the connection's
-                 source. Valid names could be power supplies, MicBias
-                 of codec and the jacks on the board.
-
-- model:
-       Usage: required
-       Value type: <stringlist>
-       Definition: The user-visible name of this sound card.
-
-- aux-devs
-       Usage: optional
-       Value type: <array of phandles>
-       Definition: A list of phandles for auxiliary devices (e.g. analog
-                   amplifiers) that do not appear directly within the DAI
-                   links. Should be connected to another audio component
-                   using "audio-routing".
-
-= dailinks
-Each subnode of sndcard represents either a dailink, and subnodes of each
-dailinks would be cpu/codec/platform dais.
-
-- link-name:
-       Usage: required
-       Value type: <string>
-       Definition: User friendly name for dai link
-
-= CPU, PLATFORM, CODEC dais subnodes
-- cpu:
-       Usage: required
-       Value type: <subnode>
-       Definition: cpu dai sub-node
-
-- codec:
-       Usage: required
-       Value type: <subnode>
-       Definition: codec dai sub-node
-
-- platform:
-       Usage: Optional
-       Value type: <subnode>
-       Definition: platform dai sub-node
-
-- sound-dai:
-       Usage: required
-       Value type: <phandle>
-       Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node.
-
-Example:
-
-audio {
-       compatible = "qcom,sdm845-sndcard";
-       model = "sdm845-snd-card";
-       pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active>;
-       pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep>;
-
-       mm1-dai-link {
-               link-name = "MultiMedia1";
-               cpu {
-                       sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
-               };
-       };
-
-       pri-mi2s-dai-link {
-               link-name = "PRI MI2S Playback";
-               cpu {
-                       sound-dai = <&q6afedai PRIMARY_MI2S_RX>;
-               };
-
-               platform {
-                       sound-dai = <&q6routing>;
-               };
-       };
-};
index 4ecd4080bb9629005a026cb8c2a445c4afc07467..e6e27d09783eca2f8a1f7410c421abb72c1c20cd 100644 (file)
@@ -16,8 +16,11 @@ description:
 properties:
   compatible:
     enum:
+      - lenovo,yoga-c630-sndcard
       - qcom,apq8016-sbc-sndcard
+      - qcom,db845c-sndcard
       - qcom,msm8916-qdsp6-sndcard
+      - qcom,sdm845-sndcard
       - qcom,sm8250-sndcard
       - qcom,qrb5165-rb5-sndcard
 
index 9b225dbf8b79f6a4489d7f6cac92e5ccf61d4a6c..8ca19f2b0b3dec9a69a278f9c7bf9f2a48a4baad 100644 (file)
@@ -127,7 +127,7 @@ properties:
 
   gpio@42:
     type: object
-    $ref: ../gpio/qcom,wcd934x-gpio.yaml#
+    $ref: /schemas/gpio/qcom,wcd934x-gpio.yaml#
 
 patternProperties:
   "^.*@[0-9a-f]+$":
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml
new file mode 100644 (file)
index 0000000..6113f65
--- /dev/null
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wsa883x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for The Qualcomm WSA8830/WSA8832/WSA8835
+  smart speaker amplifier
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+description: |
+  WSA883X is the Qualcomm Aqstic smart speaker amplifier
+  Their primary operating mode uses a SoundWire digital audio
+  interface. This binding is for SoundWire interface.
+
+properties:
+  compatible:
+    const: sdw10217020200
+
+  reg:
+    maxItems: 1
+
+  powerdown-gpios:
+    description: GPIO spec for Powerdown/Shutdown line to use
+    maxItems: 1
+
+  vdd-supply:
+    description: VDD Supply for the Codec
+
+  '#thermal-sensor-cells':
+    const: 0
+
+  '#sound-dai-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - vdd-supply
+  - powerdown-gpios
+  - "#thermal-sensor-cells"
+  - "#sound-dai-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    soundwire-controller@3250000 {
+        #address-cells = <2>;
+        #size-cells = <0>;
+        reg = <0x3250000 0x2000>;
+
+        speaker@0,1 {
+            compatible = "sdw10217020200";
+            reg = <0 1>;
+            powerdown-gpios = <&tlmm 1 0>;
+            vdd-supply = <&vreg_s10b_1p8>;
+            #thermal-sensor-cells = <0>;
+            #sound-dai-cells = <0>;
+        };
+
+        speaker@0,2 {
+            compatible = "sdw10217020200";
+            reg = <0 2>;
+            powerdown-gpios = <&tlmm 89 0>;
+            vdd-supply = <&vreg_s10b_1p8>;
+            #thermal-sensor-cells = <0>;
+            #sound-dai-cells = <0>;
+        };
+    };
+
+...
index 5ea16b8ef93f120c39806980f2a835a5b8ce3b82..7e36e389e97643176942ae9dcb131f43babe0cac 100644 (file)
@@ -61,6 +61,13 @@ properties:
           - const: tx
           - const: rx
 
+  pinctrl-names:
+    oneOf:
+      - const: default
+      - items:
+          - const: bclk_on
+          - const: bclk_off
+
   power-domains:
     maxItems: 1
 
index e762c320b574d044da95d8ee2baa6e53afc6e0e1..2bc7f00ce4a2c50cdbc05893135c64368ed268e5 100644 (file)
@@ -47,6 +47,7 @@ properties:
     description: The bias voltage to be used in mVolts. The voltage can take
       values from 1.25V to 3V by 250mV steps. If this node is not mentioned
       or the value is unknown, then the value is set to 1.25V.
+    $ref: "/schemas/types.yaml#/definitions/uint32"
     enum: [ 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000 ]
 
   lrclk-strength:
diff --git a/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml b/Documentation/devicetree/bindings/sound/snps,designware-i2s.yaml
new file mode 100644 (file)
index 0000000..4b07958
--- /dev/null
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/snps,designware-i2s.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DesignWare I2S controller
+
+maintainers:
+  - Jose Abreu <joabreu@synopsys.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+          - const: canaan,k210-i2s
+          - const: snps,designware-i2s
+      - enum:
+          - snps,designware-i2s
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: |
+      The interrupt line number for the I2S controller. Add this
+      parameter if the I2S controller that you are using does not
+      support DMA.
+    maxItems: 1
+
+  clocks:
+    description: Sampling rate reference clock
+    maxItems: 1
+
+  clock-names:
+    const: i2sclk
+
+  resets:
+    maxItems: 1
+
+  dmas:
+    items:
+      - description: TX DMA Channel
+      - description: RX DMA Channel
+    minItems: 1
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+    minItems: 1
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: canaan,k210-i2s
+
+then:
+  properties:
+    "#sound-dai-cells":
+      const: 1
+
+else:
+  properties:
+    "#sound-dai-cells":
+      const: 0
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+
+oneOf:
+  - required:
+      - dmas
+      - dma-names
+  - required:
+      - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    soc_i2s: i2s@7ff90000 {
+      compatible = "snps,designware-i2s";
+      reg = <0x7ff90000 0x1000>;
+      clocks = <&scpi_i2sclk 0>;
+      clock-names = "i2sclk";
+      #sound-dai-cells = <0>;
+      dmas = <&dma0 5>;
+      dma-names = "tx";
+    };
index e7220e8b49f080673e2a25c18f8463bddb052913..15795f63b5a3ef295cf7677488e73e0e813eb519 100644 (file)
@@ -52,10 +52,6 @@ properties:
   DCVDD-supply:
     description: Digital core supply regulator for the DCVDD pin.
 
-  spi-max-frequency: true
-
-additionalProperties: false
-
 required:
   - reg
   - compatible
@@ -64,6 +60,11 @@ required:
   - DBVDD-supply
   - DCVDD-supply
 
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
 examples:
   - |
     spi {
index 502289d6338565f4f8425dcbbf24f46c32f0d042..306ad373a0022e0d0389fd31e53b6f3f48355b45 100644 (file)
@@ -116,7 +116,7 @@ On-line docs
     * Title: **Writing an ALSA Driver**
 
       :Author: Takashi Iwai <tiwai@suse.de>
-      :URL: http://www.alsa-project.org/~iwai/writing-an-alsa-driver/index.html
+      :URL: https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html
       :Date: 2005
       :Keywords: ALSA, sound, soundcard, driver, lowlevel, hardware.
       :Description: Advanced Linux Sound Architecture for developers,
index 57df149acafc527a713eca33ba021273081d1a5f..af973c4cac93097531ded40d35a9c4bafe6842bd 100644 (file)
@@ -132,7 +132,7 @@ The codec driver also supports the following ALSA PCM operations:-
   };
 
 Please refer to the ALSA driver PCM documentation for details.
-http://www.alsa-project.org/~iwai/writing-an-alsa-driver/
+https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html
 
 
 DAPM description
index c1badea53d3d377edc8b9a978160b8cceb5f83c9..7036630eaf016ce3a8eb62be9e357d83f49be07d 100644 (file)
@@ -46,7 +46,7 @@ snd_soc_component_driver:-
   };
 
 Please refer to the ALSA driver documentation for details of audio DMA.
-http://www.alsa-project.org/~iwai/writing-an-alsa-driver/
+https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html
 
 An example DMA driver is soc/pxa/pxa2xx-pcm.c
 
index f692bd93d6d0eae7af2f411e32c2450e7923bc48..272167f944b9609091ab3778d2dc5195485c17a2 100644 (file)
@@ -4912,6 +4912,7 @@ S:        Maintained
 F:     Documentation/devicetree/bindings/sound/cirrus,cs*
 F:     include/dt-bindings/sound/cs*
 F:     sound/pci/hda/cs*
+F:     sound/pci/hda/hda_cs_dsp_ctl.*
 F:     sound/soc/codecs/cs*
 
 CIRRUS LOGIC DSP FIRMWARE DRIVER
@@ -16579,6 +16580,9 @@ M:      Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
 M:     Banajit Goswami <bgoswami@quicinc.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
+F:     include/dt-bindings/sound/qcom,wcd9335.h
+F:     sound/soc/codecs/lpass-rx-macro.*
+F:     sound/soc/codecs/lpass-tx-macro.*
 F:     sound/soc/codecs/lpass-va-macro.c
 F:     sound/soc/codecs/lpass-wsa-macro.*
 F:     sound/soc/codecs/msm8916-wcd-analog.c
@@ -16586,7 +16590,9 @@ F:      sound/soc/codecs/msm8916-wcd-digital.c
 F:     sound/soc/codecs/wcd9335.*
 F:     sound/soc/codecs/wcd934x.c
 F:     sound/soc/codecs/wcd-clsh-v2.*
+F:     sound/soc/codecs/wcd-mbhc-v2.*
 F:     sound/soc/codecs/wsa881x.c
+F:     sound/soc/codecs/wsa883x.c
 F:     sound/soc/qcom/
 
 QCOM EMBEDDED USB DEBUGGER (EUD)
index b100e6ca9bb427775f60376e9844a637ac2333bc..42cec8120f18e513d60bed04c3d1b1a389f26864 100644 (file)
@@ -1722,6 +1722,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
                {"INT3515", },
                /* Non-conforming _HID for Cirrus Logic already released */
                {"CLSA0100", },
+               {"CLSA0101", },
        /*
         * Some ACPI devs contain SerialBus resources even though they are not
         * attached to a serial bus at all.
index 3a9773a09e199ad884b7954e1dfb24812937ed2a..5a7b8065e77ffd73f4d1b339571fc5e12d9d58f7 100644 (file)
@@ -291,6 +291,44 @@ int acpi_get_local_address(acpi_handle handle, u32 *addr)
 }
 EXPORT_SYMBOL(acpi_get_local_address);
 
+#define ACPI_MAX_SUB_BUF_SIZE  9
+
+const char *acpi_get_subsystem_id(acpi_handle handle)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+       const char *sub;
+       size_t len;
+
+       status = acpi_evaluate_object(handle, METHOD_NAME__SUB, NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               acpi_handle_debug(handle, "Reading ACPI _SUB failed: %#x\n", status);
+               return ERR_PTR(-ENODATA);
+       }
+
+       obj = buffer.pointer;
+       if (obj->type == ACPI_TYPE_STRING) {
+               len = strlen(obj->string.pointer);
+               if (len < ACPI_MAX_SUB_BUF_SIZE && len > 0) {
+                       sub = kstrdup(obj->string.pointer, GFP_KERNEL);
+                       if (!sub)
+                               sub = ERR_PTR(-ENOMEM);
+               } else {
+                       acpi_handle_err(handle, "ACPI _SUB Length %zu is Invalid\n", len);
+                       sub = ERR_PTR(-ENODATA);
+               }
+       } else {
+               acpi_handle_warn(handle, "Warning ACPI _SUB did not return a string\n");
+               sub = ERR_PTR(-ENODATA);
+       }
+
+       acpi_os_free(buffer.pointer);
+
+       return sub;
+}
+EXPORT_SYMBOL_GPL(acpi_get_subsystem_id);
+
 acpi_status
 acpi_evaluate_reference(acpi_handle handle,
                        acpi_string pathname,
index 7dad6f57d97042cc1a13b48a58c58e3938465e0f..81cc3d0f6eec1834eff9896d15ebcfd2540dff41 100644 (file)
@@ -2725,6 +2725,9 @@ void cs_dsp_stop(struct cs_dsp *dsp)
 
        mutex_lock(&dsp->pwr_lock);
 
+       if (dsp->client_ops->pre_stop)
+               dsp->client_ops->pre_stop(dsp);
+
        dsp->running = false;
 
        if (dsp->ops->stop_core)
@@ -3177,6 +3180,110 @@ static const struct cs_dsp_ops cs_dsp_halo_ops = {
        .stop_core = cs_dsp_halo_stop_core,
 };
 
+/**
+ * cs_dsp_chunk_write() - Format data to a DSP memory chunk
+ * @ch: Pointer to the chunk structure
+ * @nbits: Number of bits to write
+ * @val: Value to write
+ *
+ * This function sequentially writes values into the format required for DSP
+ * memory, it handles both inserting of the padding bytes and converting to
+ * big endian. Note that data is only committed to the chunk when a whole DSP
+ * words worth of data is available.
+ *
+ * Return: Zero for success, a negative number on error.
+ */
+int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val)
+{
+       int nwrite, i;
+
+       nwrite = min(CS_DSP_DATA_WORD_BITS - ch->cachebits, nbits);
+
+       ch->cache <<= nwrite;
+       ch->cache |= val >> (nbits - nwrite);
+       ch->cachebits += nwrite;
+       nbits -= nwrite;
+
+       if (ch->cachebits == CS_DSP_DATA_WORD_BITS) {
+               if (cs_dsp_chunk_end(ch))
+                       return -ENOSPC;
+
+               ch->cache &= 0xFFFFFF;
+               for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
+                       *ch->data++ = (ch->cache & 0xFF000000) >> CS_DSP_DATA_WORD_BITS;
+
+               ch->bytes += sizeof(ch->cache);
+               ch->cachebits = 0;
+       }
+
+       if (nbits)
+               return cs_dsp_chunk_write(ch, nbits, val);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cs_dsp_chunk_write);
+
+/**
+ * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk
+ * @ch: Pointer to the chunk structure
+ *
+ * As cs_dsp_chunk_write only writes data when a whole DSP word is ready to
+ * be written out it is possible that some data will remain in the cache, this
+ * function will pad that data with zeros upto a whole DSP word and write out.
+ *
+ * Return: Zero for success, a negative number on error.
+ */
+int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch)
+{
+       if (!ch->cachebits)
+               return 0;
+
+       return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0);
+}
+EXPORT_SYMBOL_GPL(cs_dsp_chunk_flush);
+
+/**
+ * cs_dsp_chunk_read() - Parse data from a DSP memory chunk
+ * @ch: Pointer to the chunk structure
+ * @nbits: Number of bits to read
+ *
+ * This function sequentially reads values from a DSP memory formatted buffer,
+ * it handles both removing of the padding bytes and converting from big endian.
+ *
+ * Return: A negative number is returned on error, otherwise the read value.
+ */
+int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits)
+{
+       int nread, i;
+       u32 result;
+
+       if (!ch->cachebits) {
+               if (cs_dsp_chunk_end(ch))
+                       return -ENOSPC;
+
+               ch->cache = 0;
+               ch->cachebits = CS_DSP_DATA_WORD_BITS;
+
+               for (i = 0; i < sizeof(ch->cache); i++, ch->cache <<= BITS_PER_BYTE)
+                       ch->cache |= *ch->data++;
+
+               ch->bytes += sizeof(ch->cache);
+       }
+
+       nread = min(ch->cachebits, nbits);
+       nbits -= nread;
+
+       result = ch->cache >> ((sizeof(ch->cache) * BITS_PER_BYTE) - nread);
+       ch->cache <<= nread;
+       ch->cachebits -= nread;
+
+       if (nbits)
+               result = (result << nbits) | cs_dsp_chunk_read(ch, nbits);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(cs_dsp_chunk_read);
+
 MODULE_DESCRIPTION("Cirrus Logic DSP Support");
 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
 MODULE_LICENSE("GPL v2");
index cb255a99170c9e3829ed530cb0e5d099bf8c54e3..3c071f814455522dc0b27fabbdf6d27793dea4f4 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
+static const char * const adsp_mbox_ch_names[MTK_ADSP_MBOX_NUM] = { "rx", "tx" };
+
 /*
  * mtk_adsp_ipc_send - send ipc cmd to MTK ADSP
  *
@@ -72,7 +74,6 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev)
        struct mtk_adsp_ipc *adsp_ipc;
        struct mtk_adsp_chan *adsp_chan;
        struct mbox_client *cl;
-       char *chan_name;
        int ret;
        int i, j;
 
@@ -83,12 +84,6 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
-               chan_name = kasprintf(GFP_KERNEL, "mbox%d", i);
-               if (!chan_name) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
                adsp_chan = &adsp_ipc->chans[i];
                cl = &adsp_chan->cl;
                cl->dev = dev->parent;
@@ -99,17 +94,20 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev)
 
                adsp_chan->ipc = adsp_ipc;
                adsp_chan->idx = i;
-               adsp_chan->ch = mbox_request_channel_byname(cl, chan_name);
+               adsp_chan->ch = mbox_request_channel_byname(cl, adsp_mbox_ch_names[i]);
                if (IS_ERR(adsp_chan->ch)) {
                        ret = PTR_ERR(adsp_chan->ch);
                        if (ret != -EPROBE_DEFER)
-                               dev_err(dev, "Failed to request mbox chan %d ret %d\n",
-                                       i, ret);
-                       goto out_free;
-               }
+                               dev_err(dev, "Failed to request mbox chan %s ret %d\n",
+                                       adsp_mbox_ch_names[i], ret);
+
+                       for (j = 0; j < i; j++) {
+                               adsp_chan = &adsp_ipc->chans[j];
+                               mbox_free_channel(adsp_chan->ch);
+                       }
 
-               dev_dbg(dev, "request mbox chan %s\n", chan_name);
-               kfree(chan_name);
+                       return ret;
+               }
        }
 
        adsp_ipc->dev = dev;
@@ -117,16 +115,6 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev)
        dev_dbg(dev, "MTK ADSP IPC initialized\n");
 
        return 0;
-
-out_free:
-       kfree(chan_name);
-out:
-       for (j = 0; j < i; j++) {
-               adsp_chan = &adsp_ipc->chans[j];
-               mbox_free_channel(adsp_chan->ch);
-       }
-
-       return ret;
 }
 
 static int mtk_adsp_ipc_remove(struct platform_device *pdev)
index 281f8a9ba4fd214989cd2a143bbe1c2414508709..7ab38d734ad67661c8882e975eed04b8365e4acc 100644 (file)
@@ -550,8 +550,9 @@ static int sii902x_audio_hw_params(struct device *dev, void *data,
        unsigned long mclk_rate;
        int i, ret;
 
-       if (daifmt->bit_clk_master || daifmt->frame_clk_master) {
-               dev_dbg(dev, "%s: I2S master mode not supported\n", __func__);
+       if (daifmt->bit_clk_provider || daifmt->frame_clk_provider) {
+               dev_dbg(dev, "%s: I2S clock provider mode not supported\n",
+                       __func__);
                return -EINVAL;
        }
 
index f50b47ac11a82ec88af0aa77de2b7dc4e1104082..a2f0860b20bb9a9993731953d74a3835ea567552 100644 (file)
@@ -45,7 +45,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
        u8 inputclkfs = 0;
 
        /* it cares I2S only */
-       if (fmt->bit_clk_master | fmt->frame_clk_master) {
+       if (fmt->bit_clk_provider | fmt->frame_clk_provider) {
                dev_err(dev, "unsupported clock settings\n");
                return -EINVAL;
        }
index 7655142a4651cadc40d25e5fb6f719aa28dec516..10b0036f8a2e2d49f10daa2843018e3edf8c6e8a 100644 (file)
@@ -1594,12 +1594,12 @@ static int hdmi_audio_hw_params(struct device *dev, void *data,
        struct hdmi_context *hdata = dev_get_drvdata(dev);
 
        if (daifmt->fmt != HDMI_I2S || daifmt->bit_clk_inv ||
-           daifmt->frame_clk_inv || daifmt->bit_clk_master ||
-           daifmt->frame_clk_master) {
+           daifmt->frame_clk_inv || daifmt->bit_clk_provider ||
+           daifmt->frame_clk_provider) {
                dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
                        daifmt->bit_clk_inv, daifmt->frame_clk_inv,
-                       daifmt->bit_clk_master,
-                       daifmt->frame_clk_master);
+                       daifmt->bit_clk_provider,
+                       daifmt->frame_clk_provider);
                return -EINVAL;
        }
 
index 7c4455541dbb31892bd52c9e017140f8f63d7228..f8eb6f69be05757b54e359c5e8a9e72a0dccb177 100644 (file)
@@ -1096,11 +1096,11 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
 
        if (!spdif &&
            (daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
-            daifmt->bit_clk_master || daifmt->frame_clk_master)) {
+            daifmt->bit_clk_provider || daifmt->frame_clk_provider)) {
                dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
                        daifmt->bit_clk_inv, daifmt->frame_clk_inv,
-                       daifmt->bit_clk_master,
-                       daifmt->frame_clk_master);
+                       daifmt->bit_clk_provider,
+                       daifmt->frame_clk_provider);
                return -EINVAL;
        }
 
index 61a034a0176448bf257228354fe280547eee4b41..cb82622877d20fd29bc0c2fb990322a752913e76 100644 (file)
@@ -1176,12 +1176,12 @@ static int hdmi_audio_hw_params(struct device *dev,
        DRM_DEBUG_DRIVER("\n");
 
        if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv ||
-           daifmt->frame_clk_inv || daifmt->bit_clk_master ||
-           daifmt->frame_clk_master) {
+           daifmt->frame_clk_inv || daifmt->bit_clk_provider ||
+           daifmt->frame_clk_provider) {
                dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
                        daifmt->bit_clk_inv, daifmt->frame_clk_inv,
-                       daifmt->bit_clk_master,
-                       daifmt->frame_clk_master);
+                       daifmt->bit_clk_provider,
+                       daifmt->frame_clk_provider);
                return -EINVAL;
        }
 
index 6ab83296b0e4b87d5c80844e03a5c9411e5d06c6..592c3b5d03e6e1f296dace9bf27b0a39c8a42dd9 100644 (file)
@@ -2003,6 +2003,7 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
 
 static const struct snd_soc_component_driver vc4_hdmi_audio_cpu_dai_comp = {
        .name = "vc4-hdmi-cpu-dai-component",
+       .legacy_dai_naming = 1,
 };
 
 static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai)
index 0de7acdf58a73eaac90626e6f646c8479be61c91..f66ac14cffad5971d7dd9d05fd2ced2af9acfebb 100644 (file)
@@ -2517,7 +2517,6 @@ static struct snd_soc_component_driver tda1997x_codec_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int tda1997x_probe(struct i2c_client *client,
index 95ce292994ccb6f983917b3db9695e0cf3a961d3..89d1d0d021fc72ab7a3724fc625fcb25bf0ec2bd 100644 (file)
@@ -1004,9 +1004,18 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sn
 {
        struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
        struct sdw_intel *sdw = cdns_to_intel(cdns);
+       struct sdw_intel_link_res *res = sdw->link_res;
        struct sdw_cdns_dma_data *dma;
        int ret = 0;
 
+       /*
+        * The .trigger callback is used to send required IPC to audio
+        * firmware. The .free_stream callback will still be called
+        * by intel_free_stream() in the TRIGGER_SUSPEND case.
+        */
+       if (res->ops && res->ops->trigger)
+               res->ops->trigger(dai, cmd, substream->stream);
+
        dma = snd_soc_dai_get_dma_data(dai, substream);
        if (!dma) {
                dev_err(dai->dev, "failed to get dma data in %s\n",
@@ -1114,9 +1123,10 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
 };
 
 static const struct snd_soc_component_driver dai_component = {
-       .name           = "soundwire",
-       .probe          = intel_component_probe,
-       .suspend        = intel_component_dais_suspend
+       .name                   = "soundwire",
+       .probe                  = intel_component_probe,
+       .suspend                = intel_component_dais_suspend,
+       .legacy_dai_naming      = 1,
 };
 
 static int intel_create_dai(struct sdw_cdns *cdns,
diff --git a/include/dt-bindings/sound/qcom,wcd9335.h b/include/dt-bindings/sound/qcom,wcd9335.h
new file mode 100644 (file)
index 0000000..f5e9f1d
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef __DT_SOUND_QCOM_WCD9335_H
+#define __DT_SOUND_QCOM_WCD9335_H
+
+#define AIF1_PB                 0
+#define AIF1_CAP                1
+#define AIF2_PB                 2
+#define AIF2_CAP                3
+#define AIF3_PB                 4
+#define AIF3_CAP                5
+#define AIF4_PB                 6
+#define NUM_CODEC_DAIS          7
+
+#endif
index f6d4539c3895d8a0b19fcbffcb17eaa43e2ab9a0..7ee10b2848d5e50d5e1ab0ac2d9d359f33103233 100644 (file)
@@ -764,6 +764,7 @@ static inline u64 acpi_arch_get_root_pointer(void)
 #endif
 
 int acpi_get_local_address(acpi_handle handle, u32 *addr);
+const char *acpi_get_subsystem_id(acpi_handle handle);
 
 #else  /* !CONFIG_ACPI */
 
@@ -1025,6 +1026,11 @@ static inline int acpi_get_local_address(acpi_handle handle, u32 *addr)
        return -ENODEV;
 }
 
+static inline const char *acpi_get_subsystem_id(acpi_handle handle)
+{
+       return ERR_PTR(-ENODEV);
+}
+
 static inline int acpi_register_wakeup_handler(int wake_irq,
        bool (*wakeup)(void *context), void *context)
 {
index 30055706cce214d7ab918d2509a05f09f99aad02..cad828e21c72bc781e9d8da60dc3cf773bc4384e 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __CS_DSP_H
 #define __CS_DSP_H
 
+#include <linux/bits.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/list.h>
@@ -34,6 +35,7 @@
 #define CS_ADSP2_REGION_ALL (CS_ADSP2_REGION_0 | CS_ADSP2_REGION_1_9)
 
 #define CS_DSP_DATA_WORD_SIZE                3
+#define CS_DSP_DATA_WORD_BITS                (3 * BITS_PER_BYTE)
 
 #define CS_DSP_ACKED_CTL_TIMEOUT_MS          100
 #define CS_DSP_ACKED_CTL_N_QUICKPOLLS        10
@@ -189,7 +191,8 @@ struct cs_dsp {
  * @control_remove:    Called under the pwr_lock when a control is destroyed
  * @pre_run:           Called under the pwr_lock by cs_dsp_run() before the core is started
  * @post_run:          Called under the pwr_lock by cs_dsp_run() after the core is started
- * @post_stop:         Called under the pwr_lock by cs_dsp_stop()
+ * @pre_stop:          Called under the pwr_lock by cs_dsp_stop() before the core is stopped
+ * @post_stop:         Called under the pwr_lock by cs_dsp_stop() after the core is stopped
  * @watchdog_expired:  Called when a watchdog expiry is detected
  *
  * These callbacks give the cs_dsp client an opportunity to respond to events
@@ -200,6 +203,7 @@ struct cs_dsp_client_ops {
        void (*control_remove)(struct cs_dsp_coeff_ctl *ctl);
        int (*pre_run)(struct cs_dsp *dsp);
        int (*post_run)(struct cs_dsp *dsp);
+       void (*pre_stop)(struct cs_dsp *dsp);
        void (*post_stop)(struct cs_dsp *dsp);
        void (*watchdog_expired)(struct cs_dsp *dsp);
 };
@@ -250,4 +254,75 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp,
 
 const char *cs_dsp_mem_region_name(unsigned int type);
 
+/**
+ * struct cs_dsp_chunk - Describes a buffer holding data formatted for the DSP
+ * @data:      Pointer to underlying buffer memory
+ * @max:       Pointer to end of the buffer memory
+ * @bytes:     Number of bytes read/written into the memory chunk
+ * @cache:     Temporary holding data as it is formatted
+ * @cachebits: Number of bits of data currently in cache
+ */
+struct cs_dsp_chunk {
+       u8 *data;
+       u8 *max;
+       int bytes;
+
+       u32 cache;
+       int cachebits;
+};
+
+/**
+ * cs_dsp_chunk() - Create a DSP memory chunk
+ * @data: Pointer to the buffer that will be used to store data
+ * @size: Size of the buffer in bytes
+ *
+ * Return: A cs_dsp_chunk structure
+ */
+static inline struct cs_dsp_chunk cs_dsp_chunk(void *data, int size)
+{
+       struct cs_dsp_chunk ch = {
+               .data = data,
+               .max = data + size,
+       };
+
+       return ch;
+}
+
+/**
+ * cs_dsp_chunk_end() - Check if a DSP memory chunk is full
+ * @ch: Pointer to the chunk structure
+ *
+ * Return: True if the whole buffer has been read/written
+ */
+static inline bool cs_dsp_chunk_end(struct cs_dsp_chunk *ch)
+{
+       return ch->data == ch->max;
+}
+
+/**
+ * cs_dsp_chunk_bytes() - Number of bytes written/read from a DSP memory chunk
+ * @ch: Pointer to the chunk structure
+ *
+ * Return: Number of bytes read/written to the buffer
+ */
+static inline int cs_dsp_chunk_bytes(struct cs_dsp_chunk *ch)
+{
+       return ch->bytes;
+}
+
+/**
+ * cs_dsp_chunk_valid_addr() - Check if an address is in a DSP memory chunk
+ * @ch: Pointer to the chunk structure
+ *
+ * Return: True if the given address is within the buffer
+ */
+static inline bool cs_dsp_chunk_valid_addr(struct cs_dsp_chunk *ch, void *addr)
+{
+       return (u8 *)addr >= ch->data && (u8 *)addr < ch->max;
+}
+
+int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val);
+int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch);
+int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits);
+
 #endif
index 67e0d3e750b5c90884c3e03cd63be024fab50a3c..ec16ae49e6a43c3a54cf9c8d2b377a36b5dca12e 100644 (file)
@@ -9,6 +9,8 @@
 
 #define SDW_SHIM_BASE                  0x2C000
 #define SDW_ALH_BASE                   0x2C800
+#define SDW_SHIM_BASE_ACE              0x38000
+#define SDW_ALH_BASE_ACE               0x24000
 #define SDW_LINK_BASE                  0x30000
 #define SDW_LINK_SIZE                  0x10000
 
@@ -119,6 +121,7 @@ struct sdw_intel_ops {
                             struct sdw_intel_stream_params_data *params_data);
        int (*free_stream)(struct device *dev,
                           struct sdw_intel_stream_free_data *free_data);
+       int (*trigger)(struct snd_soc_dai *dai, int cmd, int stream);
 };
 
 /**
index 985c51a8fb7487fa1453f39fc5b9d6b0d88fd390..eae443ba79ba5522c29ca7e1c4e0362e6f26889e 100644 (file)
@@ -23,7 +23,7 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
                                    unsigned int __user *tlv);
 
 /* internal flag for skipping validations */
-#ifdef CONFIG_SND_CTL_VALIDATION
+#ifdef CONFIG_SND_CTL_DEBUG
 #define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK       (1 << 24)
 #define snd_ctl_skip_validation(info) \
        ((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK)
@@ -109,7 +109,7 @@ struct snd_ctl_file {
        int preferred_subdevice[SND_CTL_SUBDEV_ITEMS];
        wait_queue_head_t change_sleep;
        spinlock_t read_lock;
-       struct fasync_struct *fasync;
+       struct snd_fasync *fasync;
        int subscribed;                 /* read interface is activated */
        struct list_head events;        /* waiting events for read */
 };
index 6d4cc49584c6372a127525a9b47710d4bcd64d8b..4365c35d038b4cd6fe6ee675d4dbc5bc4bd67739 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pm.h>                  /* pm_message_t */
 #include <linux/stringify.h>
 #include <linux/printk.h>
+#include <linux/xarray.h>
 
 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -103,6 +104,11 @@ struct snd_card {
        size_t user_ctl_alloc_size;     // current memory allocation by user controls.
        struct list_head controls;      /* all controls for this card */
        struct list_head ctl_files;     /* active control files */
+#ifdef CONFIG_SND_CTL_FAST_LOOKUP
+       struct xarray ctl_numids;       /* hash table for numids */
+       struct xarray ctl_hash;         /* hash table for ctl id matching */
+       bool ctl_hash_collision;        /* ctl_hash collision seen? */
+#endif
 
        struct snd_info_entry *proc_root;       /* root for soundcard specific files */
        struct proc_dir_entry *proc_root_link;  /* number link to real id */
@@ -501,4 +507,12 @@ snd_pci_quirk_lookup_id(u16 vendor, u16 device,
 }
 #endif
 
+/* async signal helpers */
+struct snd_fasync;
+
+int snd_fasync_helper(int fd, struct file *file, int on,
+                     struct snd_fasync **fasyncp);
+void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll);
+void snd_fasync_free(struct snd_fasync *fasync);
+
 #endif /* __SOUND_CORE_H */
index 8972fa6976227084e710e9b9ef7200f623330141..9ac5918269a5da22217b9ff2d8eb2e9388315e17 100644 (file)
 #define CS35L41_BST_EN_DEFAULT         0x2
 #define CS35L41_AMP_EN_SHIFT           0
 #define CS35L41_AMP_EN_MASK            1
+#define CS35L41_VMON_EN_MASK           0x1000
+#define CS35L41_VMON_EN_SHIFT          12
+#define CS35L41_IMON_EN_MASK           0x2000
+#define CS35L41_IMON_EN_SHIFT          13
 
 #define CS35L41_PDN_DONE_MASK          0x00800000
 #define CS35L41_PDN_DONE_SHIFT         23
@@ -881,6 +885,9 @@ void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_
 int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
                              enum cs35l41_cspl_mbox_cmd cmd);
 int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap);
+int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap,
+                           enum cs35l41_boost_type b_type);
+int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap);
 int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
                       struct cs35l41_hw_cfg *hw_cfg);
 bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type);
index 38ea046e653c5f50488c90193f2a3112f006f37c..2df54cf02cb33c5bc332ae9b64a89b052fa7a454 100644 (file)
@@ -15,6 +15,8 @@
  * snd_pcm_substream_to_dma_direction - Get dma_transfer_direction for a PCM
  *   substream
  * @substream: PCM substream
+ *
+ * Return: DMA transfer direction
  */
 static inline enum dma_transfer_direction
 snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
index b7be300b6b18c69bd519e8f2c60cd683b6203250..6d3c82c4b6acdfea864576a2a3fc237379b6666b 100644 (file)
@@ -231,7 +231,6 @@ struct hda_codec {
        /* misc flags */
        unsigned int configured:1; /* codec was configured */
        unsigned int in_freeing:1; /* being released */
-       unsigned int registered:1; /* codec was registered */
        unsigned int display_power_control:1; /* needs display power */
        unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
                                             * status change
index 15f15075238d0b0216f517d81f6bb362b71df166..797bf67a164dbca813cd7045679e38215a7ca761 100644 (file)
@@ -93,6 +93,7 @@ struct hdac_device {
        bool lazy_cache:1;      /* don't wake up for writes */
        bool caps_overwriting:1; /* caps overwrite being in process */
        bool cache_coef:1;      /* cache COEF read/write too */
+       unsigned int registered:1; /* codec was registered */
 };
 
 /* device/driver type used for matching */
index 4fc733c8c570e3fa74fb17916996dbb64341283d..48ad33aba393bb49416a0f4a5089ab24a00f5056 100644 (file)
@@ -32,8 +32,8 @@ struct hdmi_codec_daifmt {
        } fmt;
        unsigned int bit_clk_inv:1;
        unsigned int frame_clk_inv:1;
-       unsigned int bit_clk_master:1;
-       unsigned int frame_clk_master:1;
+       unsigned int bit_clk_provider:1;
+       unsigned int frame_clk_provider:1;
        /* bit_fmt could be standard PCM format or
         * IEC958 encoded format. ALSA IEC958 plugin will pass
         * IEC958_SUBFRAME format to the underneath driver.
index e3060f48f10819d95238e92842742b844ce31975..58398d80c3de32c37caea0b4ed304039cc8ad87c 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef MADERA_CODEC_PDATA_H
 #define MADERA_CODEC_PDATA_H
 
-#include <linux/kernel.h>
+#include <linux/types.h>
 
 #define MADERA_MAX_INPUT               6
 #define MADERA_MAX_MUXED_CHANNELS      4
index 6b99310b5b8890bd7ceacbae4f347a30c6a0324f..8c48a5bce88c166026fdece07e60603eba733ef9 100644 (file)
@@ -399,7 +399,7 @@ struct snd_pcm_runtime {
        snd_pcm_uframes_t twake;        /* do transfer (!poll) wakeup if non-zero */
        wait_queue_head_t sleep;        /* poll sleep */
        wait_queue_head_t tsleep;       /* transfer sleep */
-       struct fasync_struct *fasync;
+       struct snd_fasync *fasync;
        bool stop_operating;            /* sync_stop will be called */
        struct mutex buffer_mutex;      /* protect for buffer changes */
        atomic_t buffer_accessing;      /* >0: in r/w operation, <0: blocked */
@@ -607,7 +607,7 @@ snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
  * snd_pcm_stream_linked - Check whether the substream is linked with others
  * @substream: substream to check
  *
- * Returns true if the given substream is being linked with others.
+ * Return: true if the given substream is being linked with others
  */
 static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream)
 {
@@ -673,7 +673,7 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
  * snd_pcm_running - Check whether the substream is in a running state
  * @substream: substream to check
  *
- * Returns true if the given substream is in the state RUNNING, or in the
+ * Return: true if the given substream is in the state RUNNING, or in the
  * state DRAINING for playback.
  */
 static inline int snd_pcm_running(struct snd_pcm_substream *substream)
@@ -687,6 +687,8 @@ static inline int snd_pcm_running(struct snd_pcm_substream *substream)
  * bytes_to_samples - Unit conversion of the size from bytes to samples
  * @runtime: PCM runtime instance
  * @size: size in bytes
+ *
+ * Return: the size in samples
  */
 static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t size)
 {
@@ -697,6 +699,8 @@ static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t
  * bytes_to_frames - Unit conversion of the size from bytes to frames
  * @runtime: PCM runtime instance
  * @size: size in bytes
+ *
+ * Return: the size in frames
  */
 static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime, ssize_t size)
 {
@@ -707,6 +711,8 @@ static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime,
  * samples_to_bytes - Unit conversion of the size from samples to bytes
  * @runtime: PCM runtime instance
  * @size: size in samples
+ *
+ * Return: the byte size
  */
 static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t size)
 {
@@ -717,6 +723,8 @@ static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t
  * frames_to_bytes - Unit conversion of the size from frames to bytes
  * @runtime: PCM runtime instance
  * @size: size in frames
+ *
+ * Return: the byte size
  */
 static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_sframes_t size)
 {
@@ -727,6 +735,8 @@ static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_s
  * frame_aligned - Check whether the byte size is aligned to frames
  * @runtime: PCM runtime instance
  * @bytes: size in bytes
+ *
+ * Return: true if aligned, or false if not
  */
 static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes)
 {
@@ -736,6 +746,8 @@ static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes)
 /**
  * snd_pcm_lib_buffer_bytes - Get the buffer size of the current PCM in bytes
  * @substream: PCM substream
+ *
+ * Return: buffer byte size
  */
 static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substream)
 {
@@ -746,6 +758,8 @@ static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substrea
 /**
  * snd_pcm_lib_period_bytes - Get the period size of the current PCM in bytes
  * @substream: PCM substream
+ *
+ * Return: period byte size
  */
 static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substream)
 {
@@ -758,6 +772,8 @@ static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substrea
  * @runtime: PCM runtime instance
  *
  * Result is between 0 ... (boundary - 1)
+ *
+ * Return: available frame size
  */
 static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime)
 {
@@ -774,6 +790,8 @@ static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *r
  * @runtime: PCM runtime instance
  *
  * Result is between 0 ... (boundary - 1)
+ *
+ * Return: available frame size
  */
 static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime)
 {
@@ -786,6 +804,8 @@ static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *ru
 /**
  * snd_pcm_playback_hw_avail - Get the queued space for playback
  * @runtime: PCM runtime instance
+ *
+ * Return: available frame size
  */
 static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime)
 {
@@ -795,6 +815,8 @@ static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime
 /**
  * snd_pcm_capture_hw_avail - Get the free space for capture
  * @runtime: PCM runtime instance
+ *
+ * Return: available frame size
  */
 static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime *runtime)
 {
@@ -934,6 +956,8 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
 /**
  * params_channels - Get the number of channels from the hw params
  * @p: hw params
+ *
+ * Return: the number of channels
  */
 static inline unsigned int params_channels(const struct snd_pcm_hw_params *p)
 {
@@ -943,6 +967,8 @@ static inline unsigned int params_channels(const struct snd_pcm_hw_params *p)
 /**
  * params_rate - Get the sample rate from the hw params
  * @p: hw params
+ *
+ * Return: the sample rate
  */
 static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
 {
@@ -952,6 +978,8 @@ static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
 /**
  * params_period_size - Get the period size (in frames) from the hw params
  * @p: hw params
+ *
+ * Return: the period size in frames
  */
 static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
 {
@@ -961,6 +989,8 @@ static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
 /**
  * params_periods - Get the number of periods from the hw params
  * @p: hw params
+ *
+ * Return: the number of periods
  */
 static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
 {
@@ -970,6 +1000,8 @@ static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
 /**
  * params_buffer_size - Get the buffer size (in frames) from the hw params
  * @p: hw params
+ *
+ * Return: the buffer size in frames
  */
 static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
 {
@@ -979,6 +1011,8 @@ static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
 /**
  * params_buffer_bytes - Get the buffer size (in bytes) from the hw params
  * @p: hw params
+ *
+ * Return: the buffer size in bytes
  */
 static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p)
 {
@@ -1241,6 +1275,8 @@ int snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
  * only the given sized buffer and doesn't allow re-allocation nor dynamic
  * allocation of a larger buffer unlike the standard one.
  * The function may return -ENOMEM error, hence the caller must check it.
+ *
+ * Return: zero if successful, or a negative error code
  */
 static inline int __must_check
 snd_pcm_set_fixed_buffer(struct snd_pcm_substream *substream, int type,
@@ -1259,6 +1295,8 @@ snd_pcm_set_fixed_buffer(struct snd_pcm_substream *substream, int type,
  * Apply the set up of the fixed buffer via snd_pcm_set_fixed_buffer() for
  * all substream.  If any of allocation fails, it returns -ENOMEM, hence the
  * caller must check the return value.
+ *
+ * Return: zero if successful, or a negative error code
  */
 static inline int __must_check
 snd_pcm_set_fixed_buffer_all(struct snd_pcm *pcm, int type,
@@ -1315,6 +1353,8 @@ static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
  * snd_pcm_sgbuf_get_addr - Get the DMA address at the corresponding offset
  * @substream: PCM substream
  * @ofs: byte offset
+ *
+ * Return: DMA address
  */
 static inline dma_addr_t
 snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
@@ -1328,6 +1368,8 @@ snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
  * @substream: PCM substream
  * @ofs: byte offset
  * @size: byte size to examine
+ *
+ * Return: chunk size
  */
 static inline unsigned int
 snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
@@ -1392,6 +1434,20 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
 
 const char *snd_pcm_format_name(snd_pcm_format_t format);
 
+/**
+ * snd_pcm_direction_name - Get a string naming the direction of a stream
+ * @direction: Stream's direction, one of SNDRV_PCM_STREAM_XXX
+ *
+ * Returns a string naming the direction of the stream.
+ */
+static inline const char *snd_pcm_direction_name(int direction)
+{
+       if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+               return "Playback";
+       else
+               return "Capture";
+}
+
 /**
  * snd_pcm_stream_str - Get a string naming the direction of a stream
  * @substream: the pcm substream instance
@@ -1400,10 +1456,7 @@ const char *snd_pcm_format_name(snd_pcm_format_t format);
  */
 static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
 {
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return "Playback";
-       else
-               return "Capture";
+       return snd_pcm_direction_name(substream->stream);
 }
 
 /*
@@ -1430,6 +1483,8 @@ struct snd_pcm_chmap {
  * snd_pcm_chmap_substream - get the PCM substream assigned to the given chmap info
  * @info: chmap information
  * @idx: the substream number index
+ *
+ * Return: the matched PCM substream, or NULL if not found
  */
 static inline struct snd_pcm_substream *
 snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx)
@@ -1460,6 +1515,8 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
 /**
  * pcm_format_to_bits - Strong-typed conversion of pcm_format to bitwise
  * @pcm_format: PCM format
+ *
+ * Return: 64bit mask corresponding to the given PCM format
  */
 static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
 {
index 7a08ed2acd609f7a969a4d480cb5a2739939d677..e1f59b2940aff0e9fe6f07463818ec9b75af2aef 100644 (file)
@@ -63,7 +63,6 @@ struct snd_rawmidi_runtime {
        size_t xruns;           /* over/underruns counter */
        int buffer_ref;         /* buffer reference count */
        /* misc */
-       spinlock_t lock;
        wait_queue_head_t sleep;
        /* event handler (new bytes, input only) */
        void (*event)(struct snd_rawmidi_substream *substream);
@@ -85,6 +84,7 @@ struct snd_rawmidi_substream {
        unsigned int clock_type;        /* clock source to use for input framing */
        int use_count;                  /* use counter (for output) */
        size_t bytes;
+       spinlock_t lock;
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *pstr;
        char name[32];
@@ -156,10 +156,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count);
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                         unsigned char *buffer, int count);
-int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
-                             unsigned char *buffer, int count);
-int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
-                              int count);
 int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
 
 /* main midi functions */
index 8faa649f712b80644c6d9ed0de9d24f92bcf6043..ab55f40896e0a48343afa240c0954549841d21d3 100644 (file)
@@ -51,7 +51,6 @@ struct prop_nums {
        int cpus;
        int codecs;
        int platforms;
-       int c2c;
 };
 
 struct asoc_simple_priv {
@@ -64,7 +63,6 @@ struct asoc_simple_priv {
                struct snd_soc_dai_link_component *platforms;
                struct asoc_simple_data adata;
                struct snd_soc_codec_conf *codec_conf;
-               struct snd_soc_pcm_stream *c2c_conf;
                struct prop_nums num;
                unsigned int mclk_fs;
        } *dai_props;
@@ -75,7 +73,6 @@ struct asoc_simple_priv {
        struct snd_soc_dai_link_component *dlcs;
        struct snd_soc_dai_link_component dummy;
        struct snd_soc_codec_conf *codec_conf;
-       struct snd_soc_pcm_stream *c2c_conf;
        struct gpio_desc *pa_gpio;
        const struct snd_soc_ops *ops;
        unsigned int dpcm_selectable:1;
@@ -173,7 +170,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo
 void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
                                  int is_single_links);
 
-int asoc_simple_clean_reference(struct snd_soc_card *card);
+void asoc_simple_clean_reference(struct snd_soc_card *card);
 
 void asoc_simple_convert_fixup(struct asoc_simple_data *data,
                                      struct snd_pcm_hw_params *params);
index 59551b1f22f3c50e5ffabaf5e42d272485ccc8d5..bc7fd46ec2bc8c960336a65a35155ba349e465bd 100644 (file)
@@ -30,6 +30,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[];
 
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
@@ -37,6 +38,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[];
 
 /*
  * generic table used for HDA codec-based platforms, possibly with
index df08573bd80cdc7f7664df56b352ffadac3024df..9d31a5c0db33c2ff36a18b8629430c218884e889 100644 (file)
@@ -29,6 +29,7 @@ int snd_soc_card_resume_post(struct snd_soc_card *card);
 
 int snd_soc_card_probe(struct snd_soc_card *card);
 int snd_soc_card_late_probe(struct snd_soc_card *card);
+void snd_soc_card_fixup_controls(struct snd_soc_card *card);
 int snd_soc_card_remove(struct snd_soc_card *card);
 
 int snd_soc_card_set_bias_level(struct snd_soc_card *card,
index 5a764c3099d3ead15ca0d97eccc6e6768621dac0..c26ffb033777a18df1104f754f2a0f217acd0ce7 100644 (file)
@@ -179,7 +179,7 @@ struct snd_soc_component_driver {
         * analogue).
         */
        unsigned int endianness:1;
-       unsigned int non_legacy_dai_naming:1;
+       unsigned int legacy_dai_naming:1;
 
        /* this component uses topology and ignore machine driver FEs */
        const char *ignore_machine;
@@ -348,11 +348,6 @@ static inline int snd_soc_component_cache_sync(
        return regcache_sync(component->regmap);
 }
 
-static inline int snd_soc_component_is_codec(struct snd_soc_component *component)
-{
-       return component->driver->non_legacy_dai_naming;
-}
-
 void snd_soc_component_set_aux(struct snd_soc_component *component,
                               struct snd_soc_aux_dev *aux);
 int snd_soc_component_init(struct snd_soc_component *component);
index bbd821d2df9ca976c973398ea7a60da71efbbab8..ea75096720864a1f2598d4aeb555f36249804c69 100644 (file)
@@ -124,6 +124,12 @@ struct snd_compr_stream;
 #define SND_SOC_DAIFMT_CBM_CFS         SND_SOC_DAIFMT_CBP_CFC
 #define SND_SOC_DAIFMT_CBS_CFS         SND_SOC_DAIFMT_CBC_CFC
 
+/* when passed to set_fmt directly indicate if the device is provider or consumer */
+#define SND_SOC_DAIFMT_BP_FP           SND_SOC_DAIFMT_CBP_CFP
+#define SND_SOC_DAIFMT_BC_FP           SND_SOC_DAIFMT_CBC_CFP
+#define SND_SOC_DAIFMT_BP_FC           SND_SOC_DAIFMT_CBP_CFC
+#define SND_SOC_DAIFMT_BC_FC           SND_SOC_DAIFMT_CBC_CFC
+
 /* Describes the possible PCM format */
 #define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT   48
 #define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK    (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
index b276dcb5d4e8b1f827ab52c9773ea90c228f484a..aad24a1d32767a3d8a5c082afce63ca88e68c146 100644 (file)
        .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
                                          max, invert, 0) }
+#define SOC_DOUBLE_SX_TLV(xname, xreg, shift_left, shift_right, xmin, xmax, tlv_array) \
+{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+       SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p  = (tlv_array), \
+       .info = snd_soc_info_volsw_sx, \
+       .get = snd_soc_get_volsw_sx, \
+       .put = snd_soc_put_volsw_sx, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .rreg = xreg, \
+               .shift = shift_left, .rshift = shift_right, \
+               .max = xmax, .min = xmin} }
 #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -414,7 +426,7 @@ enum snd_soc_pcm_subclass {
 };
 
 int snd_soc_register_card(struct snd_soc_card *card);
-int snd_soc_unregister_card(struct snd_soc_card *card);
+void snd_soc_unregister_card(struct snd_soc_card *card);
 int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
 #ifdef CONFIG_PM_SLEEP
 int snd_soc_suspend(struct device *dev);
@@ -914,6 +926,7 @@ struct snd_soc_card {
 
        int (*probe)(struct snd_soc_card *card);
        int (*late_probe)(struct snd_soc_card *card);
+       void (*fixup_controls)(struct snd_soc_card *card);
        int (*remove)(struct snd_soc_card *card);
 
        /* the pre and post PM functions are used to do any PM work before and
index 1a82a0db5e7f065baf833454f1b0b3be506928fe..367dccfea7ade86d47eef46b8cc1cba54c4e3f1a 100644 (file)
@@ -138,6 +138,7 @@ struct sof_dev_desc {
 
        struct snd_sof_dsp_ops *ops;
        int (*ops_init)(struct snd_sof_dev *sdev);
+       void (*ops_free)(struct snd_sof_dev *sdev);
 };
 
 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd);
index 90d09dbdd709b02f4a85aca779ddef45bed7fd9c..92f45c180b7cce419523b4cf3479d95fcf541fe1 100644 (file)
@@ -18,4 +18,11 @@ struct sof_ipc_dai_acp_params {
        uint32_t fsync_rate;    /* FSYNC frequency in Hz */
        uint32_t tdm_slots;
 } __packed;
+
+/* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */
+struct sof_ipc_dai_acpdmic_params {
+       uint32_t pdm_rate;
+       uint32_t pdm_ch;
+} __packed;
+
 #endif
index 7a266f41983cb46112ebe38d33c618c54b61064d..5b93b7292f5e1af542e48fe19c073b22411fca5a 100644 (file)
@@ -52,6 +52,8 @@
 #define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_ES               BIT(6)
 /* bclk early start */
 #define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_ES               BIT(7)
+/* mclk always on */
+#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_AON             BIT(8)
 
 /* DMIC max. four controllers for eight microphone channels */
 #define SOF_DAI_INTEL_DMIC_NUM_CTRL                    4
index a818a0f0a2267c71521c0c0c9b55e3288aec2fef..21d98f31a9cabf1c563dda807968852220c33065 100644 (file)
@@ -111,7 +111,7 @@ struct sof_ipc_dai_config {
                struct sof_ipc_dai_sai_params sai;
                struct sof_ipc_dai_acp_params acpbt;
                struct sof_ipc_dai_acp_params acpsp;
-               struct sof_ipc_dai_acp_params acpdmic;
+               struct sof_ipc_dai_acpdmic_params acpdmic;
                struct sof_ipc_dai_mtk_afe_params afe;
        };
 } __packed;
index b8b8e5b5e3e1cddef43caf86214706332e9f76ab..a795deacc2eae482280a4210dc1088b770a731db 100644 (file)
@@ -385,6 +385,14 @@ struct sof_ipc4_fw_version {
        uint16_t build;
 } __packed;
 
+/* Payload data for SOF_IPC4_MOD_SET_DX */
+struct sof_ipc4_dx_state_info {
+       /* core(s) to apply the change */
+       uint32_t core_mask;
+       /* core state: 0: put core_id to D3; 1: put core_id to D0 */
+       uint32_t dx_mask;
+} __packed __aligned(4);
+
 /* Reply messages */
 
 /*
index 1db3bbc3e65d43ee07908c7ee09e4c789d19ceee..9377113f13e49e1db7930dc37880fe9c50d7b2ef 100644 (file)
@@ -86,9 +86,11 @@ struct sof_ipc_stream_params {
        uint32_t host_period_bytes;
        uint16_t no_stream_position; /**< 1 means don't send stream position */
        uint8_t cont_update_posn; /**< 1 means continuous update stream position */
-
-       uint8_t reserved[5];
+       uint8_t reserved0;
+       int16_t ext_data_length; /**< 0, means no extended data */
+       uint8_t reserved[2];
        uint16_t chmap[SOF_IPC_MAX_CHANNELS];   /**< channel map - SOF_CHMAP_ */
+       uint8_t ext_data[]; /**< extended data */
 } __packed;
 
 /* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */
index 9555f31c8425c79ac87cb239c446509e73f39369..3aef123dbd7f61d8dbdaad5fa0d06eb9fd48f4de 100644 (file)
@@ -123,7 +123,7 @@ struct snd_compr_codec_caps {
 } __attribute__((packed, aligned(4)));
 
 /**
- * enum sndrv_compress_encoder
+ * enum sndrv_compress_encoder - encoder metadata key
  * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
  * end of the track
  * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
index 79b14389ae4112fa39f115372fc7901b4427bf4b..7263617169195600b5749a1941356829e81b3b31 100644 (file)
@@ -250,7 +250,7 @@ struct snd_enc_wma {
 
 
 /**
- * struct snd_enc_vorbis
+ * struct snd_enc_vorbis - Vorbis encoder parameters
  * @quality: Sets encoding quality to n, between -1 (low) and 10 (high).
  * In the default mode of operation, the quality level is 3.
  * Normal quality range is 0 - 10.
@@ -279,7 +279,7 @@ struct snd_enc_vorbis {
 
 
 /**
- * struct snd_enc_real
+ * struct snd_enc_real - RealAudio encoder parameters
  * @quant_bits: number of coupling quantization bits in the stream
  * @start_region: coupling start region in the stream
  * @num_regions: number of regions value
@@ -294,7 +294,7 @@ struct snd_enc_real {
 } __attribute__((packed, aligned(4)));
 
 /**
- * struct snd_enc_flac
+ * struct snd_enc_flac - FLAC encoder parameters
  * @num: serial number, valid only for OGG formats
  *     needs to be set by application
  * @gain: Add replay gain tags
index 0e7dccdc25fdd1c3fde410f4f5f2337f46651c43..3566630ca965b05bffc938f78c77a6206c02a18e 100644 (file)
 #ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__
 #define __INCLUDE_UAPI_SOUND_SOF_ABI_H__
 
+#include <linux/types.h>
+
 /* SOF ABI version major, minor and patch numbers */
 #define SOF_ABI_MAJOR 3
-#define SOF_ABI_MINOR 21
+#define SOF_ABI_MINOR 23
 #define SOF_ABI_PATCH 0
 
 /* SOF ABI version number. Format within 32bit word is MMmmmppp */
index dbf137516522113feae125c28c29ad9f4971376c..e9bba93a53990b4f32ad148ea8f51295fff3e3d5 100644 (file)
@@ -26,4 +26,34 @@ struct sof_abi_hdr {
        __u32 data[];           /**< Component data - opaque to core */
 }  __packed;
 
+#define SOF_MANIFEST_DATA_TYPE_NHLT 1
+
+/**
+ * struct sof_manifest_tlv - SOF manifest TLV data
+ * @type: type of data
+ * @size: data size (not including the size of this struct)
+ * @data: payload data
+ */
+struct sof_manifest_tlv {
+       __le32 type;
+       __le32 size;
+       __u8 data[];
+};
+
+/**
+ * struct sof_manifest - SOF topology manifest
+ * @abi_major: Major ABI version
+ * @abi_minor: Minor ABI version
+ * @abi_patch: ABI patch
+ * @count: count of tlv items
+ * @items: consecutive variable size tlv items
+ */
+struct sof_manifest {
+       __le16 abi_major;
+       __le16 abi_minor;
+       __le16 abi_patch;
+       __le16 count;
+       struct sof_manifest_tlv items[];
+};
+
 #endif
index b72fa385bebf5129f8b69e27e1be9a0f18d62e05..5caf75cadaf8c3216e4cf4f0efec487bc113f99a 100644 (file)
 #define SOF_TKN_SCHED_FRAMES                   204
 #define SOF_TKN_SCHED_TIME_DOMAIN              205
 #define SOF_TKN_SCHED_DYNAMIC_PIPELINE         206
+#define SOF_TKN_SCHED_LP_MODE                  207
+#define SOF_TKN_SCHED_MEM_USAGE                        208
 
 /* volume */
 #define SOF_TKN_VOLUME_RAMP_STEP_TYPE          250
 #define SOF_TKN_VOLUME_RAMP_STEP_MS            251
 
+#define SOF_TKN_GAIN_RAMP_TYPE                 260
+#define SOF_TKN_GAIN_RAMP_DURATION             261
+#define SOF_TKN_GAIN_VAL                       262
+
 /* SRC */
 #define SOF_TKN_SRC_RATE_IN                    300
 #define SOF_TKN_SRC_RATE_OUT                   301
@@ -79,6 +85,9 @@
  */
 #define SOF_TKN_COMP_CORE_ID                   404
 #define SOF_TKN_COMP_UUID                       405
+#define SOF_TKN_COMP_CPC                       406
+#define SOF_TKN_COMP_IS_PAGES                  409
+#define SOF_TKN_COMP_NUM_AUDIO_FORMATS         410
 
 /* SSP */
 #define SOF_TKN_INTEL_SSP_CLKS_CONTROL         500
 #define SOF_TKN_MEDIATEK_AFE_CH                        1601
 #define SOF_TKN_MEDIATEK_AFE_FORMAT            1602
 
+/* MIXER */
+#define SOF_TKN_MIXER_TYPE                     1700
+
+/* ACPDMIC */
+#define SOF_TKN_AMD_ACPDMIC_RATE               1800
+#define SOF_TKN_AMD_ACPDMIC_CH                 1801
+
+/* CAVS AUDIO FORMAT */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE      1900
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH 1901
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT 1902
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CHANNELS  1903
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP    1904
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG    1905
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE        1906
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG   1907
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_SAMPLE_TYPE       1908
+/* intentional token numbering discontinuity, reserved for future use */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE     1930
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH        1931
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT        1932
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CHANNELS 1933
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP   1934
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG   1935
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE       1936
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG  1937
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_SAMPLE_TYPE      1938
+/* intentional token numbering discontinuity, reserved for future use */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IBS          1970
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OBS          1971
+#define SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE      1972
+
+/* COPIER */
+#define SOF_TKN_INTEL_COPIER_NODE_TYPE         1980
+
 #endif
index 0d31a6d71468cf3a04b0178e3dcdf1857d8d334c..045330883a9633f5a52b82be9304c15420ded684 100644 (file)
@@ -460,7 +460,7 @@ static ssize_t vendor_id_show(struct device *dev,
 {
        struct ac97_codec_device *codec = to_ac97_device(dev);
 
-       return sprintf(buf, "%08x", codec->vendor_id);
+       return sysfs_emit(buf, "%08x", codec->vendor_id);
 }
 DEVICE_ATTR_RO(vendor_id);
 
index dead3105689b747454b982dbfcdfe6efe9e220be..e87b28428b99992fb4c90853020162024d131143 100644 (file)
@@ -10,19 +10,13 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
 {
        struct soundbus_dev *sdev = to_soundbus_device(dev);
        struct platform_device *of = &sdev->ofdev;
-       int length;
 
-       if (*sdev->modalias) {
-               strscpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1);
-               strcat(buf, "\n");
-               length = strlen(buf);
-       } else {
-               length = sprintf(buf, "of:N%pOFn%c%s\n",
-                                of->dev.of_node, 'T',
-                                 of_node_get_device_type(of->dev.of_node));
-       }
-
-       return length;
+       if (*sdev->modalias)
+               return sysfs_emit(buf, "%s\n", sdev->modalias);
+       else
+               return sysfs_emit(buf, "of:N%pOFn%c%s\n",
+                                 of->dev.of_node, 'T',
+                                 of_node_get_device_type(of->dev.of_node));
 }
 static DEVICE_ATTR_RO(modalias);
 
@@ -32,7 +26,7 @@ static ssize_t name_show(struct device *dev,
        struct soundbus_dev *sdev = to_soundbus_device(dev);
        struct platform_device *of = &sdev->ofdev;
 
-       return sprintf(buf, "%pOFn\n", of->dev.of_node);
+       return sysfs_emit(buf, "%pOFn\n", of->dev.of_node);
 }
 static DEVICE_ATTR_RO(name);
 
@@ -42,7 +36,7 @@ static ssize_t type_show(struct device *dev,
        struct soundbus_dev *sdev = to_soundbus_device(dev);
        struct platform_device *of = &sdev->ofdev;
 
-       return sprintf(buf, "%s\n", of_node_get_device_type(of->dev.of_node));
+       return sysfs_emit(buf, "%s\n", of_node_get_device_type(of->dev.of_node));
 }
 static DEVICE_ATTR_RO(type);
 
index dd7b40734723066c7d5deb892cd2941011995ae8..12990d9a4dffe76d7e321f780e181dee71fb8aef 100644 (file)
@@ -154,6 +154,16 @@ config SND_VERBOSE_PRINTK
 
          You don't need this unless you're debugging ALSA.
 
+config SND_CTL_FAST_LOOKUP
+       bool "Fast lookup of control elements" if EXPERT
+       default y
+       select XARRAY_MULTI
+       help
+         This option enables the faster lookup of control elements.
+         It will consume more memory because of the additional Xarray.
+         If you want to choose the memory footprint over the performance
+         inevitably, turn this off.
+
 config SND_DEBUG
        bool "Debug"
        help
@@ -178,14 +188,29 @@ config SND_PCM_XRUN_DEBUG
          sound clicking when system is loaded, it may help to determine
          the process or driver which causes the scheduling gaps.
 
-config SND_CTL_VALIDATION
-       bool "Perform sanity-checks for each control element access"
+config SND_CTL_INPUT_VALIDATION
+       bool "Validate input data to control API"
+       help
+         Say Y to enable the additional validation for the input data to
+         each control element, including the value range checks.
+         An error is returned from ALSA core for invalid inputs without
+         passing to the driver.  This is a kind of hardening for drivers
+         that have no proper error checks, at the cost of a slight
+         performance overhead.
+
+config SND_CTL_DEBUG
+       bool "Enable debugging feature for control API"
        depends on SND_DEBUG
        help
-         Say Y to enable the additional validation of each control element
-         access, including sanity-checks like whether the values returned
-         from the driver are in the proper ranges or the check of the invalid
-         access at out-of-array areas.
+         Say Y to enable the debugging feature for ALSA control API.
+         It performs the additional sanity-checks for each control element
+         read access, such as whether the values returned from the driver
+         are in the proper ranges or the check of the invalid access at
+         out-of-array areas.  The error is printed when the driver gives
+         such unexpected values.
+         When you develop a driver that deals with control elements, it's
+         strongly recommended to try this one once and verify whether you see
+         any relevant errors or not.
 
 config SND_JACK_INJECTION_DEBUG
        bool "Sound jack injection interface via debugfs"
index de514ec8c83d547ca798264079674110771dc0f9..243acad89fd3bc01d6171c56779ee7699560891f 100644 (file)
@@ -810,7 +810,7 @@ static void error_delayed_work(struct work_struct *work)
        mutex_unlock(&stream->device->lock);
 }
 
-/*
+/**
  * snd_compr_stop_error: Report a fatal error on a stream
  * @stream: pointer to stream
  * @state: state to transition the stream to
@@ -818,6 +818,8 @@ static void error_delayed_work(struct work_struct *work)
  * Stop the stream and set its state.
  *
  * Should be called with compressed device lock held.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_compr_stop_error(struct snd_compr_stream *stream,
                         snd_pcm_state_t state)
@@ -1157,12 +1159,15 @@ static int snd_compress_dev_free(struct snd_device *device)
        return 0;
 }
 
-/*
+/**
  * snd_compress_new: create new compress device
  * @card: sound card pointer
  * @device: device number
  * @dirn: device direction, should be of type enum snd_compr_direction
+ * @id: ID string
  * @compr: compress device pointer
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_compress_new(struct snd_card *card, int device,
                        int dirn, const char *id, struct snd_compr *compr)
index a25c0d64d104f171ec8fe5eb1320919a406c9081..f3e893715369f0c759bca83e1184cff63e075398 100644 (file)
@@ -127,6 +127,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
                        if (control->vd[idx].owner == ctl)
                                control->vd[idx].owner = NULL;
        up_write(&card->controls_rwsem);
+       snd_fasync_free(ctl->fasync);
        snd_ctl_empty_read_queue(ctl);
        put_pid(ctl->pid);
        kfree(ctl);
@@ -181,7 +182,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
        _found:
                wake_up(&ctl->change_sleep);
                spin_unlock(&ctl->read_lock);
-               kill_fasync(&ctl->fasync, SIGIO, POLL_IN);
+               snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN);
        }
        read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
 }
@@ -364,6 +365,93 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
        return 0;
 }
 
+/* check whether the given id is contained in the given kctl */
+static bool elem_id_matches(const struct snd_kcontrol *kctl,
+                           const struct snd_ctl_elem_id *id)
+{
+       return kctl->id.iface == id->iface &&
+               kctl->id.device == id->device &&
+               kctl->id.subdevice == id->subdevice &&
+               !strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)) &&
+               kctl->id.index <= id->index &&
+               kctl->id.index + kctl->count > id->index;
+}
+
+#ifdef CONFIG_SND_CTL_FAST_LOOKUP
+/* Compute a hash key for the corresponding ctl id
+ * It's for the name lookup, hence the numid is excluded.
+ * The hash key is bound in LONG_MAX to be used for Xarray key.
+ */
+#define MULTIPLIER     37
+static unsigned long get_ctl_id_hash(const struct snd_ctl_elem_id *id)
+{
+       unsigned long h;
+       const unsigned char *p;
+
+       h = id->iface;
+       h = MULTIPLIER * h + id->device;
+       h = MULTIPLIER * h + id->subdevice;
+       for (p = id->name; *p; p++)
+               h = MULTIPLIER * h + *p;
+       h = MULTIPLIER * h + id->index;
+       h &= LONG_MAX;
+       return h;
+}
+
+/* add hash entries to numid and ctl xarray tables */
+static void add_hash_entries(struct snd_card *card,
+                            struct snd_kcontrol *kcontrol)
+{
+       struct snd_ctl_elem_id id = kcontrol->id;
+       int i;
+
+       xa_store_range(&card->ctl_numids, kcontrol->id.numid,
+                      kcontrol->id.numid + kcontrol->count - 1,
+                      kcontrol, GFP_KERNEL);
+
+       for (i = 0; i < kcontrol->count; i++) {
+               id.index = kcontrol->id.index + i;
+               if (xa_insert(&card->ctl_hash, get_ctl_id_hash(&id),
+                             kcontrol, GFP_KERNEL)) {
+                       /* skip hash for this entry, noting we had collision */
+                       card->ctl_hash_collision = true;
+                       dev_dbg(card->dev, "ctl_hash collision %d:%s:%d\n",
+                               id.iface, id.name, id.index);
+               }
+       }
+}
+
+/* remove hash entries that have been added */
+static void remove_hash_entries(struct snd_card *card,
+                               struct snd_kcontrol *kcontrol)
+{
+       struct snd_ctl_elem_id id = kcontrol->id;
+       struct snd_kcontrol *matched;
+       unsigned long h;
+       int i;
+
+       for (i = 0; i < kcontrol->count; i++) {
+               xa_erase(&card->ctl_numids, id.numid);
+               h = get_ctl_id_hash(&id);
+               matched = xa_load(&card->ctl_hash, h);
+               if (matched && (matched == kcontrol ||
+                               elem_id_matches(matched, &id)))
+                       xa_erase(&card->ctl_hash, h);
+               id.index++;
+               id.numid++;
+       }
+}
+#else /* CONFIG_SND_CTL_FAST_LOOKUP */
+static inline void add_hash_entries(struct snd_card *card,
+                                   struct snd_kcontrol *kcontrol)
+{
+}
+static inline void remove_hash_entries(struct snd_card *card,
+                                      struct snd_kcontrol *kcontrol)
+{
+}
+#endif /* CONFIG_SND_CTL_FAST_LOOKUP */
+
 enum snd_ctl_add_mode {
        CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE,
 };
@@ -408,6 +496,8 @@ static int __snd_ctl_add_replace(struct snd_card *card,
        kcontrol->id.numid = card->last_numid + 1;
        card->last_numid += kcontrol->count;
 
+       add_hash_entries(card, kcontrol);
+
        for (idx = 0; idx < kcontrol->count; idx++)
                snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_ADD, kcontrol, idx);
 
@@ -479,6 +569,26 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL(snd_ctl_replace);
 
+static int __snd_ctl_remove(struct snd_card *card,
+                           struct snd_kcontrol *kcontrol,
+                           bool remove_hash)
+{
+       unsigned int idx;
+
+       if (snd_BUG_ON(!card || !kcontrol))
+               return -EINVAL;
+       list_del(&kcontrol->list);
+
+       if (remove_hash)
+               remove_hash_entries(card, kcontrol);
+
+       card->controls_count -= kcontrol->count;
+       for (idx = 0; idx < kcontrol->count; idx++)
+               snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx);
+       snd_ctl_free_one(kcontrol);
+       return 0;
+}
+
 /**
  * snd_ctl_remove - remove the control from the card and release it
  * @card: the card instance
@@ -492,16 +602,7 @@ EXPORT_SYMBOL(snd_ctl_replace);
  */
 int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
 {
-       unsigned int idx;
-
-       if (snd_BUG_ON(!card || !kcontrol))
-               return -EINVAL;
-       list_del(&kcontrol->list);
-       card->controls_count -= kcontrol->count;
-       for (idx = 0; idx < kcontrol->count; idx++)
-               snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx);
-       snd_ctl_free_one(kcontrol);
-       return 0;
+       return __snd_ctl_remove(card, kcontrol, true);
 }
 EXPORT_SYMBOL(snd_ctl_remove);
 
@@ -642,14 +743,30 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
                up_write(&card->controls_rwsem);
                return -ENOENT;
        }
+       remove_hash_entries(card, kctl);
        kctl->id = *dst_id;
        kctl->id.numid = card->last_numid + 1;
        card->last_numid += kctl->count;
+       add_hash_entries(card, kctl);
        up_write(&card->controls_rwsem);
        return 0;
 }
 EXPORT_SYMBOL(snd_ctl_rename_id);
 
+#ifndef CONFIG_SND_CTL_FAST_LOOKUP
+static struct snd_kcontrol *
+snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
+{
+       struct snd_kcontrol *kctl;
+
+       list_for_each_entry(kctl, &card->controls, list) {
+               if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
+                       return kctl;
+       }
+       return NULL;
+}
+#endif /* !CONFIG_SND_CTL_FAST_LOOKUP */
+
 /**
  * snd_ctl_find_numid - find the control instance with the given number-id
  * @card: the card instance
@@ -665,15 +782,13 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
  */
 struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
 {
-       struct snd_kcontrol *kctl;
-
        if (snd_BUG_ON(!card || !numid))
                return NULL;
-       list_for_each_entry(kctl, &card->controls, list) {
-               if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
-                       return kctl;
-       }
-       return NULL;
+#ifdef CONFIG_SND_CTL_FAST_LOOKUP
+       return xa_load(&card->ctl_numids, numid);
+#else
+       return snd_ctl_find_numid_slow(card, numid);
+#endif
 }
 EXPORT_SYMBOL(snd_ctl_find_numid);
 
@@ -699,21 +814,18 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
                return NULL;
        if (id->numid != 0)
                return snd_ctl_find_numid(card, id->numid);
-       list_for_each_entry(kctl, &card->controls, list) {
-               if (kctl->id.iface != id->iface)
-                       continue;
-               if (kctl->id.device != id->device)
-                       continue;
-               if (kctl->id.subdevice != id->subdevice)
-                       continue;
-               if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))
-                       continue;
-               if (kctl->id.index > id->index)
-                       continue;
-               if (kctl->id.index + kctl->count <= id->index)
-                       continue;
+#ifdef CONFIG_SND_CTL_FAST_LOOKUP
+       kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id));
+       if (kctl && elem_id_matches(kctl, id))
                return kctl;
-       }
+       if (!card->ctl_hash_collision)
+               return NULL; /* we can rely on only hash table */
+#endif
+       /* no matching in hash table - try all as the last resort */
+       list_for_each_entry(kctl, &card->controls, list)
+               if (elem_id_matches(kctl, id))
+                       return kctl;
+
        return NULL;
 }
 EXPORT_SYMBOL(snd_ctl_find_id);
@@ -855,7 +967,6 @@ static const unsigned int value_sizes[] = {
        [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
 };
 
-#ifdef CONFIG_SND_CTL_VALIDATION
 /* fill the remaining snd_ctl_elem_value data with the given pattern */
 static void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
                                      struct snd_ctl_elem_info *info,
@@ -872,7 +983,7 @@ static void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
 static int sanity_check_int_value(struct snd_card *card,
                                  const struct snd_ctl_elem_value *control,
                                  const struct snd_ctl_elem_info *info,
-                                 int i)
+                                 int i, bool print_error)
 {
        long long lval, lmin, lmax, lstep;
        u64 rem;
@@ -906,21 +1017,23 @@ static int sanity_check_int_value(struct snd_card *card,
        }
 
        if (lval < lmin || lval > lmax) {
-               dev_err(card->dev,
-                       "control %i:%i:%i:%s:%i: value out of range %lld (%lld/%lld) at count %i\n",
-                       control->id.iface, control->id.device,
-                       control->id.subdevice, control->id.name,
-                       control->id.index, lval, lmin, lmax, i);
+               if (print_error)
+                       dev_err(card->dev,
+                               "control %i:%i:%i:%s:%i: value out of range %lld (%lld/%lld) at count %i\n",
+                               control->id.iface, control->id.device,
+                               control->id.subdevice, control->id.name,
+                               control->id.index, lval, lmin, lmax, i);
                return -EINVAL;
        }
        if (lstep) {
                div64_u64_rem(lval, lstep, &rem);
                if (rem) {
-                       dev_err(card->dev,
-                               "control %i:%i:%i:%s:%i: unaligned value %lld (step %lld) at count %i\n",
-                               control->id.iface, control->id.device,
-                               control->id.subdevice, control->id.name,
-                               control->id.index, lval, lstep, i);
+                       if (print_error)
+                               dev_err(card->dev,
+                                       "control %i:%i:%i:%s:%i: unaligned value %lld (step %lld) at count %i\n",
+                                       control->id.iface, control->id.device,
+                                       control->id.subdevice, control->id.name,
+                                       control->id.index, lval, lstep, i);
                        return -EINVAL;
                }
        }
@@ -928,15 +1041,13 @@ static int sanity_check_int_value(struct snd_card *card,
        return 0;
 }
 
-/* perform sanity checks to the given snd_ctl_elem_value object */
-static int sanity_check_elem_value(struct snd_card *card,
-                                  const struct snd_ctl_elem_value *control,
-                                  const struct snd_ctl_elem_info *info,
-                                  u32 pattern)
+/* check whether the all input values are valid for the given elem value */
+static int sanity_check_input_values(struct snd_card *card,
+                                    const struct snd_ctl_elem_value *control,
+                                    const struct snd_ctl_elem_info *info,
+                                    bool print_error)
 {
-       size_t offset;
-       int i, ret = 0;
-       u32 *p;
+       int i, ret;
 
        switch (info->type) {
        case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
@@ -944,7 +1055,8 @@ static int sanity_check_elem_value(struct snd_card *card,
        case SNDRV_CTL_ELEM_TYPE_INTEGER64:
        case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
                for (i = 0; i < info->count; i++) {
-                       ret = sanity_check_int_value(card, control, info, i);
+                       ret = sanity_check_int_value(card, control, info, i,
+                                                    print_error);
                        if (ret < 0)
                                return ret;
                }
@@ -953,6 +1065,23 @@ static int sanity_check_elem_value(struct snd_card *card,
                break;
        }
 
+       return 0;
+}
+
+/* perform sanity checks to the given snd_ctl_elem_value object */
+static int sanity_check_elem_value(struct snd_card *card,
+                                  const struct snd_ctl_elem_value *control,
+                                  const struct snd_ctl_elem_info *info,
+                                  u32 pattern)
+{
+       size_t offset;
+       int ret;
+       u32 *p;
+
+       ret = sanity_check_input_values(card, control, info, true);
+       if (ret < 0)
+               return ret;
+
        /* check whether the remaining area kept untouched */
        offset = value_sizes[info->type] * info->count;
        offset = DIV_ROUND_UP(offset, sizeof(u32));
@@ -967,21 +1096,6 @@ static int sanity_check_elem_value(struct snd_card *card,
 
        return ret;
 }
-#else
-static inline void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
-                                            struct snd_ctl_elem_info *info,
-                                            u32 pattern)
-{
-}
-
-static inline int sanity_check_elem_value(struct snd_card *card,
-                                         struct snd_ctl_elem_value *control,
-                                         struct snd_ctl_elem_info *info,
-                                         u32 pattern)
-{
-       return 0;
-}
-#endif
 
 static int __snd_ctl_elem_info(struct snd_card *card,
                               struct snd_kcontrol *kctl,
@@ -1077,7 +1191,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
 
        snd_ctl_build_ioff(&control->id, kctl, index_offset);
 
-#ifdef CONFIG_SND_CTL_VALIDATION
+#ifdef CONFIG_SND_CTL_DEBUG
        /* info is needed only for validation */
        memset(&info, 0, sizeof(info));
        info.id = control->id;
@@ -1154,6 +1268,17 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
 
        snd_ctl_build_ioff(&control->id, kctl, index_offset);
        result = snd_power_ref_and_wait(card);
+       /* validate input values */
+       if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) {
+               struct snd_ctl_elem_info info;
+
+               memset(&info, 0, sizeof(info));
+               info.id = control->id;
+               result = __snd_ctl_elem_info(card, kctl, &info, NULL);
+               if (!result)
+                       result = sanity_check_input_values(card, control, &info,
+                                                          false);
+       }
        if (!result)
                result = kctl->put(kctl, control);
        snd_power_unref(card);
@@ -1930,6 +2055,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
  * @fcn: ioctl callback function
  *
  * called from each device manager like pcm.c, hwdep.c, etc.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
 {
@@ -1942,6 +2069,8 @@ EXPORT_SYMBOL(snd_ctl_register_ioctl);
  * snd_ctl_register_ioctl_compat - register the device-specific 32bit compat
  * control-ioctls
  * @fcn: ioctl callback function
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
 {
@@ -1977,6 +2106,8 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
 /**
  * snd_ctl_unregister_ioctl - de-register the device-specific control-ioctls
  * @fcn: ioctl callback function to unregister
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
 {
@@ -1989,6 +2120,8 @@ EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
  * snd_ctl_unregister_ioctl_compat - de-register the device-specific compat
  * 32bit control-ioctls
  * @fcn: ioctl callback function to unregister
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
 {
@@ -2002,7 +2135,7 @@ static int snd_ctl_fasync(int fd, struct file * file, int on)
        struct snd_ctl_file *ctl;
 
        ctl = file->private_data;
-       return fasync_helper(fd, file, on, &ctl->fasync);
+       return snd_fasync_helper(fd, file, on, &ctl->fasync);
 }
 
 /* return the preferred subdevice number if already assigned;
@@ -2044,7 +2177,7 @@ EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
  * snd_ctl_request_layer - request to use the layer
  * @module_name: Name of the kernel module (NULL == build-in)
  *
- * Return an error code when the module cannot be loaded.
+ * Return: zero if successful, or an error code when the module cannot be loaded
  */
 int snd_ctl_request_layer(const char *module_name)
 {
@@ -2170,7 +2303,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
        read_lock_irqsave(&card->ctl_files_rwlock, flags);
        list_for_each_entry(ctl, &card->ctl_files, list) {
                wake_up(&ctl->change_sleep);
-               kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
+               snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);
        }
        read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
 
@@ -2195,8 +2328,13 @@ static int snd_ctl_dev_free(struct snd_device *device)
        down_write(&card->controls_rwsem);
        while (!list_empty(&card->controls)) {
                control = snd_kcontrol(card->controls.next);
-               snd_ctl_remove(card, control);
+               __snd_ctl_remove(card, control, false);
        }
+
+#ifdef CONFIG_SND_CTL_FAST_LOOKUP
+       xa_destroy(&card->ctl_numids);
+       xa_destroy(&card->ctl_hash);
+#endif
        up_write(&card->controls_rwsem);
        put_device(&card->ctl_dev);
        return 0;
@@ -2241,6 +2379,8 @@ int snd_ctl_create(struct snd_card *card)
  *
  * This is a function that can be used as info callback for a standard
  * boolean control with a single mono channel.
+ *
+ * Return: Zero (always successful)
  */
 int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_info *uinfo)
@@ -2261,6 +2401,8 @@ EXPORT_SYMBOL(snd_ctl_boolean_mono_info);
  *
  * This is a function that can be used as info callback for a standard
  * boolean control with stereo two channels.
+ *
+ * Return: Zero (always successful)
  */
 int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_info *uinfo)
@@ -2284,7 +2426,7 @@ EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
  * If the control's accessibility is not the default (readable and writable),
  * the caller has to fill @info->access.
  *
- * Return: Zero.
+ * Return: Zero (always successful)
  */
 int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
                      unsigned int items, const char *const names[])
index 207828f30983550c2a526e34a20140f2cadc9a7b..f975cc85772bbce857fd2565fe720070a9f83bd9 100644 (file)
@@ -405,7 +405,7 @@ static ssize_t mode_show(struct device *dev,
        case MODE_ON:           str = "on"; break;
        case MODE_OFF:          str = "off"; break;
        }
-       return sprintf(buf, "%s\n", str);
+       return sysfs_emit(buf, "%s\n", str);
 }
 
 static ssize_t mode_store(struct device *dev,
@@ -443,7 +443,7 @@ static ssize_t brightness_show(struct device *dev,
 {
        struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
 
-       return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
+       return sysfs_emit(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
 }
 
 static DEVICE_ATTR_RW(mode);
@@ -618,8 +618,7 @@ static ssize_t list_show(struct device *dev,
        struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
        struct snd_card *card;
        struct snd_ctl_led_ctl *lctl;
-       char *buf2 = buf;
-       size_t l;
+       size_t l = 0;
 
        card = snd_card_ref(led_card->number);
        if (!card)
@@ -627,23 +626,19 @@ static ssize_t list_show(struct device *dev,
        down_read(&card->controls_rwsem);
        mutex_lock(&snd_ctl_led_mutex);
        if (snd_ctl_led_card_valid[led_card->number]) {
-               list_for_each_entry(lctl, &led_card->led->controls, list)
-                       if (lctl->card == card) {
-                               if (buf2 - buf > PAGE_SIZE - 16)
-                                       break;
-                               if (buf2 != buf)
-                                       *buf2++ = ' ';
-                               l = scnprintf(buf2, 15, "%u",
-                                               lctl->kctl->id.numid +
-                                                       lctl->index_offset);
-                               buf2[l] = '\0';
-                               buf2 += l + 1;
-                       }
+               list_for_each_entry(lctl, &led_card->led->controls, list) {
+                       if (lctl->card != card)
+                               continue;
+                       if (l)
+                               l += sysfs_emit_at(buf, l, " ");
+                       l += sysfs_emit_at(buf, l, "%u",
+                                          lctl->kctl->id.numid + lctl->index_offset);
+               }
        }
        mutex_unlock(&snd_ctl_led_mutex);
        up_read(&card->controls_rwsem);
        snd_card_unref(card);
-       return buf2 - buf;
+       return l;
 }
 
 static DEVICE_ATTR_WO(attach);
index bf0b04a7ee79756c2b3ff907b8acbaa1a24f59e1..b57d80a170522de0463df59eaaa76f08b0f8d90e 100644 (file)
@@ -247,6 +247,8 @@ void snd_device_free_all(struct snd_card *card)
  * device, either @SNDRV_DEV_BUILD, @SNDRV_DEV_REGISTERED or
  * @SNDRV_DEV_DISCONNECTED is returned.
  * Or for a non-existing device, -1 is returned as an error.
+ *
+ * Return: the current state, or -1 if not found
  */
 int snd_device_get_state(struct snd_card *card, void *device_data)
 {
index 782fba87cc043a156427d6c5500b13a63da9fe06..b8058b341178349184a5597a6b8cf1a673576f8e 100644 (file)
@@ -868,6 +868,8 @@ EXPORT_SYMBOL(snd_info_register);
  *
  * This proc file entry will be registered via snd_card_register() call, and
  * it will be removed automatically at the card removal, too.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_card_rw_proc_new(struct snd_card *card, const char *name,
                         void *private_data,
index 726a8353201f834048f5a847c03fe95806441459..193dae361fac39d7d9f3a6a1cd413944eb0e6a2a 100644 (file)
@@ -215,6 +215,8 @@ static void __snd_card_release(struct device *dev, void *data)
  * via snd_card_free() call in the error; otherwise it may lead to UAF due to
  * devres call orders.  You can use snd_card_free_on_error() helper for
  * handling it more easily.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_devm_card_new(struct device *parent, int idx, const char *xid,
                      struct module *module, size_t extra_size,
@@ -249,6 +251,8 @@ EXPORT_SYMBOL_GPL(snd_devm_card_new);
  * This function handles the explicit snd_card_free() call at the error from
  * the probe callback.  It's just a small helper for simplifying the error
  * handling with the managed devices.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_card_free_on_error(struct device *dev, int ret)
 {
@@ -310,6 +314,10 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
        rwlock_init(&card->ctl_files_rwlock);
        INIT_LIST_HEAD(&card->controls);
        INIT_LIST_HEAD(&card->ctl_files);
+#ifdef CONFIG_SND_CTL_FAST_LOOKUP
+       xa_init(&card->ctl_numids);
+       xa_init(&card->ctl_hash);
+#endif
        spin_lock_init(&card->files_lock);
        INIT_LIST_HEAD(&card->files_list);
        mutex_init(&card->memory_mutex);
@@ -366,6 +374,8 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
  *
  * Returns a card object corresponding to the given index or NULL if not found.
  * Release the object via snd_card_unref().
+ *
+ * Return: a card object or NULL
  */
 struct snd_card *snd_card_ref(int idx)
 {
@@ -604,6 +614,8 @@ static int snd_card_do_free(struct snd_card *card)
  * resource immediately, but tries to disconnect at first.  When the card
  * is still in use, the function returns before freeing the resources.
  * The card resources will be freed when the refcount gets to zero.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_card_free_when_closed(struct snd_card *card)
 {
@@ -772,7 +784,7 @@ static ssize_t id_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
 {
        struct snd_card *card = container_of(dev, struct snd_card, card_dev);
-       return scnprintf(buf, PAGE_SIZE, "%s\n", card->id);
+       return sysfs_emit(buf, "%s\n", card->id);
 }
 
 static ssize_t id_store(struct device *dev, struct device_attribute *attr,
@@ -810,7 +822,7 @@ static ssize_t number_show(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
        struct snd_card *card = container_of(dev, struct snd_card, card_dev);
-       return scnprintf(buf, PAGE_SIZE, "%i\n", card->number);
+       return sysfs_emit(buf, "%i\n", card->number);
 }
 
 static DEVICE_ATTR_RO(number);
@@ -829,6 +841,8 @@ static const struct attribute_group card_dev_attr_group = {
  * snd_card_add_dev_attr - Append a new sysfs attribute group to card
  * @card: card instance
  * @group: attribute group to append
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_card_add_dev_attr(struct snd_card *card,
                          const struct attribute_group *group)
index 18a86212e3a82d01994ff728544316c9db08e446..28768061d769eb9ca9ef0f0b088ec8bfaf6e0d91 100644 (file)
@@ -116,8 +116,9 @@ static void __snd_release_dma(struct device *dev, void *data)
  * @dma: the dma number
  * @name: the name string of the requester
  *
- * Returns zero on success, or a negative error code.
  * The requested DMA will be automatically released at unbinding via devres.
+ *
+ * Return: zero on success, or a negative error code
  */
 int snd_devm_request_dma(struct device *dev, int dma, const char *name)
 {
index 8cfdaee779050ca64a8d7b9fa5647c66dcd4e60a..d3885cb02270e005ba74b06a82f440c85216e028 100644 (file)
@@ -147,7 +147,7 @@ static void __snd_release_pages(struct device *dev, void *res)
  * hence it can't work with SNDRV_DMA_TYPE_CONTINUOUS or
  * SNDRV_DMA_TYPE_VMALLOC type.
  *
- * The function returns the snd_dma_buffer object at success, or NULL if failed.
+ * Return: the snd_dma_buffer object at success, or NULL if failed
  */
 struct snd_dma_buffer *
 snd_devm_alloc_dir_pages(struct device *dev, int type,
@@ -179,6 +179,8 @@ EXPORT_SYMBOL_GPL(snd_devm_alloc_dir_pages);
  * snd_dma_buffer_mmap - perform mmap of the given DMA buffer
  * @dmab: buffer allocation information
  * @area: VM area information
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
                        struct vm_area_struct *area)
@@ -219,6 +221,8 @@ EXPORT_SYMBOL_GPL(snd_dma_buffer_sync);
  * snd_sgbuf_get_addr - return the physical address at the corresponding offset
  * @dmab: buffer allocation information
  * @offset: offset in the ring buffer
+ *
+ * Return: the physical address
  */
 dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset)
 {
@@ -235,6 +239,8 @@ EXPORT_SYMBOL(snd_sgbuf_get_addr);
  * snd_sgbuf_get_page - return the physical page at the corresponding offset
  * @dmab: buffer allocation information
  * @offset: offset in the ring buffer
+ *
+ * Return: the page pointer
  */
 struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset)
 {
@@ -253,6 +259,8 @@ EXPORT_SYMBOL(snd_sgbuf_get_page);
  * @dmab: buffer allocation information
  * @ofs: offset in the ring buffer
  * @size: the requested size
+ *
+ * Return: the chunk size
  */
 unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
                                      unsigned int ofs, unsigned int size)
index 50e4aaa6270d187a456fb3fe5ce0af525cbe3f13..d32a19976a2b9543e660478295787f532e3c8925 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/fs.h>
 #include <sound/core.h>
 
 #ifdef CONFIG_SND_DEBUG
@@ -145,3 +146,96 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
 }
 EXPORT_SYMBOL(snd_pci_quirk_lookup);
 #endif
+
+/*
+ * Deferred async signal helpers
+ *
+ * Below are a few helper functions to wrap the async signal handling
+ * in the deferred work.  The main purpose is to avoid the messy deadlock
+ * around tasklist_lock and co at the kill_fasync() invocation.
+ * fasync_helper() and kill_fasync() are replaced with snd_fasync_helper()
+ * and snd_kill_fasync(), respectively.  In addition, snd_fasync_free() has
+ * to be called at releasing the relevant file object.
+ */
+struct snd_fasync {
+       struct fasync_struct *fasync;
+       int signal;
+       int poll;
+       int on;
+       struct list_head list;
+};
+
+static DEFINE_SPINLOCK(snd_fasync_lock);
+static LIST_HEAD(snd_fasync_list);
+
+static void snd_fasync_work_fn(struct work_struct *work)
+{
+       struct snd_fasync *fasync;
+
+       spin_lock_irq(&snd_fasync_lock);
+       while (!list_empty(&snd_fasync_list)) {
+               fasync = list_first_entry(&snd_fasync_list, struct snd_fasync, list);
+               list_del_init(&fasync->list);
+               spin_unlock_irq(&snd_fasync_lock);
+               if (fasync->on)
+                       kill_fasync(&fasync->fasync, fasync->signal, fasync->poll);
+               spin_lock_irq(&snd_fasync_lock);
+       }
+       spin_unlock_irq(&snd_fasync_lock);
+}
+
+static DECLARE_WORK(snd_fasync_work, snd_fasync_work_fn);
+
+int snd_fasync_helper(int fd, struct file *file, int on,
+                     struct snd_fasync **fasyncp)
+{
+       struct snd_fasync *fasync = NULL;
+
+       if (on) {
+               fasync = kzalloc(sizeof(*fasync), GFP_KERNEL);
+               if (!fasync)
+                       return -ENOMEM;
+               INIT_LIST_HEAD(&fasync->list);
+       }
+
+       spin_lock_irq(&snd_fasync_lock);
+       if (*fasyncp) {
+               kfree(fasync);
+               fasync = *fasyncp;
+       } else {
+               if (!fasync) {
+                       spin_unlock_irq(&snd_fasync_lock);
+                       return 0;
+               }
+               *fasyncp = fasync;
+       }
+       fasync->on = on;
+       spin_unlock_irq(&snd_fasync_lock);
+       return fasync_helper(fd, file, on, &fasync->fasync);
+}
+EXPORT_SYMBOL_GPL(snd_fasync_helper);
+
+void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll)
+{
+       unsigned long flags;
+
+       if (!fasync || !fasync->on)
+               return;
+       spin_lock_irqsave(&snd_fasync_lock, flags);
+       fasync->signal = signal;
+       fasync->poll = poll;
+       list_move(&fasync->list, &snd_fasync_list);
+       schedule_work(&snd_fasync_work);
+       spin_unlock_irqrestore(&snd_fasync_lock, flags);
+}
+EXPORT_SYMBOL_GPL(snd_kill_fasync);
+
+void snd_fasync_free(struct snd_fasync *fasync)
+{
+       if (!fasync)
+               return;
+       fasync->on = 0;
+       flush_work(&snd_fasync_work);
+       kfree(fasync);
+}
+EXPORT_SYMBOL_GPL(snd_fasync_free);
index 977d54320a5cabd858f6fce624de9c4f9fd430d0..82925709fa12ad38d19d3b7a1d47e96b0616c8cb 100644 (file)
@@ -216,6 +216,8 @@ static const char * const snd_pcm_format_names[] = {
 /**
  * snd_pcm_format_name - Return a name string for the given PCM format
  * @format: PCM format
+ *
+ * Return: the format name string
  */
 const char *snd_pcm_format_name(snd_pcm_format_t format)
 {
@@ -1005,6 +1007,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
                substream->runtime = NULL;
        }
        mutex_destroy(&runtime->buffer_mutex);
+       snd_fasync_free(runtime->fasync);
        kfree(runtime);
        put_pid(substream->pid);
        substream->pid = NULL;
@@ -1028,7 +1031,7 @@ static ssize_t pcm_class_show(struct device *dev,
                str = "none";
        else
                str = strs[pcm->dev_class];
-       return sprintf(buf, "%s\n", str);
+       return sysfs_emit(buf, "%s\n", str);
 }
 
 static DEVICE_ATTR_RO(pcm_class);
@@ -1138,6 +1141,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
  * This adds the given notifier to the global list so that the callback is
  * called for each registered PCM devices.  This exists only for PCM OSS
  * emulation, so far.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 {
index af6f717e1e7e66fe060d0b75ab50589cc2e10087..5b2ca028f5aabdf2d6a915733cfa75f1da096299 100644 (file)
@@ -48,6 +48,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_chan);
  *
  * This function can be used to initialize a dma_slave_config from a substream
  * and hw_params in a dmaengine based PCM driver implementation.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
        const struct snd_pcm_hw_params *params,
@@ -175,10 +177,10 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
  * @substream: PCM substream
  * @cmd: Trigger command
  *
- * Returns 0 on success, a negative error code otherwise.
- *
  * This function can be used as the PCM trigger callback for dmaengine based PCM
  * driver implementations.
+ *
+ * Return: 0 on success, a negative error code otherwise
  */
 int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
@@ -223,6 +225,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
  *
  * This function is deprecated and should not be used by new drivers, as its
  * results may be unreliable.
+ *
+ * Return: PCM position in frames
  */
 snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
 {
@@ -237,6 +241,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
  *
  * This function can be used as the PCM pointer callback for dmaengine based PCM
  * driver implementations.
+ *
+ * Return: PCM position in frames
  */
 snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
 {
@@ -266,9 +272,9 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
  * @filter_fn: Filter function used to request the DMA channel
  * @filter_data: Data passed to the DMA filter function
  *
- * Returns NULL or the requested DMA channel.
- *
  * This function request a DMA channel for usage with dmaengine PCM.
+ *
+ * Return: NULL or the requested DMA channel
  */
 struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
        void *filter_data)
@@ -288,11 +294,11 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
  * @substream: PCM substream
  * @chan: DMA channel to use for data transfers
  *
- * Returns 0 on success, a negative error code otherwise.
- *
  * The function should usually be called from the pcm open callback. Note that
  * this function will use private_data field of the substream's runtime. So it
  * is not available to your pcm driver implementation.
+ *
+ * Return: 0 on success, a negative error code otherwise
  */
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
        struct dma_chan *chan)
@@ -326,12 +332,12 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
  * @filter_fn: Filter function used to request the DMA channel
  * @filter_data: Data passed to the DMA filter function
  *
- * Returns 0 on success, a negative error code otherwise.
- *
  * This function will request a DMA channel using the passed filter function and
  * data. The function should usually be called from the pcm open callback. Note
  * that this function will use private_data field of the substream's runtime. So
  * it is not available to your pcm driver implementation.
+ *
+ * Return: 0 on success, a negative error code otherwise
  */
 int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
        dma_filter_fn filter_fn, void *filter_data)
@@ -344,6 +350,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
 /**
  * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
  * @substream: PCM substream
+ *
+ * Return: 0 on success, a negative error code otherwise
  */
 int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
 {
@@ -362,6 +370,8 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
  * @substream: PCM substream
  *
  * Releases the DMA channel associated with the PCM substream.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
 {
@@ -382,10 +392,10 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
  * @hw: PCM hw params
  * @chan: DMA channel to use for data transfers
  *
- * Returns 0 on success, a negative error code otherwise.
- *
  * This function will query DMA capability, then refine the pcm hardware
  * parameters.
+ *
+ * Return: 0 on success, a negative error code otherwise
  */
 int snd_dmaengine_pcm_refine_runtime_hwparams(
        struct snd_pcm_substream *substream,
index 1fc7c50ffa625bc3ec38486b1cf251c96acb39b4..40751e5aff09f13f665e0fed717210a2bdad1086 100644 (file)
@@ -1822,7 +1822,7 @@ void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substrea
                snd_timer_interrupt(substream->timer, 1);
 #endif
  _end:
-       kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
+       snd_kill_fasync(runtime->fasync, SIGIO, POLL_IN);
 }
 EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
 
index b8296b6eb2c19c758b850b6c9f5b9e32dc49b349..7bde7fb64011e0f9372f898de4e909d854ab93ae 100644 (file)
@@ -350,6 +350,8 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
  * SNDRV_DMA_TYPE_VMALLOC type.
  *
  * Upon successful buffer allocation and setup, the function returns 0.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type,
                                struct device *data, size_t size, size_t max)
@@ -369,6 +371,8 @@ EXPORT_SYMBOL(snd_pcm_set_managed_buffer);
  *
  * Do pre-allocation to all substreams of the given pcm for the specified DMA
  * type and size, and set the managed_buffer_alloc flag to each substream.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
                                   struct device *data,
index 4adaee62ef33329d2f3f4d967be9be7d9b26dbbd..ad0541e9e88808424aee75cdfcdc4f4d4098a02b 100644 (file)
@@ -3412,6 +3412,8 @@ static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
  * The function is provided primarily for OSS layer and USB gadget drivers,
  * and it allows only the limited set of ioctls (hw_params, sw_params,
  * prepare, start, drain, drop, forward).
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
                         unsigned int cmd, void *arg)
@@ -3810,6 +3812,8 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
  *
  * This is the default mmap handler for PCM data.  When mmap pcm_ops is NULL,
  * this function is invoked implicitly.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
                             struct vm_area_struct *area)
@@ -3836,6 +3840,8 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
  * When your hardware uses the iomapped pages as the hardware buffer and
  * wants to mmap it, pass this function as mmap pcm_ops.  Note that this
  * is supposed to work only on limited architectures.
+ *
+ * Return: zero if successful, or a negative error code
  */
 int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
                           struct vm_area_struct *area)
@@ -3945,7 +3951,7 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
        runtime = substream->runtime;
        if (runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
                return -EBADFD;
-       return fasync_helper(fd, file, on, &runtime->fasync);
+       return snd_fasync_helper(fd, file, on, &runtime->fasync);
 }
 
 /*
index befa9809ff001ec514a0512d560ce079041d86cc..6963d5a487b3278dbaa8cbf029a9dde9b3966066 100644 (file)
@@ -102,13 +102,12 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime)
 
 static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
 {
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
        unsigned long flags;
        bool ready;
 
-       spin_lock_irqsave(&runtime->lock, flags);
-       ready = __snd_rawmidi_ready(runtime);
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
+       ready = __snd_rawmidi_ready(substream->runtime);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return ready;
 }
 
@@ -130,7 +129,7 @@ static void snd_rawmidi_input_event_work(struct work_struct *work)
                runtime->event(runtime->substream);
 }
 
-/* buffer refcount management: call with runtime->lock held */
+/* buffer refcount management: call with substream->lock held */
 static inline void snd_rawmidi_buffer_ref(struct snd_rawmidi_runtime *runtime)
 {
        runtime->buffer_ref++;
@@ -141,6 +140,23 @@ static inline void snd_rawmidi_buffer_unref(struct snd_rawmidi_runtime *runtime)
        runtime->buffer_ref--;
 }
 
+static void snd_rawmidi_buffer_ref_sync(struct snd_rawmidi_substream *substream)
+{
+       int loop = HZ;
+
+       spin_lock_irq(&substream->lock);
+       while (substream->runtime->buffer_ref) {
+               spin_unlock_irq(&substream->lock);
+               if (!--loop) {
+                       rmidi_err(substream->rmidi, "Buffer ref sync timeout\n");
+                       return;
+               }
+               schedule_timeout_uninterruptible(1);
+               spin_lock_irq(&substream->lock);
+       }
+       spin_unlock_irq(&substream->lock);
+}
+
 static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
 {
        struct snd_rawmidi_runtime *runtime;
@@ -149,7 +165,6 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
        if (!runtime)
                return -ENOMEM;
        runtime->substream = substream;
-       spin_lock_init(&runtime->lock);
        init_waitqueue_head(&runtime->sleep);
        INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
        runtime->event = NULL;
@@ -203,35 +218,48 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
        runtime->avail = is_input ? 0 : runtime->buffer_size;
 }
 
-static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
+static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream,
                               bool is_input)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&runtime->lock, flags);
-       __reset_runtime_ptrs(runtime, is_input);
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
+       if (substream->opened && substream->runtime)
+               __reset_runtime_ptrs(substream->runtime, is_input);
+       spin_unlock_irqrestore(&substream->lock, flags);
 }
 
 int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
 {
        snd_rawmidi_output_trigger(substream, 0);
-       reset_runtime_ptrs(substream->runtime, false);
+       reset_runtime_ptrs(substream, false);
        return 0;
 }
 EXPORT_SYMBOL(snd_rawmidi_drop_output);
 
 int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
 {
-       int err;
+       int err = 0;
        long timeout;
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       struct snd_rawmidi_runtime *runtime;
+
+       spin_lock_irq(&substream->lock);
+       runtime = substream->runtime;
+       if (!substream->opened || !runtime || !runtime->buffer) {
+               err = -EINVAL;
+       } else {
+               snd_rawmidi_buffer_ref(runtime);
+               runtime->drain = 1;
+       }
+       spin_unlock_irq(&substream->lock);
+       if (err < 0)
+               return err;
 
-       err = 0;
-       runtime->drain = 1;
        timeout = wait_event_interruptible_timeout(runtime->sleep,
                                (runtime->avail >= runtime->buffer_size),
                                10*HZ);
+
+       spin_lock_irq(&substream->lock);
        if (signal_pending(current))
                err = -ERESTARTSYS;
        if (runtime->avail < runtime->buffer_size && !timeout) {
@@ -241,6 +269,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
                err = -EIO;
        }
        runtime->drain = 0;
+       spin_unlock_irq(&substream->lock);
+
        if (err != -ERESTARTSYS) {
                /* we need wait a while to make sure that Tx FIFOs are empty */
                if (substream->ops->drain)
@@ -249,6 +279,11 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
                        msleep(50);
                snd_rawmidi_drop_output(substream);
        }
+
+       spin_lock_irq(&substream->lock);
+       snd_rawmidi_buffer_unref(runtime);
+       spin_unlock_irq(&substream->lock);
+
        return err;
 }
 EXPORT_SYMBOL(snd_rawmidi_drain_output);
@@ -256,7 +291,7 @@ EXPORT_SYMBOL(snd_rawmidi_drain_output);
 int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
 {
        snd_rawmidi_input_trigger(substream, 0);
-       reset_runtime_ptrs(substream->runtime, true);
+       reset_runtime_ptrs(substream, true);
        return 0;
 }
 EXPORT_SYMBOL(snd_rawmidi_drain_input);
@@ -311,12 +346,14 @@ static int open_substream(struct snd_rawmidi *rmidi,
                        snd_rawmidi_runtime_free(substream);
                        return err;
                }
+               spin_lock_irq(&substream->lock);
                substream->opened = 1;
                substream->active_sensing = 0;
                if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
                        substream->append = 1;
                substream->pid = get_pid(task_pid(current));
                rmidi->streams[substream->stream].substream_opened++;
+               spin_unlock_irq(&substream->lock);
        }
        substream->use_count++;
        return 0;
@@ -521,13 +558,16 @@ static void close_substream(struct snd_rawmidi *rmidi,
                        if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
                                snd_rawmidi_output_trigger(substream, 0);
                }
+               snd_rawmidi_buffer_ref_sync(substream);
        }
+       spin_lock_irq(&substream->lock);
+       substream->opened = 0;
+       substream->append = 0;
+       spin_unlock_irq(&substream->lock);
        substream->ops->close(substream);
        if (substream->runtime->private_free)
                substream->runtime->private_free(substream);
        snd_rawmidi_runtime_free(substream);
-       substream->opened = 0;
-       substream->append = 0;
        put_pid(substream->pid);
        substream->pid = NULL;
        rmidi->streams[substream->stream].substream_opened--;
@@ -676,10 +716,11 @@ static int snd_rawmidi_info_select_user(struct snd_card *card,
        return 0;
 }
 
-static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
+static int resize_runtime_buffer(struct snd_rawmidi_substream *substream,
                                 struct snd_rawmidi_params *params,
                                 bool is_input)
 {
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
        char *newbuf, *oldbuf;
        unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
 
@@ -693,9 +734,9 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
                newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
                if (!newbuf)
                        return -ENOMEM;
-               spin_lock_irq(&runtime->lock);
+               spin_lock_irq(&substream->lock);
                if (runtime->buffer_ref) {
-                       spin_unlock_irq(&runtime->lock);
+                       spin_unlock_irq(&substream->lock);
                        kvfree(newbuf);
                        return -EBUSY;
                }
@@ -703,7 +744,7 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
                runtime->buffer = newbuf;
                runtime->buffer_size = params->buffer_size;
                __reset_runtime_ptrs(runtime, is_input);
-               spin_unlock_irq(&runtime->lock);
+               spin_unlock_irq(&substream->lock);
                kvfree(oldbuf);
        }
        runtime->avail_min = params->avail_min;
@@ -713,11 +754,19 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
 int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
                              struct snd_rawmidi_params *params)
 {
-       if (substream->append && substream->use_count > 1)
-               return -EBUSY;
+       int err;
+
        snd_rawmidi_drain_output(substream);
-       substream->active_sensing = !params->no_active_sensing;
-       return resize_runtime_buffer(substream->runtime, params, false);
+       mutex_lock(&substream->rmidi->open_mutex);
+       if (substream->append && substream->use_count > 1)
+               err = -EBUSY;
+       else
+               err = resize_runtime_buffer(substream, params, false);
+
+       if (!err)
+               substream->active_sensing = !params->no_active_sensing;
+       mutex_unlock(&substream->rmidi->open_mutex);
+       return err;
 }
 EXPORT_SYMBOL(snd_rawmidi_output_params);
 
@@ -728,19 +777,22 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
        unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK;
        int err;
 
+       snd_rawmidi_drain_input(substream);
+       mutex_lock(&substream->rmidi->open_mutex);
        if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
-               return -EINVAL;
+               err = -EINVAL;
        else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
-               return -EINVAL;
-       if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
-               return -EINVAL;
-       snd_rawmidi_drain_input(substream);
-       err = resize_runtime_buffer(substream->runtime, params, true);
-       if (err < 0)
-               return err;
+               err = -EINVAL;
+       else if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
+               err = -EINVAL;
+       else
+               err = resize_runtime_buffer(substream, params, true);
 
-       substream->framing = framing;
-       substream->clock_type = clock_type;
+       if (!err) {
+               substream->framing = framing;
+               substream->clock_type = clock_type;
+       }
+       mutex_unlock(&substream->rmidi->open_mutex);
        return 0;
 }
 EXPORT_SYMBOL(snd_rawmidi_input_params);
@@ -752,9 +804,9 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
 
        memset(status, 0, sizeof(*status));
        status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
-       spin_lock_irq(&runtime->lock);
+       spin_lock_irq(&substream->lock);
        status->avail = runtime->avail;
-       spin_unlock_irq(&runtime->lock);
+       spin_unlock_irq(&substream->lock);
        return 0;
 }
 
@@ -765,11 +817,11 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
 
        memset(status, 0, sizeof(*status));
        status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
-       spin_lock_irq(&runtime->lock);
+       spin_lock_irq(&substream->lock);
        status->avail = runtime->avail;
        status->xruns = runtime->xruns;
        runtime->xruns = 0;
-       spin_unlock_irq(&runtime->lock);
+       spin_unlock_irq(&substream->lock);
        return 0;
 }
 
@@ -1064,17 +1116,21 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
        unsigned long flags;
        struct timespec64 ts64 = get_framing_tstamp(substream);
        int result = 0, count1;
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       struct snd_rawmidi_runtime *runtime;
 
-       if (!substream->opened)
-               return -EBADFD;
-       if (runtime->buffer == NULL) {
+       spin_lock_irqsave(&substream->lock, flags);
+       if (!substream->opened) {
+               result = -EBADFD;
+               goto unlock;
+       }
+       runtime = substream->runtime;
+       if (!runtime || !runtime->buffer) {
                rmidi_dbg(substream->rmidi,
                          "snd_rawmidi_receive: input is not active!!!\n");
-               return -EINVAL;
+               result = -EINVAL;
+               goto unlock;
        }
 
-       spin_lock_irqsave(&runtime->lock, flags);
        if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
                result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
        } else if (count == 1) {        /* special case, faster code */
@@ -1121,7 +1177,8 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
                else if (__snd_rawmidi_ready(runtime))
                        wake_up(&runtime->sleep);
        }
-       spin_unlock_irqrestore(&runtime->lock, flags);
+ unlock:
+       spin_unlock_irqrestore(&substream->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_receive);
@@ -1136,7 +1193,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
        unsigned long appl_ptr;
        int err = 0;
 
-       spin_lock_irqsave(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
        snd_rawmidi_buffer_ref(runtime);
        while (count > 0 && runtime->avail) {
                count1 = runtime->buffer_size - runtime->appl_ptr;
@@ -1154,11 +1211,11 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
                if (kernelbuf)
                        memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1);
                if (userbuf) {
-                       spin_unlock_irqrestore(&runtime->lock, flags);
+                       spin_unlock_irqrestore(&substream->lock, flags);
                        if (copy_to_user(userbuf + result,
                                         runtime->buffer + appl_ptr, count1))
                                err = -EFAULT;
-                       spin_lock_irqsave(&runtime->lock, flags);
+                       spin_lock_irqsave(&substream->lock, flags);
                        if (err)
                                goto out;
                }
@@ -1167,7 +1224,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
        }
  out:
        snd_rawmidi_buffer_unref(runtime);
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return result > 0 ? result : err;
 }
 
@@ -1196,31 +1253,31 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
        snd_rawmidi_input_trigger(substream, 1);
        result = 0;
        while (count > 0) {
-               spin_lock_irq(&runtime->lock);
+               spin_lock_irq(&substream->lock);
                while (!__snd_rawmidi_ready(runtime)) {
                        wait_queue_entry_t wait;
 
                        if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
-                               spin_unlock_irq(&runtime->lock);
+                               spin_unlock_irq(&substream->lock);
                                return result > 0 ? result : -EAGAIN;
                        }
                        init_waitqueue_entry(&wait, current);
                        add_wait_queue(&runtime->sleep, &wait);
                        set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irq(&runtime->lock);
+                       spin_unlock_irq(&substream->lock);
                        schedule();
                        remove_wait_queue(&runtime->sleep, &wait);
                        if (rfile->rmidi->card->shutdown)
                                return -ENODEV;
                        if (signal_pending(current))
                                return result > 0 ? result : -ERESTARTSYS;
-                       spin_lock_irq(&runtime->lock);
+                       spin_lock_irq(&substream->lock);
                        if (!runtime->avail) {
-                               spin_unlock_irq(&runtime->lock);
+                               spin_unlock_irq(&substream->lock);
                                return result > 0 ? result : -EIO;
                        }
                }
-               spin_unlock_irq(&runtime->lock);
+               spin_unlock_irq(&substream->lock);
                count1 = snd_rawmidi_kernel_read1(substream,
                                                  (unsigned char __user *)buf,
                                                  NULL/*kernelbuf*/,
@@ -1242,23 +1299,25 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
  */
 int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
 {
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       struct snd_rawmidi_runtime *runtime;
        int result;
        unsigned long flags;
 
-       if (runtime->buffer == NULL) {
+       spin_lock_irqsave(&substream->lock, flags);
+       runtime = substream->runtime;
+       if (!substream->opened || !runtime || !runtime->buffer) {
                rmidi_dbg(substream->rmidi,
                          "snd_rawmidi_transmit_empty: output is not active!!!\n");
-               return 1;
+               result = 1;
+       } else {
+               result = runtime->avail >= runtime->buffer_size;
        }
-       spin_lock_irqsave(&runtime->lock, flags);
-       result = runtime->avail >= runtime->buffer_size;
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
 
-/**
+/*
  * __snd_rawmidi_transmit_peek - copy data from the internal buffer
  * @substream: the rawmidi substream
  * @buffer: the buffer pointer
@@ -1266,8 +1325,8 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
  *
  * This is a variant of snd_rawmidi_transmit_peek() without spinlock.
  */
-int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
-                             unsigned char *buffer, int count)
+static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
+                                      unsigned char *buffer, int count)
 {
        int result, count1;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
@@ -1304,7 +1363,6 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
       __skip:
        return result;
 }
-EXPORT_SYMBOL(__snd_rawmidi_transmit_peek);
 
 /**
  * snd_rawmidi_transmit_peek - copy data from the internal buffer
@@ -1323,25 +1381,28 @@ EXPORT_SYMBOL(__snd_rawmidi_transmit_peek);
 int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                              unsigned char *buffer, int count)
 {
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
        int result;
        unsigned long flags;
 
-       spin_lock_irqsave(&runtime->lock, flags);
-       result = __snd_rawmidi_transmit_peek(substream, buffer, count);
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
+       if (!substream->opened || !substream->runtime)
+               result = -EBADFD;
+       else
+               result = __snd_rawmidi_transmit_peek(substream, buffer, count);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
 
-/**
+/*
  * __snd_rawmidi_transmit_ack - acknowledge the transmission
  * @substream: the rawmidi substream
  * @count: the transferred count
  *
  * This is a variant of __snd_rawmidi_transmit_ack() without spinlock.
  */
-int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
+static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
+                                     int count)
 {
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
@@ -1361,7 +1422,6 @@ int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int coun
        }
        return count;
 }
-EXPORT_SYMBOL(__snd_rawmidi_transmit_ack);
 
 /**
  * snd_rawmidi_transmit_ack - acknowledge the transmission
@@ -1376,13 +1436,15 @@ EXPORT_SYMBOL(__snd_rawmidi_transmit_ack);
  */
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
 {
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
        int result;
        unsigned long flags;
 
-       spin_lock_irqsave(&runtime->lock, flags);
-       result = __snd_rawmidi_transmit_ack(substream, count);
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
+       if (!substream->opened || !substream->runtime)
+               result = -EBADFD;
+       else
+               result = __snd_rawmidi_transmit_ack(substream, count);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
@@ -1400,11 +1462,10 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                         unsigned char *buffer, int count)
 {
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
        int result;
        unsigned long flags;
 
-       spin_lock_irqsave(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
        if (!substream->opened)
                result = -EBADFD;
        else {
@@ -1414,7 +1475,7 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                else
                        result = __snd_rawmidi_transmit_ack(substream, count);
        }
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit);
@@ -1427,16 +1488,18 @@ EXPORT_SYMBOL(snd_rawmidi_transmit);
  */
 int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
 {
-       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       struct snd_rawmidi_runtime *runtime;
        unsigned long flags;
        int count = 0;
 
-       spin_lock_irqsave(&runtime->lock, flags);
-       if (runtime->avail < runtime->buffer_size) {
+       spin_lock_irqsave(&substream->lock, flags);
+       runtime = substream->runtime;
+       if (substream->opened && runtime &&
+           runtime->avail < runtime->buffer_size) {
                count = runtime->buffer_size - runtime->avail;
                __snd_rawmidi_transmit_ack(substream, count);
        }
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_unlock_irqrestore(&substream->lock, flags);
        return count;
 }
 EXPORT_SYMBOL(snd_rawmidi_proceed);
@@ -1457,10 +1520,10 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                return -EINVAL;
 
        result = 0;
-       spin_lock_irqsave(&runtime->lock, flags);
+       spin_lock_irqsave(&substream->lock, flags);
        if (substream->append) {
                if ((long)runtime->avail < count) {
-                       spin_unlock_irqrestore(&runtime->lock, flags);
+                       spin_unlock_irqrestore(&substream->lock, flags);
                        return -EAGAIN;
                }
        }
@@ -1482,14 +1545,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                        memcpy(runtime->buffer + appl_ptr,
                               kernelbuf + result, count1);
                else if (userbuf) {
-                       spin_unlock_irqrestore(&runtime->lock, flags);
+                       spin_unlock_irqrestore(&substream->lock, flags);
                        if (copy_from_user(runtime->buffer + appl_ptr,
                                           userbuf + result, count1)) {
-                               spin_lock_irqsave(&runtime->lock, flags);
+                               spin_lock_irqsave(&substream->lock, flags);
                                result = result > 0 ? result : -EFAULT;
                                goto __end;
                        }
-                       spin_lock_irqsave(&runtime->lock, flags);
+                       spin_lock_irqsave(&substream->lock, flags);
                }
                result += count1;
                count -= count1;
@@ -1497,7 +1560,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
       __end:
        count1 = runtime->avail < runtime->buffer_size;
        snd_rawmidi_buffer_unref(runtime);
-       spin_unlock_irqrestore(&runtime->lock, flags);
+       spin_unlock_irqrestore(&substream->lock, flags);
        if (count1)
                snd_rawmidi_output_trigger(substream, 1);
        return result;
@@ -1527,31 +1590,31 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
                return -EIO;
        result = 0;
        while (count > 0) {
-               spin_lock_irq(&runtime->lock);
+               spin_lock_irq(&substream->lock);
                while (!snd_rawmidi_ready_append(substream, count)) {
                        wait_queue_entry_t wait;
 
                        if (file->f_flags & O_NONBLOCK) {
-                               spin_unlock_irq(&runtime->lock);
+                               spin_unlock_irq(&substream->lock);
                                return result > 0 ? result : -EAGAIN;
                        }
                        init_waitqueue_entry(&wait, current);
                        add_wait_queue(&runtime->sleep, &wait);
                        set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irq(&runtime->lock);
+                       spin_unlock_irq(&substream->lock);
                        timeout = schedule_timeout(30 * HZ);
                        remove_wait_queue(&runtime->sleep, &wait);
                        if (rfile->rmidi->card->shutdown)
                                return -ENODEV;
                        if (signal_pending(current))
                                return result > 0 ? result : -ERESTARTSYS;
-                       spin_lock_irq(&runtime->lock);
+                       spin_lock_irq(&substream->lock);
                        if (!runtime->avail && !timeout) {
-                               spin_unlock_irq(&runtime->lock);
+                               spin_unlock_irq(&substream->lock);
                                return result > 0 ? result : -EIO;
                        }
                }
-               spin_unlock_irq(&runtime->lock);
+               spin_unlock_irq(&substream->lock);
                count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count);
                if (count1 < 0)
                        return result > 0 ? result : count1;
@@ -1562,7 +1625,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
                count -= count1;
        }
        if (file->f_flags & O_DSYNC) {
-               spin_lock_irq(&runtime->lock);
+               spin_lock_irq(&substream->lock);
                while (runtime->avail != runtime->buffer_size) {
                        wait_queue_entry_t wait;
                        unsigned int last_avail = runtime->avail;
@@ -1570,16 +1633,16 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
                        init_waitqueue_entry(&wait, current);
                        add_wait_queue(&runtime->sleep, &wait);
                        set_current_state(TASK_INTERRUPTIBLE);
-                       spin_unlock_irq(&runtime->lock);
+                       spin_unlock_irq(&substream->lock);
                        timeout = schedule_timeout(30 * HZ);
                        remove_wait_queue(&runtime->sleep, &wait);
                        if (signal_pending(current))
                                return result > 0 ? result : -ERESTARTSYS;
                        if (runtime->avail == last_avail && !timeout)
                                return result > 0 ? result : -EIO;
-                       spin_lock_irq(&runtime->lock);
+                       spin_lock_irq(&substream->lock);
                }
-               spin_unlock_irq(&runtime->lock);
+               spin_unlock_irq(&substream->lock);
        }
        return result;
 }
@@ -1650,10 +1713,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                                    "  Owner PID    : %d\n",
                                    pid_vnr(substream->pid));
                                runtime = substream->runtime;
-                               spin_lock_irq(&runtime->lock);
+                               spin_lock_irq(&substream->lock);
                                buffer_size = runtime->buffer_size;
                                avail = runtime->avail;
-                               spin_unlock_irq(&runtime->lock);
+                               spin_unlock_irq(&substream->lock);
                                snd_iprintf(buffer,
                                    "  Mode         : %s\n"
                                    "  Buffer size  : %lu\n"
@@ -1677,11 +1740,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
                                            "  Owner PID    : %d\n",
                                            pid_vnr(substream->pid));
                                runtime = substream->runtime;
-                               spin_lock_irq(&runtime->lock);
+                               spin_lock_irq(&substream->lock);
                                buffer_size = runtime->buffer_size;
                                avail = runtime->avail;
                                xruns = runtime->xruns;
-                               spin_unlock_irq(&runtime->lock);
+                               spin_unlock_irq(&substream->lock);
                                snd_iprintf(buffer,
                                            "  Buffer size  : %lu\n"
                                            "  Avail        : %lu\n"
@@ -1733,6 +1796,7 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
                substream->number = idx;
                substream->rmidi = rmidi;
                substream->pstr = stream;
+               spin_lock_init(&substream->lock);
                list_add_tail(&substream->list, &stream->substreams);
                stream->substream_count++;
        }
index b3214baa89193ae83fabc040fcc4fe328c8a5fc4..e08a37c23add85141da87d5fa301378bc9598e70 100644 (file)
@@ -83,7 +83,7 @@ struct snd_timer_user {
        unsigned int filter;
        struct timespec64 tstamp;               /* trigger tstamp */
        wait_queue_head_t qchange_sleep;
-       struct fasync_struct *fasync;
+       struct snd_fasync *fasync;
        struct mutex ioctl_lock;
 };
 
@@ -1345,7 +1345,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
        }
       __wake:
        spin_unlock(&tu->qlock);
-       kill_fasync(&tu->fasync, SIGIO, POLL_IN);
+       snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
        wake_up(&tu->qchange_sleep);
 }
 
@@ -1383,7 +1383,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
        spin_lock_irqsave(&tu->qlock, flags);
        snd_timer_user_append_to_tqueue(tu, &r1);
        spin_unlock_irqrestore(&tu->qlock, flags);
-       kill_fasync(&tu->fasync, SIGIO, POLL_IN);
+       snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
        wake_up(&tu->qchange_sleep);
 }
 
@@ -1453,7 +1453,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
        spin_unlock(&tu->qlock);
        if (append == 0)
                return;
-       kill_fasync(&tu->fasync, SIGIO, POLL_IN);
+       snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
        wake_up(&tu->qchange_sleep);
 }
 
@@ -1521,6 +1521,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
                        snd_timer_instance_free(tu->timeri);
                }
                mutex_unlock(&tu->ioctl_lock);
+               snd_fasync_free(tu->fasync);
                kfree(tu->queue);
                kfree(tu->tqueue);
                kfree(tu);
@@ -2135,7 +2136,7 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       return fasync_helper(fd, file, on, &tu->fasync);
+       return snd_fasync_helper(fd, file, on, &tu->fasync);
 }
 
 static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
index ab36f9898711a60aba8798a7eea1f88d86bab993..d0f11f37889b58e3ef771ba4605fc2e683c3ecca 100644 (file)
@@ -494,7 +494,8 @@ EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
  * @arg: optional function argument
  *
  * Apply the function @func to each follower kctl of the given vmaster kctl.
- * Returns 0 if successful, or a negative error code.
+ *
+ * Return: 0 if successful, or a negative error code
  */
 int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl,
                                    int (*func)(struct snd_kcontrol *vfollower,
index b072392725c74e075fde26aceb6f26641dd2ebcf..a42f66f561f57f0cb15332bc6aa6e1d36a9ed79a 100644 (file)
 #include <sound/hda_register.h>
 #include <sound/hdaudio_ext.h>
 
-/*
- * maximum HDAC capablities we should parse to avoid endless looping:
- * currently we have 4 extended caps, so this is future proof for now.
- * extend when this limit is seen meeting in real HW
- */
-#define HDAC_MAX_CAPS 10
-
 /*
  * processing pipe helpers - these helpers are useful for dealing with HDA
  * new capability of processing pipelines
index 71db8592b33dbf666849f2922aaf68435055088d..d497414a5538fab86717a5a58f087fe4b454cbd7 100644 (file)
@@ -183,7 +183,7 @@ static void snd_hdac_bus_process_unsol_events(struct work_struct *work)
                if (!(caddr & (1 << 4))) /* no unsolicited event? */
                        continue;
                codec = bus->caddr_tbl[caddr & 0x0f];
-               if (!codec || !codec->dev.driver)
+               if (!codec || !codec->registered)
                        continue;
                spin_unlock_irq(&bus->reg_lock);
                drv = drv_to_hdac_driver(codec->dev.driver);
index f7bd6e2db085bb666bcba9618cfdeb15541455e8..9a60bfdb39bac564b07a6e2a19206d224b1160a8 100644 (file)
@@ -474,11 +474,8 @@ static void azx_int_disable(struct hdac_bus *bus)
        list_for_each_entry(azx_dev, &bus->stream_list, list)
                snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
 
-       /* disable SIE for all streams */
-       snd_hdac_chip_writeb(bus, INTCTL, 0);
-
-       /* disable controller CIE and GIE */
-       snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN, 0);
+       /* disable SIE for all streams & disable controller CIE and GIE */
+       snd_hdac_chip_writel(bus, INTCTL, 0);
 }
 
 /* clear interrupts */
index 0d7771fca9f06642059e84ce688ad8498d2a854d..e47de49a32e3e4e93982f18ce5c6c29185014bc2 100644 (file)
@@ -22,7 +22,7 @@ static ssize_t type##_show(struct device *dev,                        \
                           char *buf)                           \
 {                                                              \
        struct hdac_device *codec = dev_to_hdac_dev(dev);       \
-       return sprintf(buf, "0x%x\n", codec->type);             \
+       return sysfs_emit(buf, "0x%x\n", codec->type);          \
 } \
 static DEVICE_ATTR_RO(type)
 
@@ -32,8 +32,8 @@ static ssize_t type##_show(struct device *dev,                        \
                                        char *buf)              \
 {                                                              \
        struct hdac_device *codec = dev_to_hdac_dev(dev);       \
-       return sprintf(buf, "%s\n",                             \
-                      codec->type ? codec->type : "");         \
+       return sysfs_emit(buf, "%s\n",                          \
+                         codec->type ? codec->type : "");      \
 } \
 static DEVICE_ATTR_RO(type)
 
@@ -161,7 +161,7 @@ static struct kobj_type widget_ktype = {
 static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid,
                        struct widget_attribute *attr, char *buf)
 {
-       return sprintf(buf, "0x%08x\n", get_wcaps(codec, nid));
+       return sysfs_emit(buf, "0x%08x\n", get_wcaps(codec, nid));
 }
 
 static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
@@ -169,8 +169,8 @@ static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
 {
        if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
                return 0;
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
 }
 
 static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
@@ -182,7 +182,7 @@ static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
                return 0;
        if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
                return 0;
-       return sprintf(buf, "0x%08x\n", val);
+       return sysfs_emit(buf, "0x%08x\n", val);
 }
 
 static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid)
@@ -203,8 +203,8 @@ static ssize_t pcm_caps_show(struct hdac_device *codec, hda_nid_t nid,
 {
        if (!has_pcm_cap(codec, nid))
                return 0;
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_PCM));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_PCM));
 }
 
 static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
@@ -212,8 +212,8 @@ static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
 {
        if (!has_pcm_cap(codec, nid))
                return 0;
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_STREAM));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_STREAM));
 }
 
 static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
@@ -221,8 +221,8 @@ static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
 {
        if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
                return 0;
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
 }
 
 static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
@@ -230,8 +230,8 @@ static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
 {
        if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                return 0;
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
 }
 
 static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
@@ -239,15 +239,15 @@ static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
 {
        if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER))
                return 0;
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
 }
 
 static ssize_t gpio_caps_show(struct hdac_device *codec, hda_nid_t nid,
                              struct widget_attribute *attr, char *buf)
 {
-       return sprintf(buf, "0x%08x\n",
-                      snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP));
+       return sysfs_emit(buf, "0x%08x\n",
+                         snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP));
 }
 
 static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid,
@@ -261,8 +261,8 @@ static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid,
        if (nconns <= 0)
                return nconns;
        for (i = 0; i < nconns; i++)
-               ret += sprintf(buf + ret, "%s0x%02x", i ? " " : "", list[i]);
-       ret += sprintf(buf + ret, "\n");
+               ret += sysfs_emit_at(buf,  ret, "%s0x%02x", i ? " " : "", list[i]);
+       ret += sysfs_emit_at(buf, ret, "\n");
        return ret;
 }
 
index ec9cbb219bc1427ccd08d20a9ffec0656556c3f7..d84ffdf47210ebbbb9165c3f4f5b400266ad3e79 100644 (file)
@@ -413,6 +413,11 @@ static const struct config_entry config_table[] = {
                .device = 0x7a50,
        },
        /* Alderlake-P */
+       {
+               .flags = FLAG_SOF,
+               .device = 0x51c8,
+               .codec_hid =  &essx_83x6,
+       },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
                .device = 0x51c8,
index 70af6c8150898e2633e2ea9b55e796f3b974018c..2cc493434a8fd47962dd0a4021ba30da22f26f80 100644 (file)
@@ -19,37 +19,48 @@ struct hdac_codec;
 TRACE_EVENT(hda_send_cmd,
        TP_PROTO(struct hdac_bus *bus, unsigned int cmd),
        TP_ARGS(bus, cmd),
-       TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+       TP_STRUCT__entry(
+               __string(name, dev_name((bus)->dev))
+               __field(u32, cmd)
+       ),
        TP_fast_assign(
-               snprintf(__get_str(msg), HDAC_MSG_MAX,
-                        "[%s:%d] val=0x%08x",
-                        dev_name((bus)->dev), (cmd) >> 28, cmd);
+               __assign_str(name, dev_name((bus)->dev));
+               __entry->cmd = cmd;
        ),
-       TP_printk("%s", __get_str(msg))
+       TP_printk("[%s:%d] val=0x%08x", __get_str(name), __entry->cmd >> 28, __entry->cmd)
 );
 
 TRACE_EVENT(hda_get_response,
        TP_PROTO(struct hdac_bus *bus, unsigned int addr, unsigned int res),
        TP_ARGS(bus, addr, res),
-       TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+       TP_STRUCT__entry(
+               __string(name, dev_name((bus)->dev))
+               __field(u32, addr)
+               __field(u32, res)
+       ),
        TP_fast_assign(
-               snprintf(__get_str(msg), HDAC_MSG_MAX,
-                        "[%s:%d] val=0x%08x",
-                        dev_name((bus)->dev), addr, res);
+               __assign_str(name, dev_name((bus)->dev));
+               __entry->addr = addr;
+               __entry->res = res;
        ),
-       TP_printk("%s", __get_str(msg))
+       TP_printk("[%s:%d] val=0x%08x", __get_str(name), __entry->addr, __entry->res)
 );
 
 TRACE_EVENT(hda_unsol_event,
        TP_PROTO(struct hdac_bus *bus, u32 res, u32 res_ex),
        TP_ARGS(bus, res, res_ex),
-       TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+       TP_STRUCT__entry(
+               __string(name, dev_name((bus)->dev))
+               __field(u32, res)
+               __field(u32, res_ex)
+       ),
        TP_fast_assign(
-               snprintf(__get_str(msg), HDAC_MSG_MAX,
-                        "[%s:%d] res=0x%08x, res_ex=0x%08x",
-                        dev_name((bus)->dev), res_ex & 0x0f, res, res_ex);
+               __assign_str(name, dev_name((bus)->dev));
+               __entry->res = res;
+               __entry->res_ex = res_ex;
        ),
-       TP_printk("%s", __get_str(msg))
+       TP_printk("[%s:%d] res=0x%08x, res_ex=0x%08x", __get_str(name),
+                 __entry->res_ex & 0x0f, __entry->res, __entry->res_ex)
 );
 
 DECLARE_EVENT_CLASS(hdac_stream,
index 2aaaa68071744ec9c7e25062788dbb821255cdb6..13ce96148fa3b2c3a4b52ab7d75e5325caf07478 100644 (file)
@@ -581,8 +581,6 @@ demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes)
        int i;
        unsigned char *end = src + src_bytes;
     
-       end = src + src_bytes;
-
        /* NOTE: src and dst *CAN* point to the same address */
 
        for (i = 0; src != end; i++) {
index aa4d0635312608134d7f2423d110b1269c48c830..88d902997b7491203858dedcf392b1e7df2c4719 100644 (file)
@@ -388,7 +388,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
 /* SUBSYSTEM */
 
 /* create an adapter object and initialise it based on resource information
- * passed in in the message
+ * passed in the message
  * NOTE - you cannot use this function AND the FindAdapters function at the
  * same time, the application must use only one of them to get the adapters
  */
index 3d6914c64c4a860829da64b0921e23f07c14e8f2..27e11b5f70b97dc982867df42074fc35142517d3 100644 (file)
@@ -445,7 +445,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
 /* SUBSYSTEM */
 
 /** Create an adapter object and initialise it based on resource information
- * passed in in the message
+ * passed in the message
  * *** NOTE - you cannot use this function AND the FindAdapters function at the
  * same time, the application must use only one of them to get the adapters ***
  */
index 9d26535f3fa34484041d5fd8d920bf8ed038533e..edb3f17637192f13e65901d699e4f335334ccf4d 100644 (file)
@@ -324,7 +324,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
                return NULL;
        }
        /* fill buffer addresses but pointers are not stored so that
-        * snd_free_pci_page() is not called in in synth_free()
+        * snd_free_pci_page() is not called in synth_free()
         */
        idx = 0;
        for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
index 94efe347a97a986f3d5f175bcb3f320278e6f284..89210b2c734241c940381c35817fb8abf703bb30 100644 (file)
@@ -8,7 +8,7 @@
 /* Power-Management-Code ( CONFIG_PM )
  * for ens1371 only ( FIXME )
  * derived from cs4281.c, atiixp.c and via82xx.c
- * using http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ 
+ * using https://www.kernel.org/doc/html/latest/sound/kernel-api/writing-an-alsa-driver.html
  * by Kurt J. Bosch
  */
 
index 79ade4787d95b5171c50695c3b21915b933db2d1..a8e8cf98befa1ccd41dddc584b41bc0dd0c9c606 100644 (file)
@@ -93,16 +93,21 @@ config SND_HDA_PATCH_LOADER
 
 config SND_HDA_SCODEC_CS35L41
        tristate
+       select SND_HDA_GENERIC
+       select REGMAP_IRQ
+
+config SND_HDA_CS_DSP_CONTROLS
+       tristate
+       select CS_DSP
 
 config SND_HDA_SCODEC_CS35L41_I2C
        tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
        depends on I2C
        depends on ACPI
        depends on SND_SOC
-       select SND_HDA_GENERIC
        select SND_SOC_CS35L41_LIB
        select SND_HDA_SCODEC_CS35L41
-       select REGMAP_IRQ
+       select SND_HDA_CS_DSP_CONTROLS
        help
          Say Y or M here to include CS35L41 I2C HD-audio side codec support
          in snd-hda-intel driver, such as ALC287.
@@ -115,10 +120,9 @@ config SND_HDA_SCODEC_CS35L41_SPI
        depends on SPI_MASTER
        depends on ACPI
        depends on SND_SOC
-       select SND_HDA_GENERIC
        select SND_SOC_CS35L41_LIB
        select SND_HDA_SCODEC_CS35L41
-       select REGMAP_IRQ
+       select SND_HDA_CS_DSP_CONTROLS
        help
          Say Y or M here to include CS35L41 SPI HD-audio side codec support
          in snd-hda-intel driver, such as ALC287.
index 3e7bc608d45f27cb8ab4d21bfe446c1ac4219931..00d3061044842d50fe3b63a703cddcc5fc9f875c 100644 (file)
@@ -31,6 +31,7 @@ snd-hda-codec-hdmi-objs :=    patch_hdmi.o hda_eld.o
 snd-hda-scodec-cs35l41-objs :=         cs35l41_hda.o
 snd-hda-scodec-cs35l41-i2c-objs :=     cs35l41_hda_i2c.o
 snd-hda-scodec-cs35l41-spi-objs :=     cs35l41_hda_spi.o
+snd-hda-cs-dsp-ctls-objs :=            hda_cs_dsp_ctl.o
 
 # common driver
 obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
@@ -54,6 +55,7 @@ obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
+obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
 
 # this must be the last entry after codec drivers;
 # otherwise the codec patches won't be hooked before the PCI probe
index cce27a86267f6924919f6311b3cb4c5c7a55ac2d..129bffb431c22e7f38c4e90dc7385a2899458870 100644 (file)
 
 #include <linux/acpi.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <sound/hda_codec.h>
+#include <sound/soc.h>
+#include <linux/pm_runtime.h>
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_generic.h"
 #include "hda_component.h"
 #include "cs35l41_hda.h"
+#include "hda_cs_dsp_ctl.h"
+
+#define CS35L41_FIRMWARE_ROOT "cirrus/"
+#define CS35L41_PART "cs35l41"
+
+#define HALO_STATE_DSP_CTL_NAME                "HALO_STATE"
+#define HALO_STATE_DSP_CTL_TYPE                5
+#define HALO_STATE_DSP_CTL_ALG         262308
+#define CAL_R_DSP_CTL_NAME             "CAL_R"
+#define CAL_STATUS_DSP_CTL_NAME                "CAL_STATUS"
+#define CAL_CHECKSUM_DSP_CTL_NAME      "CAL_CHECKSUM"
+#define CAL_AMBIENT_DSP_CTL_NAME       "CAL_AMBIENT"
+#define CAL_DSP_CTL_TYPE               5
+#define CAL_DSP_CTL_ALG                        205
+
+static bool firmware_autostart = 1;
+module_param(firmware_autostart, bool, 0444);
+MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot"
+                            "(0=Disable, 1=Enable) (default=1); ");
 
 static const struct reg_sequence cs35l41_hda_config[] = {
        { CS35L41_PLL_CLK_CTRL,         0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
+       { CS35L41_DSP_CLK_CTRL,         0x00000003 }, // DSP CLK EN
        { CS35L41_GLOBAL_CLK_CTRL,      0x00000003 }, // GLOBAL_FS = 48 kHz
        { CS35L41_SP_ENABLES,           0x00010000 }, // ASP_RX1_EN = 1
        { CS35L41_SP_RATE_CTRL,         0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
        { CS35L41_SP_FORMAT,            0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
+       { CS35L41_SP_HIZ_CTRL,          0x00000002 }, // Hi-Z unused
+       { CS35L41_SP_TX_WL,             0x00000018 }, // 24 cycles/slot
+       { CS35L41_SP_RX_WL,             0x00000018 }, // 24 cycles/slot
        { CS35L41_DAC_PCM1_SRC,         0x00000008 }, // DACPCM1_SRC = ASPRX1
+       { CS35L41_ASP_TX1_SRC,          0x00000018 }, // ASPTX1 SRC = VMON
+       { CS35L41_ASP_TX2_SRC,          0x00000019 }, // ASPTX2 SRC = IMON
+       { CS35L41_ASP_TX3_SRC,          0x00000032 }, // ASPTX3 SRC = ERRVOL
+       { CS35L41_ASP_TX4_SRC,          0x00000033 }, // ASPTX4 SRC = CLASSH_TGT
+       { CS35L41_DSP1_RX1_SRC,         0x00000008 }, // DSP1RX1 SRC = ASPRX1
+       { CS35L41_DSP1_RX2_SRC,         0x00000009 }, // DSP1RX2 SRC = ASPRX2
+       { CS35L41_DSP1_RX3_SRC,         0x00000018 }, // DSP1RX3 SRC = VMON
+       { CS35L41_DSP1_RX4_SRC,         0x00000019 }, // DSP1RX4 SRC = IMON
+       { CS35L41_DSP1_RX5_SRC,         0x00000020 }, // DSP1RX5 SRC = ERRVOL
        { CS35L41_AMP_DIG_VOL_CTRL,     0x00000000 }, // AMP_VOL_PCM  0.0 dB
        { CS35L41_AMP_GAIN_CTRL,        0x00000084 }, // AMP_GAIN_PCM 4.5 dB
 };
 
+static const struct reg_sequence cs35l41_hda_config_dsp[] = {
+       { CS35L41_PLL_CLK_CTRL,         0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
+       { CS35L41_DSP_CLK_CTRL,         0x00000003 }, // DSP CLK EN
+       { CS35L41_GLOBAL_CLK_CTRL,      0x00000003 }, // GLOBAL_FS = 48 kHz
+       { CS35L41_SP_ENABLES,           0x00010001 }, // ASP_RX1_EN = 1, ASP_TX1_EN = 1
+       { CS35L41_SP_RATE_CTRL,         0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
+       { CS35L41_SP_FORMAT,            0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
+       { CS35L41_SP_HIZ_CTRL,          0x00000003 }, // Hi-Z unused/disabled
+       { CS35L41_SP_TX_WL,             0x00000018 }, // 24 cycles/slot
+       { CS35L41_SP_RX_WL,             0x00000018 }, // 24 cycles/slot
+       { CS35L41_DAC_PCM1_SRC,         0x00000032 }, // DACPCM1_SRC = ERR_VOL
+       { CS35L41_ASP_TX1_SRC,          0x00000018 }, // ASPTX1 SRC = VMON
+       { CS35L41_ASP_TX2_SRC,          0x00000019 }, // ASPTX2 SRC = IMON
+       { CS35L41_ASP_TX3_SRC,          0x00000028 }, // ASPTX3 SRC = VPMON
+       { CS35L41_ASP_TX4_SRC,          0x00000029 }, // ASPTX4 SRC = VBSTMON
+       { CS35L41_DSP1_RX1_SRC,         0x00000008 }, // DSP1RX1 SRC = ASPRX1
+       { CS35L41_DSP1_RX2_SRC,         0x00000008 }, // DSP1RX2 SRC = ASPRX1
+       { CS35L41_DSP1_RX3_SRC,         0x00000018 }, // DSP1RX3 SRC = VMON
+       { CS35L41_DSP1_RX4_SRC,         0x00000019 }, // DSP1RX4 SRC = IMON
+       { CS35L41_DSP1_RX5_SRC,         0x00000029 }, // DSP1RX5 SRC = VBSTMON
+       { CS35L41_AMP_DIG_VOL_CTRL,     0x00000000 }, // AMP_VOL_PCM  0.0 dB
+       { CS35L41_AMP_GAIN_CTRL,        0x00000233 }, // AMP_GAIN_PCM = 17.5dB AMP_GAIN_PDM = 19.5dB
+};
+
 static const struct reg_sequence cs35l41_hda_mute[] = {
        { CS35L41_AMP_GAIN_CTRL,        0x00000000 }, // AMP_GAIN_PCM 0.5 dB
        { CS35L41_AMP_DIG_VOL_CTRL,     0x0000A678 }, // AMP_VOL_PCM Mute
 };
 
+static int cs35l41_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
+{
+       struct cs35l41_hda *cs35l41 = container_of(cs_ctl->dsp, struct cs35l41_hda, cs_dsp);
+       struct hda_cs_dsp_ctl_info info;
+
+       info.device_name = cs35l41->amp_name;
+       info.fw_type = cs35l41->firmware_type;
+       info.card = cs35l41->codec->card;
+
+       return hda_cs_dsp_control_add(cs_ctl, &info);
+}
+
+static const struct cs_dsp_client_ops client_ops = {
+       .control_add = cs35l41_control_add,
+       .control_remove = hda_cs_dsp_control_remove,
+};
+
+static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
+                                        const struct firmware **firmware, char **filename,
+                                        const char *dir, const char *ssid, const char *amp_name,
+                                        int spkid, const char *filetype)
+{
+       const char * const dsp_name = cs35l41->cs_dsp.name;
+       char *s, c;
+       int ret = 0;
+
+       if (spkid > -1 && ssid && amp_name)
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d-%s.%s", dir, CS35L41_PART,
+                                     dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+                                     ssid, spkid, amp_name, filetype);
+       else if (spkid > -1 && ssid)
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-spkid%d.%s", dir, CS35L41_PART,
+                                     dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+                                     ssid, spkid, filetype);
+       else if (ssid && amp_name)
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, CS35L41_PART,
+                                     dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+                                     ssid, amp_name, filetype);
+       else if (ssid)
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, CS35L41_PART,
+                                     dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+                                     ssid, filetype);
+       else
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, CS35L41_PART,
+                                     dsp_name, hda_cs_dsp_fw_ids[cs35l41->firmware_type],
+                                     filetype);
+
+       if (*filename == NULL)
+               return -ENOMEM;
+
+       /*
+        * Make sure that filename is lower-case and any non alpha-numeric
+        * characters except full stop and '/' are replaced with hyphens.
+        */
+       s = *filename;
+       while (*s) {
+               c = *s;
+               if (isalnum(c))
+                       *s = tolower(c);
+               else if (c != '.' && c != '/')
+                       *s = '-';
+               s++;
+       }
+
+       ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
+       if (ret != 0) {
+               dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
+               kfree(*filename);
+               *filename = NULL;
+       }
+
+       return ret;
+}
+
+static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
+                                               const struct firmware **wmfw_firmware,
+                                               char **wmfw_filename,
+                                               const struct firmware **coeff_firmware,
+                                               char **coeff_filename)
+{
+       int ret;
+
+       /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT,
+                                           cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                           cs35l41->speaker_id, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                             CS35L41_FIRMWARE_ROOT,
+                                             cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                             cs35l41->speaker_id, "bin");
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                           cs35l41->amp_name, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                             CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                             cs35l41->amp_name, cs35l41->speaker_id, "bin");
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                           NULL, cs35l41->speaker_id, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   CS35L41_FIRMWARE_ROOT,
+                                                   cs35l41->acpi_subsystem_id,
+                                                   cs35l41->amp_name, cs35l41->speaker_id, "bin");
+               if (ret)
+                       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
+                       cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                               CS35L41_FIRMWARE_ROOT,
+                                               cs35l41->acpi_subsystem_id,
+                                               NULL, cs35l41->speaker_id, "bin");
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                           NULL, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   CS35L41_FIRMWARE_ROOT,
+                                                   cs35l41->acpi_subsystem_id,
+                                                   cs35l41->amp_name, cs35l41->speaker_id, "bin");
+               if (ret)
+                       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
+                       cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                     CS35L41_FIRMWARE_ROOT,
+                                                     cs35l41->acpi_subsystem_id,
+                                                     NULL, cs35l41->speaker_id, "bin");
+               return 0;
+       }
+
+       /* fallback try cirrus/part-dspN-fwtype.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
+       if (!ret) {
+               /* fallback try cirrus/part-dspN-fwtype.bin */
+               cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                             CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
+               return 0;
+       }
+
+       dev_warn(cs35l41->dev, "Failed to request firmware\n");
+
+       return ret;
+}
+
+static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
+                                         const struct firmware **wmfw_firmware,
+                                         char **wmfw_filename,
+                                         const struct firmware **coeff_firmware,
+                                         char **coeff_filename)
+{
+       int ret;
+
+       if (cs35l41->speaker_id > -1)
+               return cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
+                                                           coeff_firmware, coeff_filename);
+
+       /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                           cs35l41->amp_name, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
+               cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                             CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                             cs35l41->amp_name, -1, "bin");
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, cs35l41->acpi_subsystem_id,
+                                           NULL, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   CS35L41_FIRMWARE_ROOT,
+                                                   cs35l41->acpi_subsystem_id,
+                                                   cs35l41->amp_name, -1, "bin");
+               if (ret)
+                       /* try cirrus/part-dspN-fwtype-sub.bin */
+                       cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                     CS35L41_FIRMWARE_ROOT,
+                                                     cs35l41->acpi_subsystem_id,
+                                                     NULL, -1, "bin");
+               return 0;
+       }
+
+       /* fallback try cirrus/part-dspN-fwtype.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "wmfw");
+       if (!ret) {
+               /* fallback try cirrus/part-dspN-fwtype.bin */
+               cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                             CS35L41_FIRMWARE_ROOT, NULL, NULL, -1, "bin");
+               return 0;
+       }
+
+       dev_warn(cs35l41->dev, "Failed to request firmware\n");
+
+       return ret;
+}
+
+#if IS_ENABLED(CONFIG_EFI)
+static int cs35l41_apply_calibration(struct cs35l41_hda *cs35l41, unsigned int ambient,
+                                    unsigned int r0, unsigned int status, unsigned int checksum)
+{
+       int ret;
+
+       ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_AMBIENT_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
+                                  CAL_DSP_CTL_ALG, &ambient, 4);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_AMBIENT_DSP_CTL_NAME,
+                       ret);
+               return ret;
+       }
+       ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_R_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
+                                  CAL_DSP_CTL_ALG, &r0, 4);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_R_DSP_CTL_NAME, ret);
+               return ret;
+       }
+       ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_STATUS_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
+                                  CAL_DSP_CTL_ALG, &status, 4);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_STATUS_DSP_CTL_NAME,
+                       ret);
+               return ret;
+       }
+       ret = hda_cs_dsp_write_ctl(&cs35l41->cs_dsp, CAL_CHECKSUM_DSP_CTL_NAME, CAL_DSP_CTL_TYPE,
+                                  CAL_DSP_CTL_ALG, &checksum, 4);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot Write Control: %s - %d\n", CAL_CHECKSUM_DSP_CTL_NAME,
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41)
+{
+       static efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe,
+                                             0x5a, 0xa3, 0x5d, 0xb3);
+       static efi_char16_t efi_name[] = L"CirrusSmartAmpCalibrationData";
+       const struct cs35l41_amp_efi_data *efi_data;
+       const struct cs35l41_amp_cal_data *cl;
+       unsigned long data_size = 0;
+       efi_status_t status;
+       int ret = 0;
+       u8 *data = NULL;
+       u32 attr;
+
+       /* Get real size of UEFI variable */
+       status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               ret = -ENODEV;
+               /* Allocate data buffer of data_size bytes */
+               data = vmalloc(data_size);
+               if (!data)
+                       return -ENOMEM;
+               /* Get variable contents into buffer */
+               status = efi.get_variable(efi_name, &efi_guid, &attr, &data_size, data);
+               if (status == EFI_SUCCESS) {
+                       efi_data = (struct cs35l41_amp_efi_data *)data;
+                       dev_dbg(cs35l41->dev, "Calibration: Size=%d, Amp Count=%d\n",
+                               efi_data->size, efi_data->count);
+                       if (efi_data->count > cs35l41->index) {
+                               cl = &efi_data->data[cs35l41->index];
+                               dev_dbg(cs35l41->dev,
+                                       "Calibration: Ambient=%02x, Status=%02x, R0=%d\n",
+                                       cl->calAmbient, cl->calStatus, cl->calR);
+
+                               /* Calibration can only be applied whilst the DSP is not running */
+                               ret = cs35l41_apply_calibration(cs35l41,
+                                                               cpu_to_be32(cl->calAmbient),
+                                                               cpu_to_be32(cl->calR),
+                                                               cpu_to_be32(cl->calStatus),
+                                                               cpu_to_be32(cl->calR + 1));
+                       }
+               }
+               vfree(data);
+       }
+       return ret;
+}
+#else
+static int cs35l41_save_calibration(struct cs35l41_hda *cs35l41)
+{
+       dev_warn(cs35l41->dev, "Calibration not supported without EFI support.\n");
+       return 0;
+}
+#endif
+
+static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
+{
+       const struct firmware *coeff_firmware = NULL;
+       const struct firmware *wmfw_firmware = NULL;
+       struct cs_dsp *dsp = &cs35l41->cs_dsp;
+       char *coeff_filename = NULL;
+       char *wmfw_filename = NULL;
+       int ret;
+
+       if (!cs35l41->halo_initialized) {
+               cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, dsp);
+               dsp->client_ops = &client_ops;
+
+               ret = cs_dsp_halo_init(&cs35l41->cs_dsp);
+               if (ret)
+                       return ret;
+               cs35l41->halo_initialized = true;
+       }
+
+       ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename,
+                                            &coeff_firmware, &coeff_filename);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename);
+       if (coeff_filename)
+               dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename);
+       else
+               dev_warn(cs35l41->dev, "No Coefficient File available.\n");
+
+       ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
+                             hda_cs_dsp_fw_ids[cs35l41->firmware_type]);
+       if (ret)
+               goto err_release;
+
+       ret = cs35l41_save_calibration(cs35l41);
+
+err_release:
+       release_firmware(wmfw_firmware);
+       release_firmware(coeff_firmware);
+       kfree(wmfw_filename);
+       kfree(coeff_filename);
+
+       return ret;
+}
+
+static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
+{
+       struct cs_dsp *dsp = &cs35l41->cs_dsp;
+
+       cs_dsp_stop(dsp);
+       cs_dsp_power_down(dsp);
+       cs35l41->firmware_running = false;
+       dev_dbg(cs35l41->dev, "Unloaded Firmware\n");
+}
+
+static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
+{
+       struct cs_dsp *dsp = &cs35l41->cs_dsp;
+
+       cancel_work_sync(&cs35l41->fw_load_work);
+       cs35l41_shutdown_dsp(cs35l41);
+       cs_dsp_remove(dsp);
+       cs35l41->halo_initialized = false;
+}
+
 /* Protection release cycle to get the speaker out of Safe-Mode */
 static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask)
 {
@@ -53,9 +487,23 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
        struct regmap *reg = cs35l41->regmap;
        int ret = 0;
 
+       mutex_lock(&cs35l41->fw_mutex);
+
        switch (action) {
        case HDA_GEN_PCM_ACT_OPEN:
-               regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
+               cs35l41->playback_started = true;
+               if (cs35l41->firmware_running) {
+                       regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
+                                              ARRAY_SIZE(cs35l41_hda_config_dsp));
+                       regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
+                                          CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
+                                          1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
+                       cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
+                                                 CSPL_MBOX_CMD_RESUME);
+               } else {
+                       regmap_multi_reg_write(reg, cs35l41_hda_config,
+                                              ARRAY_SIZE(cs35l41_hda_config));
+               }
                ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
                                         CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
                if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
@@ -73,13 +521,23 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
                                         CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
                if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
                        regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
+               if (cs35l41->firmware_running) {
+                       cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
+                                                 CSPL_MBOX_CMD_PAUSE);
+                       regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
+                                          CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
+                                          0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
+               }
                cs35l41_irq_release(cs35l41);
+               cs35l41->playback_started = false;
                break;
        default:
                dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
                break;
        }
 
+       mutex_unlock(&cs35l41->fw_mutex);
+
        if (ret)
                dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret);
 }
@@ -104,10 +562,274 @@ static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsi
                                    rx_slot);
 }
 
+static int cs35l41_runtime_suspend(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       dev_dbg(cs35l41->dev, "Suspend\n");
+
+       if (!cs35l41->firmware_running)
+               return 0;
+
+       if (cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type) < 0)
+               return 0;
+
+       regcache_cache_only(cs35l41->regmap, true);
+       regcache_mark_dirty(cs35l41->regmap);
+
+       return 0;
+}
+
+static int cs35l41_runtime_resume(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(cs35l41->dev, "Resume.\n");
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+               dev_dbg(cs35l41->dev, "System does not support Resume\n");
+               return 0;
+       }
+
+       if (!cs35l41->firmware_running)
+               return 0;
+
+       regcache_cache_only(cs35l41->regmap, false);
+
+       ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
+       if (ret) {
+               regcache_cache_only(cs35l41->regmap, true);
+               return ret;
+       }
+
+       /* Test key needs to be unlocked to allow the OTP settings to re-apply */
+       cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
+       ret = regcache_sync(cs35l41->regmap);
+       cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
+               return ret;
+       }
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+               cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
+
+       return 0;
+}
+
+static int cs35l41_hda_suspend_hook(struct device *dev)
+{
+       dev_dbg(dev, "Request Suspend\n");
+       pm_runtime_mark_last_busy(dev);
+       return pm_runtime_put_autosuspend(dev);
+}
+
+static int cs35l41_hda_resume_hook(struct device *dev)
+{
+       dev_dbg(dev, "Request Resume\n");
+       return pm_runtime_get_sync(dev);
+}
+
+static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
+{
+       int halo_sts;
+       int ret;
+
+       ret = cs35l41_init_dsp(cs35l41);
+       if (ret) {
+               dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot Write FS Errata: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       ret = cs_dsp_run(&cs35l41->cs_dsp);
+       if (ret) {
+               dev_err(cs35l41->dev, "Fail to start dsp: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       ret = read_poll_timeout(hda_cs_dsp_read_ctl, ret,
+                               be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN,
+                               1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME,
+                               HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG,
+                               &halo_sts, sizeof(halo_sts));
+
+       if (ret) {
+               dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %d\n",
+                        halo_sts);
+               goto clean_dsp;
+       }
+
+       cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE);
+       cs35l41->firmware_running = true;
+
+       return 0;
+
+clean_dsp:
+       cs35l41_shutdown_dsp(cs35l41);
+       return ret;
+}
+
+static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
+{
+       pm_runtime_get_sync(cs35l41->dev);
+
+       if (cs35l41->firmware_running && !load) {
+               dev_dbg(cs35l41->dev, "Unloading Firmware\n");
+               cs35l41_shutdown_dsp(cs35l41);
+       } else if (!cs35l41->firmware_running && load) {
+               dev_dbg(cs35l41->dev, "Loading Firmware\n");
+               cs35l41_smart_amp(cs35l41);
+       } else {
+               dev_dbg(cs35l41->dev, "Unable to Load firmware.\n");
+       }
+
+       pm_runtime_mark_last_busy(cs35l41->dev);
+       pm_runtime_put_autosuspend(cs35l41->dev);
+}
+
+static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = cs35l41->request_fw_load;
+       return 0;
+}
+
+static void cs35l41_fw_load_work(struct work_struct *work)
+{
+       struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work);
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       /* Recheck if playback is ongoing, mutex will block playback during firmware loading */
+       if (cs35l41->playback_started)
+               dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
+       else
+               cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
+
+       cs35l41->fw_request_ongoing = false;
+       mutex_unlock(&cs35l41->fw_mutex);
+}
+
+static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+       unsigned int ret = 0;
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       if (cs35l41->request_fw_load == ucontrol->value.integer.value[0])
+               goto err;
+
+       if (cs35l41->fw_request_ongoing) {
+               dev_dbg(cs35l41->dev, "Existing request not complete\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* Check if playback is ongoing when initial request is made */
+       if (cs35l41->playback_started) {
+               dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
+               ret = -EBUSY;
+               goto err;
+       }
+
+       cs35l41->fw_request_ongoing = true;
+       cs35l41->request_fw_load = ucontrol->value.integer.value[0];
+       schedule_work(&cs35l41->fw_load_work);
+
+err:
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       return ret;
+}
+
+static int cs35l41_fw_type_ctl_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = cs35l41->firmware_type;
+
+       return 0;
+}
+
+static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       if (ucontrol->value.enumerated.item[0] < HDA_CS_DSP_NUM_FW) {
+               cs35l41->firmware_type = ucontrol->value.enumerated.item[0];
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(hda_cs_dsp_fw_ids), hda_cs_dsp_fw_ids);
+}
+
+static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
+{
+       char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char fw_load_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       struct snd_kcontrol_new fw_type_ctl = {
+               .name = fw_type_ctl_name,
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = cs35l41_fw_type_ctl_info,
+               .get = cs35l41_fw_type_ctl_get,
+               .put = cs35l41_fw_type_ctl_put,
+       };
+       struct snd_kcontrol_new fw_load_ctl = {
+               .name = fw_load_ctl_name,
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = snd_ctl_boolean_mono_info,
+               .get = cs35l41_fw_load_ctl_get,
+               .put = cs35l41_fw_load_ctl_put,
+       };
+       int ret;
+
+       scnprintf(fw_type_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Type",
+                 cs35l41->amp_name);
+       scnprintf(fw_load_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Load",
+                 cs35l41->amp_name);
+
+       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41));
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_type_ctl.name, ret);
+               return ret;
+       }
+
+       dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name);
+
+       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35l41));
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_load_ctl.name, ret);
+               return ret;
+       }
+
+       dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name);
+
+       return 0;
+}
+
 static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
 {
        struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
        struct hda_component *comps = master_data;
+       int ret = 0;
 
        if (!comps || cs35l41->index < 0 || cs35l41->index >= HDA_MAX_COMPONENTS)
                return -EINVAL;
@@ -116,11 +838,38 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
        if (comps->dev)
                return -EBUSY;
 
+       pm_runtime_get_sync(dev);
+
        comps->dev = dev;
+       if (!cs35l41->acpi_subsystem_id)
+               cs35l41->acpi_subsystem_id = devm_kasprintf(dev, GFP_KERNEL, "%.8x",
+                                                           comps->codec->core.subsystem_id);
+       cs35l41->codec = comps->codec;
        strscpy(comps->name, dev_name(dev), sizeof(comps->name));
+
+       cs35l41->firmware_type = HDA_CS_DSP_FW_SPK_PROT;
+
+       if (firmware_autostart) {
+               dev_dbg(cs35l41->dev, "Firmware Autostart.\n");
+               cs35l41->request_fw_load = true;
+               mutex_lock(&cs35l41->fw_mutex);
+               if (cs35l41_smart_amp(cs35l41) < 0)
+                       dev_warn(cs35l41->dev, "Cannot Run Firmware, reverting to dsp bypass...\n");
+               mutex_unlock(&cs35l41->fw_mutex);
+       } else {
+               dev_dbg(cs35l41->dev, "Firmware Autostart is disabled.\n");
+       }
+
+       ret = cs35l41_create_controls(cs35l41);
+
        comps->playback_hook = cs35l41_hda_playback_hook;
+       comps->suspend_hook = cs35l41_hda_suspend_hook;
+       comps->resume_hook = cs35l41_hda_resume_hook;
 
-       return 0;
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
 }
 
 static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
@@ -215,7 +964,7 @@ static const struct regmap_irq cs35l41_reg_irqs[] = {
        CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
 };
 
-static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
+static struct regmap_irq_chip cs35l41_regmap_irq_chip = {
        .name = "cs35l41 IRQ1 Controller",
        .status_base = CS35L41_IRQ1_STATUS1,
        .mask_base = CS35L41_IRQ1_MASK1,
@@ -223,6 +972,7 @@ static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
        .num_regs = 4,
        .irqs = cs35l41_reg_irqs,
        .num_irqs = ARRAY_SIZE(cs35l41_reg_irqs),
+       .runtime_pm = true,
 };
 
 static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
@@ -264,6 +1014,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
                        break;
                case CS35L41_INTERRUPT:
                        using_irq = true;
+                       hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
                        break;
                default:
                        dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
@@ -297,6 +1048,130 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
        return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
 }
 
+static int cs35l41_get_acpi_sub_string(struct device *dev, struct acpi_device *adev,
+                                      const char **subsysid)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+       int ret = 0;
+
+       status = acpi_evaluate_object(adev->handle, "_SUB", NULL, &buffer);
+       if (ACPI_SUCCESS(status)) {
+               obj = buffer.pointer;
+               if (obj->type == ACPI_TYPE_STRING) {
+                       *subsysid = devm_kstrdup(dev, obj->string.pointer, GFP_KERNEL);
+                       if (*subsysid == NULL) {
+                               dev_err(dev, "Cannot allocate Subsystem ID");
+                               ret = -ENOMEM;
+                       }
+               } else {
+                       dev_warn(dev, "Warning ACPI _SUB did not return a string\n");
+                       ret = -ENODEV;
+               }
+               acpi_os_free(buffer.pointer);
+       } else {
+               dev_dbg(dev, "Warning ACPI _SUB failed: %#x\n", status);
+               ret = -ENODEV;
+       }
+
+       return ret;
+}
+
+static int cs35l41_get_speaker_id(struct device *dev, int amp_index,
+                                 int num_amps, int fixed_gpio_id)
+{
+       struct gpio_desc *speaker_id_desc;
+       int speaker_id = -ENODEV;
+
+       if (fixed_gpio_id >= 0) {
+               dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
+               speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
+               if (IS_ERR(speaker_id_desc)) {
+                       speaker_id = PTR_ERR(speaker_id_desc);
+                       return speaker_id;
+               }
+               speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
+               gpiod_put(speaker_id_desc);
+               dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
+       } else {
+               int base_index;
+               int gpios_per_amp;
+               int count;
+               int tmp;
+               int i;
+
+               count = gpiod_count(dev, "spk-id");
+               if (count > 0) {
+                       speaker_id = 0;
+                       gpios_per_amp = count / num_amps;
+                       base_index = gpios_per_amp * amp_index;
+
+                       if (count % num_amps)
+                               return -EINVAL;
+
+                       dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
+
+                       for (i = 0; i < gpios_per_amp; i++) {
+                               speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
+                                                                 GPIOD_IN);
+                               if (IS_ERR(speaker_id_desc)) {
+                                       speaker_id = PTR_ERR(speaker_id_desc);
+                                       break;
+                               }
+                               tmp = gpiod_get_value_cansleep(speaker_id_desc);
+                               gpiod_put(speaker_id_desc);
+                               if (tmp < 0) {
+                                       speaker_id = tmp;
+                                       break;
+                               }
+                               speaker_id |= tmp << i;
+                       }
+                       dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
+               }
+       }
+       return speaker_id;
+}
+
+/*
+ * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
+ * And devices created by serial-multi-instantiate don't have their device struct
+ * pointing to the correct fwnode, so acpi_dev must be used here.
+ * And devm functions expect that the device requesting the resource has the correct
+ * fwnode.
+ */
+static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                              const char *hid)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+       /* check I2C address to assign the index */
+       cs35l41->index = id == 0x40 ? 0 : 1;
+       cs35l41->channel_index = 0;
+       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+       hw_cfg->spk_pos = cs35l41->index;
+       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+       hw_cfg->gpio2.valid = true;
+       hw_cfg->valid = true;
+       put_device(physdev);
+
+       if (strncmp(hid, "CLSA0100", 8) == 0) {
+               hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
+       } else if (strncmp(hid, "CLSA0101", 8) == 0) {
+               hw_cfg->bst_type = CS35L41_EXT_BOOST;
+               hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+               hw_cfg->gpio1.valid = true;
+       } else {
+               hw_cfg->valid = false;
+               hw_cfg->gpio1.valid = false;
+               hw_cfg->gpio2.valid = false;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
 {
        struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
@@ -316,10 +1191,16 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
        physdev = get_device(acpi_get_first_physical_node(adev));
        acpi_dev_put(adev);
 
+       ret = cs35l41_get_acpi_sub_string(cs35l41->dev, adev, &cs35l41->acpi_subsystem_id);
+       if (ret)
+               dev_info(cs35l41->dev, "No Subsystem ID found in ACPI: %d", ret);
+       else
+               dev_dbg(cs35l41->dev, "Subsystem ID %s found", cs35l41->acpi_subsystem_id);
+
        property = "cirrus,dev-index";
        ret = device_property_count_u32(physdev, property);
        if (ret <= 0)
-               goto no_acpi_dsd;
+               return cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid);
 
        if (ret > ARRAY_SIZE(values)) {
                ret = -EINVAL;
@@ -347,7 +1228,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
        /* To use the same release code for all laptop variants we can't use devm_ version of
         * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
         */
-       cs35l41->reset_gpio = fwnode_gpiod_get_index(&adev->fwnode, "reset", cs35l41->index,
+       cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), "reset", cs35l41->index,
                                                     GPIOD_OUT_LOW, "cs35l41-reset");
 
        property = "cirrus,speaker-position";
@@ -396,6 +1277,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
        else
                hw_cfg->bst_cap = -1;
 
+       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1);
+
        if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
                hw_cfg->bst_type = CS35L41_INT_BOOST;
        else
@@ -411,30 +1294,6 @@ err:
        dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
 
        return ret;
-
-no_acpi_dsd:
-       /*
-        * Device CLSA0100 doesn't have _DSD so a gpiod_get by the label reset won't work.
-        * And devices created by i2c-multi-instantiate don't have their device struct pointing to
-        * the correct fwnode, so acpi_dev must be used here.
-        * And devm functions expect that the device requesting the resource has the correct
-        * fwnode.
-        */
-       if (strncmp(hid, "CLSA0100", 8) != 0)
-               return -EINVAL;
-
-       /* check I2C address to assign the index */
-       cs35l41->index = id == 0x40 ? 0 : 1;
-       cs35l41->hw_cfg.spk_pos = cs35l41->index;
-       cs35l41->channel_index = 0;
-       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
-       cs35l41->hw_cfg.bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
-       hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
-       hw_cfg->gpio2.valid = true;
-       cs35l41->hw_cfg.valid = true;
-       put_device(physdev);
-
-       return 0;
 }
 
 int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
@@ -460,10 +1319,8 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
        dev_set_drvdata(dev, cs35l41);
 
        ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
-       if (ret) {
-               dev_err_probe(cs35l41->dev, ret, "Platform not supported %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(cs35l41->dev, ret, "Platform not supported\n");
 
        if (IS_ERR(cs35l41->reset_gpio)) {
                ret = PTR_ERR(cs35l41->reset_gpio);
@@ -471,7 +1328,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
                if (ret == -EBUSY) {
                        dev_info(cs35l41->dev, "Reset line busy, assuming shared reset\n");
                } else {
-                       dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO: %d\n", ret);
+                       dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO\n");
                        goto err;
                }
        }
@@ -536,13 +1393,26 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
        if (ret)
                goto err;
 
+       INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work);
+       mutex_init(&cs35l41->fw_mutex);
+
+       pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
+       pm_runtime_use_autosuspend(cs35l41->dev);
+       pm_runtime_mark_last_busy(cs35l41->dev);
+       pm_runtime_set_active(cs35l41->dev);
+       pm_runtime_get_noresume(cs35l41->dev);
+       pm_runtime_enable(cs35l41->dev);
+
        ret = cs35l41_hda_apply_properties(cs35l41);
        if (ret)
-               goto err;
+               goto err_pm;
+
+       pm_runtime_put_autosuspend(cs35l41->dev);
 
        ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
        if (ret) {
                dev_err(cs35l41->dev, "Register component failed: %d\n", ret);
+               pm_runtime_disable(cs35l41->dev);
                goto err;
        }
 
@@ -550,6 +1420,10 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
 
        return 0;
 
+err_pm:
+       pm_runtime_disable(cs35l41->dev);
+       pm_runtime_put_noidle(cs35l41->dev);
+
 err:
        if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
                gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
@@ -563,14 +1437,28 @@ void cs35l41_hda_remove(struct device *dev)
 {
        struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
 
+       pm_runtime_get_sync(cs35l41->dev);
+       pm_runtime_disable(cs35l41->dev);
+
+       if (cs35l41->halo_initialized)
+               cs35l41_remove_dsp(cs35l41);
+
        component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
 
+       pm_runtime_put_noidle(cs35l41->dev);
+
        if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
                gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
        gpiod_put(cs35l41->reset_gpio);
 }
 EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
 
+const struct dev_pm_ops cs35l41_hda_pm_ops = {
+       RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
+
 MODULE_DESCRIPTION("CS35L41 HDA Driver");
+MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
 MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
 MODULE_LICENSE("GPL");
index a52ffd1f7999471dd3835ed024315b15669e6324..bdb35f3be68a6c78eedfd6e5867bf516b33a9fac 100644 (file)
 #ifndef __CS35L41_HDA_H__
 #define __CS35L41_HDA_H__
 
+#include <linux/efi.h>
 #include <linux/regulator/consumer.h>
 #include <linux/gpio/consumer.h>
 #include <linux/device.h>
 #include <sound/cs35l41.h>
 
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+
+struct cs35l41_amp_cal_data {
+       u32 calTarget[2];
+       u32 calTime[2];
+       s8 calAmbient;
+       u8 calStatus;
+       u16 calR;
+} __packed;
+
+struct cs35l41_amp_efi_data {
+       u32 size;
+       u32 count;
+       struct cs35l41_amp_cal_data data[];
+} __packed;
+
 enum cs35l41_hda_spk_pos {
        CS35l41_LEFT,
        CS35l41_RIGHT,
@@ -32,15 +50,36 @@ struct cs35l41_hda {
        struct regmap *regmap;
        struct gpio_desc *reset_gpio;
        struct cs35l41_hw_cfg hw_cfg;
+       struct hda_codec *codec;
 
        int irq;
        int index;
        int channel_index;
        unsigned volatile long irq_errors;
        const char *amp_name;
+       const char *acpi_subsystem_id;
+       int firmware_type;
+       int speaker_id;
+       struct mutex fw_mutex;
+       struct work_struct fw_load_work;
+
        struct regmap_irq_chip_data *irq_data;
+       bool firmware_running;
+       bool request_fw_load;
+       bool fw_request_ongoing;
+       bool halo_initialized;
+       bool playback_started;
+       struct cs_dsp cs_dsp;
 };
 
+enum halo_state {
+       HALO_STATE_CODE_INIT_DOWNLOAD = 0,
+       HALO_STATE_CODE_START,
+       HALO_STATE_CODE_RUN
+};
+
+extern const struct dev_pm_ops cs35l41_hda_pm_ops;
+
 int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
                      struct regmap *regmap);
 void cs35l41_hda_remove(struct device *dev);
index e810b278fb91d5358b5b392eba80f5a928025aae..5baacfde4f16b7e522c0866880975a779ede98e2 100644 (file)
@@ -1,14 +1,14 @@
 // SPDX-License-Identifier: GPL-2.0
 //
-// cs35l41.c -- CS35l41 HDA I2C driver
+// CS35l41 HDA I2C driver
 //
 // Copyright 2021 Cirrus Logic, Inc.
 //
 // Author: Lucas Tanure <tanureal@opensource.cirrus.com>
 
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
-#include <linux/acpi.h>
 
 #include "cs35l41_hda.h"
 
@@ -16,11 +16,14 @@ static int cs35l41_hda_i2c_probe(struct i2c_client *clt, const struct i2c_device
 {
        const char *device_name;
 
-       /* Compare against the device name so it works for I2C, normal ACPI
-        * and for ACPI by i2c-multi-instantiate matching cases
+       /*
+        * Compare against the device name so it works for SPI, normal ACPI
+        * and for ACPI by serial-multi-instantiate matching cases.
         */
        if (strstr(dev_name(&clt->dev), "CLSA0100"))
                device_name = "CLSA0100";
+       else if (strstr(dev_name(&clt->dev), "CLSA0101"))
+               device_name = "CLSA0101";
        else if (strstr(dev_name(&clt->dev), "CSC3551"))
                device_name = "CSC3551";
        else
@@ -42,19 +45,19 @@ static const struct i2c_device_id cs35l41_hda_i2c_id[] = {
        {}
 };
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
        {"CLSA0100", 0 },
+       {"CLSA0101", 0 },
        {"CSC3551", 0 },
-       { },
+       {}
 };
 MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match);
-#endif
 
 static struct i2c_driver cs35l41_i2c_driver = {
        .driver = {
                .name           = "cs35l41-hda",
-               .acpi_match_table = ACPI_PTR(cs35l41_acpi_hda_match),
+               .acpi_match_table = cs35l41_acpi_hda_match,
+               .pm             = &cs35l41_hda_pm_ops,
        },
        .id_table       = cs35l41_hda_i2c_id,
        .probe          = cs35l41_hda_i2c_probe,
index 22e088f28438ee1aac031a8b622b7f921985b365..71979cfb4d7ed58400e0dec62f4c4a9c0c7bbdaa 100644 (file)
@@ -1,12 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0
 //
-// cs35l41.c -- CS35l41 HDA SPI driver
+// CS35l41 HDA SPI driver
 //
 // Copyright 2021 Cirrus Logic, Inc.
 //
 // Author: Lucas Tanure <tanureal@opensource.cirrus.com>
 
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 
@@ -16,8 +16,9 @@ static int cs35l41_hda_spi_probe(struct spi_device *spi)
 {
        const char *device_name;
 
-       /* Compare against the device name so it works for SPI, normal ACPI
-        * and for ACPI by spi-multi-instantiate matching cases
+       /*
+        * Compare against the device name so it works for SPI, normal ACPI
+        * and for ACPI by serial-multi-instantiate matching cases.
         */
        if (strstr(dev_name(&spi->dev), "CSC3551"))
                device_name = "CSC3551";
@@ -38,18 +39,17 @@ static const struct spi_device_id cs35l41_hda_spi_id[] = {
        {}
 };
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
        { "CSC3551", 0 },
-       {},
+       {}
 };
 MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match);
-#endif
 
 static struct spi_driver cs35l41_spi_driver = {
        .driver = {
                .name           = "cs35l41-hda",
-               .acpi_match_table = ACPI_PTR(cs35l41_acpi_hda_match),
+               .acpi_match_table = cs35l41_acpi_hda_match,
+               .pm             = &cs35l41_hda_pm_ops,
        },
        .id_table       = cs35l41_hda_spi_id,
        .probe          = cs35l41_hda_spi_probe,
index c572fb5886d5d63f56ead62ab2d5e5e192d75245..cae9a975cbcca809bdd59993e1343eebd4c6ad76 100644 (file)
@@ -248,6 +248,13 @@ static bool is_likely_hdmi_codec(struct hda_codec *codec)
 {
        hda_nid_t nid;
 
+       /*
+        * For ASoC users, if snd_hda_hdmi_codec module is denylisted and any
+        * event causes i915 enumeration to fail, ->wcaps remains uninitialized.
+        */
+       if (!codec->wcaps)
+               return true;
+
        for_each_hda_codec_node(nid, codec) {
                unsigned int wcaps = get_wcaps(codec, nid);
                switch (get_wcaps_type(wcaps)) {
index 7579a6982f471c17232d0206bd68a1ee252cc741..7b2e62fa82d5573e5552b4e5f4517865a974344f 100644 (file)
@@ -772,11 +772,11 @@ static void codec_release_pcms(struct hda_codec *codec)
  */
 void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
 {
-       if (codec->registered) {
+       if (codec->core.registered) {
                /* pm_runtime_put() is called in snd_hdac_device_exit() */
                pm_runtime_get_noresume(hda_codec_dev(codec));
                pm_runtime_disable(hda_codec_dev(codec));
-               codec->registered = 0;
+               codec->core.registered = 0;
        }
 
        snd_hda_codec_disconnect_pcms(codec);
@@ -825,14 +825,14 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable)
  */
 void snd_hda_codec_register(struct hda_codec *codec)
 {
-       if (codec->registered)
+       if (codec->core.registered)
                return;
        if (device_is_registered(hda_codec_dev(codec))) {
                snd_hda_codec_display_power(codec, true);
                pm_runtime_enable(hda_codec_dev(codec));
                /* it was powered up in snd_hda_codec_new(), now all done */
                snd_hda_power_down(codec);
-               codec->registered = 1;
+               codec->core.registered = 1;
        }
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_register);
@@ -950,6 +950,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
                      unsigned int codec_addr, struct hda_codec **codecp)
 {
        struct hda_codec *codec;
+       int ret;
 
        codec = snd_hda_codec_device_init(bus, codec_addr, "hdaudioC%dD%d",
                                          card->number, codec_addr);
@@ -957,7 +958,11 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
                return PTR_ERR(codec);
        *codecp = codec;
 
-       return snd_hda_codec_device_new(bus, card, codec_addr, *codecp, true);
+       ret = snd_hda_codec_device_new(bus, card, codec_addr, *codecp, true);
+       if (ret)
+               put_device(hda_codec_dev(*codecp));
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_new);
 
@@ -1012,19 +1017,17 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
 
        if (codec->bus->modelname) {
                codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
-               if (!codec->modelname) {
-                       err = -ENOMEM;
-                       goto error;
-               }
+               if (!codec->modelname)
+                       return -ENOMEM;
        }
 
        fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
        err = read_widget_caps(codec, fg);
        if (err < 0)
-               goto error;
+               return err;
        err = read_pin_defaults(codec);
        if (err < 0)
-               goto error;
+               return err;
 
        /* power-up all before initialization */
        hda_set_power_state(codec, AC_PWRST_D0);
@@ -1042,17 +1045,19 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
                /* ASoC features component management instead */
                err = snd_device_new(card, SNDRV_DEV_CODEC, codec, &dev_ops);
                if (err < 0)
-                       goto error;
+                       return err;
        }
 
+#ifdef CONFIG_PM
        /* PM runtime needs to be enabled later after binding codec */
-       pm_runtime_forbid(&codec->core.dev);
+       if (codec->core.dev.power.runtime_auto)
+               pm_runtime_forbid(&codec->core.dev);
+       else
+               /* Keep the usage_count consistent across subsequent probing */
+               pm_runtime_get_noresume(&codec->core.dev);
+#endif
 
        return 0;
-
- error:
-       put_device(hda_codec_dev(codec));
-       return err;
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_device_new);
 
@@ -3043,7 +3048,7 @@ void snd_hda_codec_shutdown(struct hda_codec *codec)
        struct hda_pcm *cpcm;
 
        /* Skip the shutdown if codec is not registered */
-       if (!codec->registered)
+       if (!codec->core.registered)
                return;
 
        cancel_delayed_work_sync(&codec->jackpoll_work);
index e26c896a13f3469f961fd732c8f6308318d95196..1223621bd62ca8280bb1d03d679b9f3f25f39f0e 100644 (file)
@@ -14,5 +14,8 @@
 struct hda_component {
        struct device *dev;
        char name[HDA_MAX_NAME_SIZE];
+       struct hda_codec *codec;
        void (*playback_hook)(struct device *dev, int action);
+       int (*suspend_hook)(struct device *dev);
+       int (*resume_hook)(struct device *dev);
 };
diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c
new file mode 100644 (file)
index 0000000..89ee549
--- /dev/null
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// HDA DSP ALSA Control Driver
+//
+// Copyright 2022 Cirrus Logic, Inc.
+//
+// Author: Stefan Binding <sbinding@opensource.cirrus.com>
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include "hda_cs_dsp_ctl.h"
+
+#define ADSP_MAX_STD_CTRL_SIZE               512
+
+struct hda_cs_dsp_coeff_ctl {
+       struct cs_dsp_coeff_ctl *cs_ctl;
+       struct snd_card *card;
+       struct snd_kcontrol *kctl;
+};
+
+static const char * const hda_cs_dsp_fw_text[HDA_CS_DSP_NUM_FW] = {
+       [HDA_CS_DSP_FW_SPK_PROT] = "Prot",
+       [HDA_CS_DSP_FW_SPK_CALI] = "Cali",
+       [HDA_CS_DSP_FW_SPK_DIAG] = "Diag",
+       [HDA_CS_DSP_FW_MISC] =     "Misc",
+};
+
+const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW] = {
+       [HDA_CS_DSP_FW_SPK_PROT] = "spk-prot",
+       [HDA_CS_DSP_FW_SPK_CALI] = "spk-cali",
+       [HDA_CS_DSP_FW_SPK_DIAG] = "spk-diag",
+       [HDA_CS_DSP_FW_MISC] =     "misc",
+};
+EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_fw_ids, SND_HDA_CS_DSP_CONTROLS);
+
+static int hda_cs_dsp_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl);
+       struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = cs_ctl->len;
+
+       return 0;
+}
+
+static int hda_cs_dsp_coeff_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl);
+       struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
+       char *p = ucontrol->value.bytes.data;
+       int ret = 0;
+
+       mutex_lock(&cs_ctl->dsp->pwr_lock);
+       ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, p, cs_ctl->len);
+       mutex_unlock(&cs_ctl->dsp->pwr_lock);
+
+       return ret;
+}
+
+static int hda_cs_dsp_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl);
+       struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
+       char *p = ucontrol->value.bytes.data;
+       int ret;
+
+       mutex_lock(&cs_ctl->dsp->pwr_lock);
+       ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, p, cs_ctl->len);
+       mutex_unlock(&cs_ctl->dsp->pwr_lock);
+
+       return ret;
+}
+
+static unsigned int wmfw_convert_flags(unsigned int in)
+{
+       unsigned int out, rd, wr, vol;
+
+       rd = SNDRV_CTL_ELEM_ACCESS_READ;
+       wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
+       vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+
+       out = 0;
+
+       if (in) {
+               out |= rd;
+               if (in & WMFW_CTL_FLAG_WRITEABLE)
+                       out |= wr;
+               if (in & WMFW_CTL_FLAG_VOLATILE)
+                       out |= vol;
+       } else {
+               out |= rd | wr | vol;
+       }
+
+       return out;
+}
+
+static int hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name)
+{
+       struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
+       struct snd_kcontrol_new kcontrol = {0};
+       struct snd_kcontrol *kctl;
+       int ret = 0;
+
+       if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) {
+               dev_err(cs_ctl->dsp->dev, "KControl %s: length %zu exceeds maximum %d\n", name,
+                       cs_ctl->len, ADSP_MAX_STD_CTRL_SIZE);
+               return -EINVAL;
+       }
+
+       kcontrol.name = name;
+       kcontrol.info = hda_cs_dsp_coeff_info;
+       kcontrol.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       kcontrol.access = wmfw_convert_flags(cs_ctl->flags);
+       kcontrol.get = hda_cs_dsp_coeff_get;
+       kcontrol.put = hda_cs_dsp_coeff_put;
+
+       /* Save ctl inside private_data, ctl is owned by cs_dsp,
+        * and will be freed when cs_dsp removes the control */
+       kctl = snd_ctl_new1(&kcontrol, (void *)ctl);
+       if (!kctl) {
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       ret = snd_ctl_add(ctl->card, kctl);
+       if (ret) {
+               dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret);
+               return ret;
+       }
+
+       dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name);
+       ctl->kctl = kctl;
+
+       return 0;
+}
+
+int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ctl_info *info)
+{
+       struct cs_dsp *cs_dsp = cs_ctl->dsp;
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       struct hda_cs_dsp_coeff_ctl *ctl;
+       const char *region_name;
+       int ret;
+
+       if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
+               return 0;
+
+       region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
+       if (!region_name) {
+               dev_err(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type);
+               return -EINVAL;
+       }
+
+       ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %.12s %x", info->device_name,
+                       cs_dsp->name, hda_cs_dsp_fw_text[info->fw_type], cs_ctl->alg_region.alg);
+
+       if (cs_ctl->subname) {
+               int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
+               int skip = 0;
+
+               /* Truncate the subname from the start if it is too long */
+               if (cs_ctl->subname_len > avail)
+                       skip = cs_ctl->subname_len - avail;
+
+               snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
+                        " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip);
+       }
+
+       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+       if (!ctl)
+               return -ENOMEM;
+
+       ctl->cs_ctl = cs_ctl;
+       ctl->card = info->card;
+       cs_ctl->priv = ctl;
+
+       ret = hda_cs_dsp_add_kcontrol(ctl, name);
+       if (ret) {
+               dev_err(cs_dsp->dev, "Error (%d) adding control %s\n", ret, name);
+               kfree(ctl);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_add, SND_HDA_CS_DSP_CONTROLS);
+
+void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
+{
+       struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv;
+
+       kfree(ctl);
+}
+EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS);
+
+int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
+                        unsigned int alg, const void *buf, size_t len)
+{
+       struct cs_dsp_coeff_ctl *cs_ctl;
+       struct hda_cs_dsp_coeff_ctl *ctl;
+       int ret;
+
+       cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
+       if (!cs_ctl)
+               return -EINVAL;
+
+       ctl = cs_ctl->priv;
+
+       ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
+       if (ret)
+               return ret;
+
+       if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
+               return 0;
+
+       snd_ctl_notify(ctl->card, SNDRV_CTL_EVENT_MASK_VALUE, &ctl->kctl->id);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, SND_HDA_CS_DSP_CONTROLS);
+
+int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type,
+                       unsigned int alg, void *buf, size_t len)
+{
+       struct cs_dsp_coeff_ctl *cs_ctl;
+
+       cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
+       if (!cs_ctl)
+               return -EINVAL;
+
+       return cs_dsp_coeff_read_ctrl(cs_ctl, 0, buf, len);
+}
+EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS);
+
+MODULE_DESCRIPTION("CS_DSP ALSA Control HDA Library");
+MODULE_AUTHOR("Stefan Binding, <sbinding@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_cs_dsp_ctl.h b/sound/pci/hda/hda_cs_dsp_ctl.h
new file mode 100644 (file)
index 0000000..4babc69
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * HDA DSP ALSA Control Driver
+ *
+ * Copyright 2022 Cirrus Logic, Inc.
+ *
+ * Author: Stefan Binding <sbinding@opensource.cirrus.com>
+ */
+
+#ifndef __HDA_CS_DSP_CTL_H__
+#define __HDA_CS_DSP_CTL_H__
+
+#include <sound/soc.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+
+enum hda_cs_dsp_fw_id {
+       HDA_CS_DSP_FW_SPK_PROT,
+       HDA_CS_DSP_FW_SPK_CALI,
+       HDA_CS_DSP_FW_SPK_DIAG,
+       HDA_CS_DSP_FW_MISC,
+       HDA_CS_DSP_NUM_FW
+};
+
+struct hda_cs_dsp_ctl_info {
+       struct snd_card *card;
+       enum hda_cs_dsp_fw_id fw_type;
+       const char *device_name;
+};
+
+extern const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW];
+
+int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ctl_info *info);
+void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl);
+int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
+                        unsigned int alg, const void *buf, size_t len);
+int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type,
+                       unsigned int alg, void *buf, size_t len);
+
+#endif /*__HDA_CS_DSP_CTL_H__*/
index d5ffcba794e50f50a138e49ecfbdd9462afb2491..bf951c10ae61b0819676e9134237002dda9cba04 100644 (file)
@@ -33,7 +33,7 @@ static ssize_t power_on_acct_show(struct device *dev,
 {
        struct hda_codec *codec = dev_get_drvdata(dev);
        snd_hda_update_power_acct(codec);
-       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
+       return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
 }
 
 static ssize_t power_off_acct_show(struct device *dev,
@@ -42,7 +42,7 @@ static ssize_t power_off_acct_show(struct device *dev,
 {
        struct hda_codec *codec = dev_get_drvdata(dev);
        snd_hda_update_power_acct(codec);
-       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
+       return sysfs_emit(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
 }
 
 static DEVICE_ATTR_RO(power_on_acct);
@@ -55,7 +55,7 @@ static ssize_t type##_show(struct device *dev,                        \
                           char *buf)                           \
 {                                                              \
        struct hda_codec *codec = dev_get_drvdata(dev);         \
-       return sprintf(buf, "0x%x\n", codec->field);            \
+       return sysfs_emit(buf, "0x%x\n", codec->field);         \
 }
 
 #define CODEC_INFO_STR_SHOW(type, field)                       \
@@ -64,8 +64,8 @@ static ssize_t type##_show(struct device *dev,                        \
                                        char *buf)              \
 {                                                              \
        struct hda_codec *codec = dev_get_drvdata(dev);         \
-       return sprintf(buf, "%s\n",                             \
-                      codec->field ? codec->field : "");       \
+       return sysfs_emit(buf, "%s\n",                          \
+                         codec->field ? codec->field : "");    \
 }
 
 CODEC_INFO_SHOW(vendor_id, core.vendor_id);
@@ -85,8 +85,8 @@ static ssize_t pin_configs_show(struct hda_codec *codec,
        int i, len = 0;
        mutex_lock(&codec->user_mutex);
        snd_array_for_each(list, i, pin) {
-               len += sprintf(buf + len, "0x%02x 0x%08x\n",
-                              pin->nid, pin->cfg);
+               len += sysfs_emit_at(buf, len, "0x%02x 0x%08x\n",
+                                    pin->nid, pin->cfg);
        }
        mutex_unlock(&codec->user_mutex);
        return len;
@@ -222,9 +222,8 @@ static ssize_t init_verbs_show(struct device *dev,
        int i, len = 0;
        mutex_lock(&codec->user_mutex);
        snd_array_for_each(&codec->init_verbs, i, v) {
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "0x%02x 0x%03x 0x%04x\n",
-                               v->nid, v->verb, v->param);
+               len += sysfs_emit_at(buf, len, "0x%02x 0x%03x 0x%04x\n",
+                                    v->nid, v->verb, v->param);
        }
        mutex_unlock(&codec->user_mutex);
        return len;
@@ -272,8 +271,8 @@ static ssize_t hints_show(struct device *dev,
        int i, len = 0;
        mutex_lock(&codec->user_mutex);
        snd_array_for_each(&codec->hints, i, hint) {
-               len += scnprintf(buf + len, PAGE_SIZE - len,
-                               "%s = %s\n", hint->key, hint->val);
+               len += sysfs_emit_at(buf, len, "%s = %s\n",
+                                    hint->key, hint->val);
        }
        mutex_unlock(&codec->user_mutex);
        return len;
index 4f4cc8215917992c598c8dcc527411eaaa9ef008..e0d3a8be2e38b56f63727250a541e9e07888d303 100644 (file)
@@ -68,7 +68,7 @@ const struct hda_verb cs8409_cs42l42_init_verbs[] = {
        {} /* terminator */
 };
 
-const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
+static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
        { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 },  /* ASP-1-TX */
        { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 },     /* ASP-1-RX */
        { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 },  /* ASP-2-TX */
@@ -76,7 +76,7 @@ const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
        {} /* terminator */
 };
 
-const struct hda_pintbl cs8409_cs42l42_pincfgs_no_dmic[] = {
+static const struct hda_pintbl cs8409_cs42l42_pincfgs_no_dmic[] = {
        { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 },  /* ASP-1-TX */
        { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 },     /* ASP-1-RX */
        { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 },  /* ASP-2-TX */
@@ -279,7 +279,7 @@ const struct hda_verb dolphin_init_verbs[] = {
        {} /* terminator */
 };
 
-const struct hda_pintbl dolphin_pincfgs[] = {
+static const struct hda_pintbl dolphin_pincfgs[] = {
        { 0x24, 0x022210f0 }, /* ASP-1-TX-A */
        { 0x25, 0x010240f0 }, /* ASP-1-TX-B */
        { 0x34, 0x02a21050 }, /* ASP-1-RX */
index 260388a6256cd010e0e3c153449da976e102a542..2a8dfb4ff046b0918fa3d21e91255d8b98417f00 100644 (file)
@@ -358,13 +358,11 @@ extern const struct snd_pci_quirk cs8409_fixup_tbl[];
 extern const struct hda_model_fixup cs8409_models[];
 extern const struct hda_fixup cs8409_fixups[];
 extern const struct hda_verb cs8409_cs42l42_init_verbs[];
-extern const struct hda_pintbl cs8409_cs42l42_pincfgs[];
 extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[];
 extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[];
 extern struct sub_codec cs8409_cs42l42_codec;
 
 extern const struct hda_verb dolphin_init_verbs[];
-extern const struct hda_pintbl dolphin_pincfgs[];
 extern const struct cs8409_cir_param dolphin_hw_cfg[];
 extern struct sub_codec dolphin_cs42l42_0;
 extern struct sub_codec dolphin_cs42l42_1;
index 2f55bc43bfa9cce2176d497286780c034f6f0755..8a57636f622e9774bc16ae04e789f9ce2cc177b9 100644 (file)
@@ -4021,15 +4021,22 @@ static void alc5505_dsp_init(struct hda_codec *codec)
 static int alc269_suspend(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       int i;
 
        if (spec->has_alc5505_dsp)
                alc5505_dsp_suspend(codec);
+
+       for (i = 0; i < HDA_MAX_COMPONENTS; i++)
+               if (spec->comps[i].suspend_hook)
+                       spec->comps[i].suspend_hook(spec->comps[i].dev);
+
        return alc_suspend(codec);
 }
 
 static int alc269_resume(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       int i;
 
        if (spec->codec_variant == ALC269_TYPE_ALC269VB)
                alc269vb_toggle_power_output(codec, 0);
@@ -4060,6 +4067,10 @@ static int alc269_resume(struct hda_codec *codec)
        if (spec->has_alc5505_dsp)
                alc5505_dsp_resume(codec);
 
+       for (i = 0; i < HDA_MAX_COMPONENTS; i++)
+               if (spec->comps[i].resume_hook)
+                       spec->comps[i].resume_hook(spec->comps[i].dev);
+
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -6610,8 +6621,20 @@ static int comp_bind(struct device *dev)
 {
        struct hda_codec *cdc = dev_to_hda_codec(dev);
        struct alc_spec *spec = cdc->spec;
+       int ret, i;
 
-       return component_bind_all(dev, spec->comps);
+       ret = component_bind_all(dev, spec->comps);
+       if (ret)
+               return ret;
+
+       if (snd_hdac_is_power_on(&cdc->core)) {
+               codec_dbg(cdc, "Resuming after bind.\n");
+               for (i = 0; i < HDA_MAX_COMPONENTS; i++)
+                       if (spec->comps[i].resume_hook)
+                               spec->comps[i].resume_hook(spec->comps[i].dev);
+       }
+
+       return 0;
 }
 
 static void comp_unbind(struct device *dev)
@@ -6654,6 +6677,7 @@ static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char
                                              "%s-%s:00-cs35l41-hda.%d", bus, hid, i);
                        if (!name)
                                return;
+                       spec->comps[i].codec = cdc;
                        component_match_add(dev, &spec->match, component_compare_dev_name, name);
                }
                ret = component_master_add_with_match(dev, &comp_master_ops, spec->match);
@@ -6686,6 +6710,12 @@ static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const st
        cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2);
 }
 
+static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
+                                                int action)
+{
+       cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2);
+}
+
 /* for alc295_fixup_hp_top_speakers */
 #include "hp_x360_helper.c"
 
@@ -6787,6 +6817,43 @@ static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
        }
 }
 
+static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       /*
+        * The Pin Complex 0x17 for the bass speakers is wrongly reported as
+        * unconnected.
+        */
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x17, 0x90170121 },
+               { }
+       };
+       /*
+        * Avoid DAC 0x06 and 0x08, as they have no volume controls.
+        * DAC 0x02 and 0x03 would be fine.
+        */
+       static const hda_nid_t conn[] = { 0x02, 0x03 };
+       /*
+        * Prefer both speakerbar (0x14) and bass speakers (0x17) connected to DAC 0x02.
+        * Headphones (0x21) are connected to DAC 0x03.
+        */
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x02,
+               0x17, 0x02,
+               0x21, 0x03,
+               0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               spec->gen.preferred_dacs = preferred_pairs;
+               break;
+       }
+}
+
 enum {
        ALC269_FIXUP_GPIO2,
        ALC269_FIXUP_SONY_VAIO,
@@ -7023,6 +7090,9 @@ enum {
        ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED,
        ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED,
        ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE,
+       ALC287_FIXUP_LEGION_16ITHG6,
+       ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
+       ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -8865,6 +8935,78 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
        },
+       [ALC287_FIXUP_LEGION_16ITHG6] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_legion_16ithg6_speakers,
+       },
+       [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       // enable left speaker
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xf },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x10 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x40 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       // enable right speaker
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xf },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x10 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x44 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { },
+               },
+       },
+       [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9044,6 +9186,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+       SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
        SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
@@ -9114,6 +9258,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -9203,6 +9349,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x4041, "Clevo NV4[15]PZ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x40a1, "Clevo NL40GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x40c1, "Clevo NL40[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x40d1, "Clevo NL41DU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9315,6 +9462,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
+       SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
        SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
@@ -9329,6 +9477,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
@@ -9560,6 +9709,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
        {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
        {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
+       {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
        {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
        {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"},
        {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"},
index d4528962ac34e8c8e2714a5060d81c77e123099b..453181ef6c94c90dfc57a666632e348e4a1a0381 100644 (file)
@@ -9,12 +9,12 @@ endif
 
 ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),)
 # snd-soc-test-objs := soc-topology-test.o
-obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o
+obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) += soc-topology-test.o
 endif
 
 ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
 # snd-soc-test-objs := soc-utils-test.o
-obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) := soc-utils-test.o
+obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o
 endif
 
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
index 1289cb4e2988c4650d96a6c24bd6fd5fcb4c1278..b1342351bff43c85bcf02b34c6e8d6388f572ae0 100644 (file)
@@ -161,6 +161,7 @@ static struct snd_soc_dai_driver axi_i2s_dai = {
 
 static const struct snd_soc_component_driver axi_i2s_component = {
        .name = "axi-i2s",
+       .legacy_dai_naming = 1,
 };
 
 static const struct regmap_config axi_i2s_regmap_config = {
index 8d4a6cb4e5c5519800420124cf06eabbfc493c4d..51b968ea21daa119976682883cbd71a6b3867bf8 100644 (file)
@@ -167,6 +167,7 @@ static struct snd_soc_dai_driver axi_spdif_dai = {
 
 static const struct snd_soc_component_driver axi_spdif_component = {
        .name = "axi-spdif",
+       .legacy_dai_naming = 1,
 };
 
 static const struct regmap_config axi_spdif_regmap_config = {
index 1381aec230481f58af3cac2c63d0f3b412b5cfd8..08f5289dac5408cca3ba08878d26aa8d40838b97 100644 (file)
@@ -23,6 +23,18 @@ config SND_SOC_AMD_CZ_RT5645_MACH
        help
         This option enables machine driver for rt5645.
 
+config SND_SOC_AMD_ST_ES8336_MACH
+       tristate "AMD ST support for ES8336"
+       select SND_SOC_ACPI if ACPI
+       select SND_SOC_ES8316
+       depends on SND_SOC_AMD_ACP && ACPI
+       depends on I2C
+       help
+        This option enables machine driver for Jadeite platform
+        using es8336 codec.
+        Say m if you have such a device.
+        If unsure select "N".
+
 config SND_SOC_AMD_ACP3x
        tristate "AMD Audio Coprocessor-v3.x support"
        depends on X86 && PCI
@@ -105,3 +117,13 @@ config SND_AMD_ACP_CONFIG
         driver modules to use
 
 source "sound/soc/amd/acp/Kconfig"
+
+config SND_SOC_AMD_RPL_ACP6x
+        tristate "AMD Audio Coprocessor-v6.2 RPL support"
+        depends on X86 && PCI
+        help
+          This option enables Audio Coprocessor i.e ACP v6.2 support on
+          AMD RPL platform. By enabling this flag build will be
+          triggered for ACP PCI driver.
+          Say m if you have such a device.
+          If unsure select "N".
index 4b1f77930a4a8e6eaed527188d76025706f0c95a..0592e7c5c40711a316cededfe36541339a45d947 100644 (file)
@@ -2,12 +2,14 @@
 acp_audio_dma-objs := acp-pcm-dma.o
 snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o
 snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
+snd-soc-acp-es8336-mach-objs := acp-es8336.o
 snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o
 snd-acp-config-objs := acp-config.o
 
 obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
 obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o
 obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
+obj-$(CONFIG_SND_SOC_AMD_ST_ES8336_MACH) += snd-soc-acp-es8336-mach.o
 obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/
 obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o
 obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/
@@ -15,3 +17,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/
 obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/
 obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/
 obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o
+obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/
index 5cbc82eca4c9a06d1ce4ba674ac563a4b68e06e0..0932473b63945fb3eda1ac6087245e6daa1f71ff 100644 (file)
@@ -130,4 +130,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = {
 };
 EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines);
 
+struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = {
+       {
+               .id = "AMDI1019",
+               .drv_name = "rmb-dsp",
+               .pdata = &acp_quirk_data,
+               .fw_filename = "sof-rmb.ri",
+               .sof_tplg_filename = "sof-acp-rmb.tplg",
+       },
+       {
+               .id = "10508825",
+               .drv_name = "nau8825-max",
+               .pdata = &acp_quirk_data,
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_max,
+               .fw_filename = "sof-rmb.ri",
+               .sof_tplg_filename = "sof-rmb-nau8825-max98360.tplg",
+       },
+       {
+               .id = "RTL5682",
+               .drv_name = "rt5682s-hs-rt1019",
+               .pdata = &acp_quirk_data,
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_rt1019,
+               .fw_filename = "sof-rmb.ri",
+               .sof_tplg_filename = "sof-rmb-rt5682s-rt1019.tplg",
+       },
+       {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_rmb_sof_machines);
+
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c
new file mode 100644 (file)
index 0000000..2fe8df8
--- /dev/null
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Machine driver for AMD Stoney platform using ES8336 Codec
+ *
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ */
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+
+#include "acp.h"
+
+#define DUAL_CHANNEL   2
+#define DRV_NAME "acp2x_mach"
+#define ST_JADEITE     1
+#define ES8336_PLL_FREQ (48000 * 256)
+
+static unsigned long acp2x_machine_id;
+static struct snd_soc_jack st_jack;
+static struct device *codec_dev;
+static struct gpio_desc *gpio_pa;
+
+static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w,
+                                         struct snd_kcontrol *kcontrol, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpiod_set_value_cansleep(gpio_pa, true);
+       else
+               gpiod_set_value_cansleep(gpio_pa, false);
+
+       return 0;
+}
+
+static struct snd_soc_jack_pin st_es8316_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
+static int st_es8336_init(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+       struct snd_soc_card *card;
+       struct snd_soc_component *codec;
+
+       codec = asoc_rtd_to_codec(rtd, 0)->component;
+       card = rtd->card;
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                        &st_jack, st_es8316_jack_pins,
+                                        ARRAY_SIZE(st_es8316_jack_pins));
+       if (ret) {
+               dev_err(card->dev, "HP jack creation failed %d\n", ret);
+               return ret;
+       }
+       snd_jack_set_key(st_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       ret = snd_soc_component_set_jack(codec, &st_jack, NULL);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static const unsigned int st_channels[] = {
+       DUAL_CHANNEL,
+};
+
+static const unsigned int st_rates[] = {
+       48000,
+};
+
+static const struct snd_pcm_hw_constraint_list st_constraints_rates = {
+       .count = ARRAY_SIZE(st_rates),
+       .list  = st_rates,
+       .mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list st_constraints_channels = {
+       .count = ARRAY_SIZE(st_channels),
+       .list = st_channels,
+       .mask = 0,
+};
+
+static int st_es8336_codec_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime;
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_card *card;
+       struct acp_platform_info *machine;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       runtime = substream->runtime;
+       rtd = asoc_substream_to_rtd(substream);
+       card = rtd->card;
+       machine = snd_soc_card_get_drvdata(card);
+       codec_dai = asoc_rtd_to_codec(rtd, 0);
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, ES8336_PLL_FREQ, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+       runtime->hw.channels_max = DUAL_CHANNEL;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &st_constraints_channels);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                  &st_constraints_rates);
+
+       machine->play_i2s_instance = I2S_MICSP_INSTANCE;
+       machine->cap_i2s_instance = I2S_MICSP_INSTANCE;
+       machine->capture_channel = CAP_CHANNEL0;
+       return 0;
+}
+
+static const struct snd_soc_ops st_es8336_ops = {
+       .startup = st_es8336_codec_startup,
+};
+
+SND_SOC_DAILINK_DEF(designware1,
+                   DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto")));
+SND_SOC_DAILINK_DEF(codec,
+                   DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi")));
+SND_SOC_DAILINK_DEF(platform,
+                   DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.1.auto")));
+
+static struct snd_soc_dai_link st_dai_es8336[] = {
+       {
+               .name = "amdes8336",
+               .stream_name = "ES8336 HiFi Play",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBP_CFP,
+               .stop_dma_first = 1,
+               .dpcm_capture = 1,
+               .dpcm_playback = 1,
+               .init = st_es8336_init,
+               .ops = &st_es8336_ops,
+               SND_SOC_DAILINK_REG(designware1, codec, platform),
+       },
+};
+
+static const struct snd_soc_dapm_widget st_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic", NULL),
+
+       SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0,
+                           sof_es8316_speaker_power_event,
+                           SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route st_audio_route[] = {
+       {"Speaker", NULL, "HPOL"},
+       {"Speaker", NULL, "HPOR"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"MIC1", NULL, "Headset Mic"},
+       {"MIC2", NULL, "Internal Mic"},
+       {"Speaker", NULL, "Speaker Power"},
+};
+
+static const struct snd_kcontrol_new st_mc_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static const struct acpi_gpio_params pa_enable_gpio = { 0, 0, false };
+static const struct acpi_gpio_mapping acpi_es8336_gpios[] = {
+       { "pa-enable-gpios", &pa_enable_gpio, 1 },
+       { }
+};
+
+static int st_es8336_late_probe(struct snd_soc_card *card)
+{
+       struct acpi_device *adev;
+       int ret;
+
+       adev = acpi_dev_get_first_match_dev("ESSX8336", NULL, -1);
+       if (adev)
+               put_device(&adev->dev);
+       codec_dev = acpi_get_first_physical_node(adev);
+       if (!codec_dev)
+               dev_err(card->dev, "can not find codec dev\n");
+
+       ret = devm_acpi_dev_add_driver_gpios(codec_dev, acpi_es8336_gpios);
+       if (ret)
+               dev_warn(card->dev, "Failed to add driver gpios\n");
+
+       gpio_pa = gpiod_get_optional(codec_dev, "pa-enable", GPIOD_OUT_LOW);
+       if (IS_ERR(gpio_pa)) {
+               ret = dev_err_probe(card->dev, PTR_ERR(gpio_pa),
+                                   "could not get pa-enable GPIO\n");
+               put_device(codec_dev);
+               return ret;
+       }
+       return 0;
+}
+
+static struct snd_soc_card st_card = {
+       .name = "acpes8336",
+       .owner = THIS_MODULE,
+       .dai_link = st_dai_es8336,
+       .num_links = ARRAY_SIZE(st_dai_es8336),
+       .dapm_widgets = st_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(st_widgets),
+       .dapm_routes = st_audio_route,
+       .num_dapm_routes = ARRAY_SIZE(st_audio_route),
+       .controls = st_mc_controls,
+       .num_controls = ARRAY_SIZE(st_mc_controls),
+       .late_probe = st_es8336_late_probe,
+};
+
+static int st_es8336_quirk_cb(const struct dmi_system_id *id)
+{
+       acp2x_machine_id = ST_JADEITE;
+       return 1;
+}
+
+static const struct dmi_system_id st_es8336_quirk_table[] = {
+       {
+               .callback = st_es8336_quirk_cb,
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMD"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jadeite"),
+               },
+       },
+       {
+               .callback = st_es8336_quirk_cb,
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "IP3 Technology CO.,Ltd."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN1D"),
+               },
+       },
+       {
+               .callback = st_es8336_quirk_cb,
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Standard"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN10"),
+               },
+       },
+       {}
+};
+
+static int st_es8336_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct snd_soc_card *card;
+       struct acp_platform_info *machine;
+
+       machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info), GFP_KERNEL);
+       if (!machine)
+               return -ENOMEM;
+
+       dmi_check_system(st_es8336_quirk_table);
+       switch (acp2x_machine_id) {
+       case ST_JADEITE:
+               card = &st_card;
+               st_card.dev = &pdev->dev;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+       ret = devm_snd_soc_register_card(&pdev->dev, &st_card);
+       if (ret) {
+               return dev_err_probe(&pdev->dev, ret,
+                                    "devm_snd_soc_register_card(%s) failed\n",
+                                    card->name);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id st_audio_acpi_match[] = {
+       {"AMDI8336", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, st_audio_acpi_match);
+#endif
+
+static struct platform_driver st_mach_driver = {
+       .driver = {
+               .name = "st-es8316",
+               .acpi_match_table = ACPI_PTR(st_audio_acpi_match),
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = st_es8336_probe,
+};
+
+module_platform_driver(st_mach_driver);
+
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("st-es8316 audio support");
+MODULE_LICENSE("GPL v2");
index 1cd2e70a57dfc1ff29277cd30e8f3b1846583d37..198358d28ea9b19e87a2912bedc9758bfa264d16 100644 (file)
@@ -433,6 +433,7 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular)
        case I2S_TO_ACP_DMA_CH_NUM:
        case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM:
        case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM:
+       case ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM:
                dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
                break;
        default:
@@ -710,6 +711,13 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
                              acp_mmio, mmACP_EXTERNAL_INTR_STAT);
        }
 
+       if ((intr_flag & BIT(ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM)) != 0) {
+               valid_irq = true;
+               snd_pcm_period_elapsed(irq_data->play_i2s_micsp_stream);
+               acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM)) << 16,
+                             acp_mmio, mmACP_EXTERNAL_INTR_STAT);
+       }
+
        if ((intr_flag & BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) != 0) {
                valid_irq = true;
                snd_pcm_period_elapsed(irq_data->play_i2sbt_stream);
@@ -807,7 +815,8 @@ static int acp_dma_open(struct snd_soc_component *component,
         * stream is not closed
         */
        if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream &&
-           !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream)
+           !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream &&
+           !intr_data->play_i2s_micsp_stream)
                acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -867,6 +876,9 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
                        case I2S_BT_INSTANCE:
                                val |= ACP_I2S_BT_16BIT_RESOLUTION_EN;
                                break;
+                       case I2S_MICSP_INSTANCE:
+                               val |= ACP_I2S_MICSP_16BIT_RESOLUTION_EN;
+                               break;
                        case I2S_SP_INSTANCE:
                        default:
                                val |= ACP_I2S_SP_16BIT_RESOLUTION_EN;
@@ -876,6 +888,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
                        case I2S_BT_INSTANCE:
                                val |= ACP_I2S_BT_16BIT_RESOLUTION_EN;
                                break;
+                       case I2S_MICSP_INSTANCE:
                        case I2S_SP_INSTANCE:
                        default:
                                val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN;
@@ -901,6 +914,27 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
                                        mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW;
                        adata->play_i2sbt_stream = substream;
                        break;
+               case I2S_MICSP_INSTANCE:
+                       switch (adata->asic_type) {
+                       case CHIP_STONEY:
+                               rtd->pte_offset = ACP_ST_PLAYBACK_PTE_OFFSET;
+                               break;
+                       default:
+                               rtd->pte_offset = ACP_PLAYBACK_PTE_OFFSET;
+                       }
+                       rtd->ch1 = SYSRAM_TO_ACP_MICSP_INSTANCE_CH_NUM;
+                       rtd->ch2 = ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM;
+                       rtd->sram_bank = ACP_SRAM_BANK_1_ADDRESS;
+                       rtd->destination = TO_ACP_I2S_2;
+                       rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH4;
+                       rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH5;
+                       rtd->byte_cnt_high_reg_offset =
+                                       mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH;
+                       rtd->byte_cnt_low_reg_offset =
+                                       mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW;
+
+                       adata->play_i2s_micsp_stream = substream;
+                       break;
                case I2S_SP_INSTANCE:
                default:
                        switch (adata->asic_type) {
@@ -939,6 +973,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
                        rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11;
                        adata->capture_i2sbt_stream = substream;
                        break;
+               case I2S_MICSP_INSTANCE:
                case I2S_SP_INSTANCE:
                default:
                        rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
@@ -1160,6 +1195,9 @@ static int acp_dma_close(struct snd_soc_component *component,
                case I2S_BT_INSTANCE:
                        adata->play_i2sbt_stream = NULL;
                        break;
+               case I2S_MICSP_INSTANCE:
+                       adata->play_i2s_micsp_stream = NULL;
+                       break;
                case I2S_SP_INSTANCE:
                default:
                        adata->play_i2ssp_stream = NULL;
@@ -1181,6 +1219,7 @@ static int acp_dma_close(struct snd_soc_component *component,
                case I2S_BT_INSTANCE:
                        adata->capture_i2sbt_stream = NULL;
                        break;
+               case I2S_MICSP_INSTANCE:
                case I2S_SP_INSTANCE:
                default:
                        adata->capture_i2ssp_stream = NULL;
@@ -1197,7 +1236,8 @@ static int acp_dma_close(struct snd_soc_component *component,
         * another stream is also not active.
         */
        if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream &&
-           !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream)
+           !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream &&
+           !adata->play_i2s_micsp_stream)
                acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
        kfree(rtd);
        return 0;
@@ -1245,6 +1285,7 @@ static int acp_audio_probe(struct platform_device *pdev)
        audio_drv_data->capture_i2ssp_stream = NULL;
        audio_drv_data->play_i2sbt_stream = NULL;
        audio_drv_data->capture_i2sbt_stream = NULL;
+       audio_drv_data->play_i2s_micsp_stream = NULL;
 
        audio_drv_data->asic_type =  *pdata;
 
@@ -1333,6 +1374,11 @@ static int acp_pcm_resume(struct device *dev)
                config_acp_dma(adata->acp_mmio, rtd, adata->asic_type);
        }
        if (adata->asic_type != CHIP_CARRIZO) {
+               if (adata->play_i2s_micsp_stream &&
+                   adata->play_i2s_micsp_stream->runtime) {
+                       rtd = adata->play_i2s_micsp_stream->runtime->private_data;
+                       config_acp_dma(adata->acp_mmio, rtd, adata->asic_type);
+               }
                if (adata->play_i2sbt_stream &&
                    adata->play_i2sbt_stream->runtime) {
                        rtd = adata->play_i2sbt_stream->runtime->private_data;
index db80a73aa5932df24bb03f2312cb0a6f4c5279ab..b29bef90f886b3deecb6c229416b317d2e26e86a 100644 (file)
@@ -55,6 +55,7 @@
 
 #define I2S_SP_INSTANCE                 0x01
 #define I2S_BT_INSTANCE                 0x02
+#define I2S_MICSP_INSTANCE             0x03
 #define CAP_CHANNEL0                   0x00
 #define CAP_CHANNEL1                   0x01
 
 #define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 10
 #define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 11
 
+/* Playback DMA channels for I2S MICSP instance */
+#define SYSRAM_TO_ACP_MICSP_INSTANCE_CH_NUM  4
+#define ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM 5
+
 #define NUM_DSCRS_PER_CHANNEL 2
 
 #define PLAYBACK_START_DMA_DESCR_CH12 0
 #define CAPTURE_START_DMA_DESCR_CH11 14
 #define CAPTURE_END_DMA_DESCR_CH11 15
 
+/* I2S MICSP Instance DMA Descriptors */
+#define PLAYBACK_START_DMA_DESCR_CH4 0
+#define PLAYBACK_END_DMA_DESCR_CH4 1
+#define PLAYBACK_START_DMA_DESCR_CH5 2
+#define PLAYBACK_END_DMA_DESCR_CH5 3
+
 #define mmACP_I2S_16BIT_RESOLUTION_EN       0x5209
 #define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01
+#define ACP_I2S_MICSP_16BIT_RESOLUTION_EN 0x01
 #define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02
 #define ACP_I2S_BT_16BIT_RESOLUTION_EN 0x04
 #define ACP_BT_UART_PAD_SELECT_MASK    0x1
@@ -149,6 +161,7 @@ struct audio_drv_data {
        struct snd_pcm_substream *capture_i2ssp_stream;
        struct snd_pcm_substream *play_i2sbt_stream;
        struct snd_pcm_substream *capture_i2sbt_stream;
+       struct snd_pcm_substream *play_i2s_micsp_stream;
        void __iomem *acp_mmio;
        u32 asic_type;
        snd_pcm_sframes_t delay;
index 9dae2719084ce040b4425e8a79f1e043086a0c95..ce003781074311f9451ff0bc97213ec611354d18 100644 (file)
@@ -40,6 +40,17 @@ config SND_AMD_ASOC_RENOIR
        help
          This option enables Renoir I2S support on AMD platform.
 
+config SND_AMD_ASOC_REMBRANDT
+       tristate "AMD ACP ASOC Rembrandt Support"
+       select SND_SOC_AMD_ACP_PCM
+       select SND_SOC_AMD_ACP_I2S
+       select SND_SOC_AMD_ACP_PDM
+       depends on X86 && PCI
+       help
+         This option enables Rembrandt I2S support on AMD platform.
+         Say Y if you want to enable AUDIO on Rembrandt
+         If unsure select "N".
+
 config SND_SOC_AMD_MACH_COMMON
        tristate
        depends on X86 && PCI && I2C
@@ -49,6 +60,7 @@ config SND_SOC_AMD_MACH_COMMON
        select SND_SOC_RT1019
        select SND_SOC_MAX98357A
        select SND_SOC_RT5682S
+       select SND_SOC_NAU8825
        help
          This option enables common Machine driver module for ACP.
 
index 657ddfadf0bbfd81fe95bf2fc3e105d31b6c2b7d..d9abb0ee5218f78301ff552cf9b578db9cdd5766 100644 (file)
@@ -12,6 +12,7 @@ snd-acp-pci-objs     := acp-pci.o
 
 #platform specific driver
 snd-acp-renoir-objs     := acp-renoir.o
+snd-acp-rembrandt-objs  := acp-rembrandt.o
 
 #machine specific driver
 snd-acp-mach-objs     := acp-mach-common.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o
 obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o
 
 obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
+obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o
 
 obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
 obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
index ce9aca8dd6f5159dcd8ba68a060ff45410501bbf..393f729ef561beeb8c7f7262395f28dc31df678d 100644 (file)
@@ -30,11 +30,14 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
 {
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata;
+       struct acp_resource *rsrc;
        u32 val;
        u32 xfer_resolution;
        u32 reg_val;
+       u32 lrclk_div_val, bclk_div_val;
 
        adata = snd_soc_dai_get_drvdata(dai);
+       rsrc = adata->rsrc;
 
        /* These values are as per Hardware Spec */
        switch (params_format(params)) {
@@ -63,6 +66,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
                case I2S_SP_INSTANCE:
                        reg_val = ACP_I2STDM_ITER;
                        break;
+               case I2S_HS_INSTANCE:
+                       reg_val = ACP_HSTDM_ITER;
+                       break;
                default:
                        dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                        return -EINVAL;
@@ -75,6 +81,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
                case I2S_SP_INSTANCE:
                        reg_val = ACP_I2STDM_IRER;
                        break;
+               case I2S_HS_INSTANCE:
+                       reg_val = ACP_HSTDM_IRER;
+                       break;
                default:
                        dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                        return -EINVAL;
@@ -86,6 +95,74 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
        val = val | (xfer_resolution  << 3);
        writel(val, adata->acp_base + reg_val);
 
+       if (rsrc->soc_mclk) {
+               switch (params_format(params)) {
+               case SNDRV_PCM_FORMAT_S16_LE:
+                       switch (params_rate(params)) {
+                       case 8000:
+                               bclk_div_val = 768;
+                               break;
+                       case 16000:
+                               bclk_div_val = 384;
+                               break;
+                       case 24000:
+                               bclk_div_val = 256;
+                               break;
+                       case 32000:
+                               bclk_div_val = 192;
+                               break;
+                       case 44100:
+                       case 48000:
+                               bclk_div_val = 128;
+                               break;
+                       case 88200:
+                       case 96000:
+                               bclk_div_val = 64;
+                               break;
+                       case 192000:
+                               bclk_div_val = 32;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       lrclk_div_val = 32;
+                       break;
+               case SNDRV_PCM_FORMAT_S32_LE:
+                       switch (params_rate(params)) {
+                       case 8000:
+                               bclk_div_val = 384;
+                               break;
+                       case 16000:
+                               bclk_div_val = 192;
+                               break;
+                       case 24000:
+                               bclk_div_val = 128;
+                               break;
+                       case 32000:
+                               bclk_div_val = 96;
+                               break;
+                       case 44100:
+                       case 48000:
+                               bclk_div_val = 64;
+                               break;
+                       case 88200:
+                       case 96000:
+                               bclk_div_val = 32;
+                               break;
+                       case 192000:
+                               bclk_div_val = 16;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       lrclk_div_val = 64;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               adata->lrclk_div = lrclk_div_val;
+               adata->bclk_div = bclk_div_val;
+       }
        return 0;
 }
 
@@ -94,6 +171,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
        struct acp_stream *stream = substream->runtime->private_data;
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_resource *rsrc = adata->rsrc;
        u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
 
        period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
@@ -118,6 +196,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                                ier_val = ACP_I2STDM_IER;
                                buf_reg = ACP_I2S_TX_RINGBUFSIZE;
                                break;
+                       case I2S_HS_INSTANCE:
+                               water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
+                               reg_val = ACP_HSTDM_ITER;
+                               ier_val = ACP_HSTDM_IER;
+                               buf_reg = ACP_HS_TX_RINGBUFSIZE;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -136,6 +220,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                                ier_val = ACP_I2STDM_IER;
                                buf_reg = ACP_I2S_RX_RINGBUFSIZE;
                                break;
+                       case I2S_HS_INSTANCE:
+                               water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
+                               reg_val = ACP_HSTDM_IRER;
+                               ier_val = ACP_HSTDM_IER;
+                               buf_reg = ACP_HS_RX_RINGBUFSIZE;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -147,6 +237,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                val = val | BIT(0);
                writel(val, adata->acp_base + reg_val);
                writel(1, adata->acp_base + ier_val);
+               if (rsrc->soc_mclk)
+                       acp_set_i2s_clk(adata, dai->driver->id);
                return 0;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -159,6 +251,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                        case I2S_SP_INSTANCE:
                                reg_val = ACP_I2STDM_ITER;
                                break;
+                       case I2S_HS_INSTANCE:
+                               reg_val = ACP_HSTDM_ITER;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -172,6 +267,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                        case I2S_SP_INSTANCE:
                                reg_val = ACP_I2STDM_IRER;
                                break;
+                       case I2S_HS_INSTANCE:
+                               reg_val = ACP_HSTDM_IRER;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -187,6 +285,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
                    !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
                        writel(0, adata->acp_base + ACP_I2STDM_IER);
+               if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
+                   !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
+                       writel(0, adata->acp_base + ACP_HSTDM_IER);
                return 0;
        default:
                return -EINVAL;
@@ -199,6 +300,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
 {
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_resource *rsrc = adata->rsrc;
        struct acp_stream *stream = substream->runtime->private_data;
        u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
        u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
@@ -208,7 +310,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
        case I2S_SP_INSTANCE:
                if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
                        reg_dma_size = ACP_I2S_TX_DMA_SIZE;
-                       acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+                       acp_fifo_addr = rsrc->sram_pte_offset +
                                                SP_PB_FIFO_ADDR_OFFSET;
                        reg_fifo_addr = ACP_I2S_TX_FIFOADDR;
                        reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
@@ -217,7 +319,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
                        writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
                } else {
                        reg_dma_size = ACP_I2S_RX_DMA_SIZE;
-                       acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+                       acp_fifo_addr = rsrc->sram_pte_offset +
                                                SP_CAPT_FIFO_ADDR_OFFSET;
                        reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
                        reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
@@ -228,7 +330,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
        case I2S_BT_INSTANCE:
                if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
                        reg_dma_size = ACP_BT_TX_DMA_SIZE;
-                       acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+                       acp_fifo_addr = rsrc->sram_pte_offset +
                                                BT_PB_FIFO_ADDR_OFFSET;
                        reg_fifo_addr = ACP_BT_TX_FIFOADDR;
                        reg_fifo_size = ACP_BT_TX_FIFOSIZE;
@@ -237,7 +339,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
                        writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
                } else {
                        reg_dma_size = ACP_BT_RX_DMA_SIZE;
-                       acp_fifo_addr = ACP_SRAM_PTE_OFFSET +
+                       acp_fifo_addr = rsrc->sram_pte_offset +
                                                BT_CAPT_FIFO_ADDR_OFFSET;
                        reg_fifo_addr = ACP_BT_RX_FIFOADDR;
                        reg_fifo_size = ACP_BT_RX_FIFOSIZE;
@@ -246,6 +348,27 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
                        writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
                }
                break;
+       case I2S_HS_INSTANCE:
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       reg_dma_size = ACP_HS_TX_DMA_SIZE;
+                       acp_fifo_addr = rsrc->sram_pte_offset +
+                               HS_PB_FIFO_ADDR_OFFSET;
+                       reg_fifo_addr = ACP_HS_TX_FIFOADDR;
+                       reg_fifo_size = ACP_HS_TX_FIFOSIZE;
+
+                       phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
+               } else {
+                       reg_dma_size = ACP_HS_RX_DMA_SIZE;
+                       acp_fifo_addr = rsrc->sram_pte_offset +
+                                       HS_CAPT_FIFO_ADDR_OFFSET;
+                       reg_fifo_addr = ACP_HS_RX_FIFOADDR;
+                       reg_fifo_size = ACP_HS_RX_FIFOSIZE;
+
+                       phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
+               }
+               break;
        default:
                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                return -EINVAL;
@@ -255,11 +378,15 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
        writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
        writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
 
-       ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
-       ext_int_ctrl |= BIT(I2S_RX_THRESHOLD) | BIT(BT_RX_THRESHOLD)
-                       | BIT(I2S_TX_THRESHOLD) | BIT(BT_TX_THRESHOLD);
+       ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+       ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
+                       BIT(BT_RX_THRESHOLD(rsrc->offset)) |
+                       BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
+                       BIT(BT_TX_THRESHOLD(rsrc->offset)) |
+                       BIT(HS_RX_THRESHOLD(rsrc->offset)) |
+                       BIT(HS_TX_THRESHOLD(rsrc->offset));
 
-       writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+       writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
 
        return 0;
 }
@@ -268,32 +395,45 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
 {
        struct acp_stream *stream = substream->runtime->private_data;
        struct device *dev = dai->component->dev;
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_resource *rsrc = adata->rsrc;
        unsigned int dir = substream->stream;
        unsigned int irq_bit = 0;
 
        switch (dai->driver->id) {
        case I2S_SP_INSTANCE:
                if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
-                       irq_bit = BIT(I2S_TX_THRESHOLD);
+                       irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));
                        stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
                        stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
                } else {
-                       irq_bit = BIT(I2S_RX_THRESHOLD);
+                       irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));
                        stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
                        stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
                }
                break;
        case I2S_BT_INSTANCE:
                if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
-                       irq_bit = BIT(BT_TX_THRESHOLD);
+                       irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));
                        stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
                        stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
                } else {
-                       irq_bit = BIT(BT_RX_THRESHOLD);
+                       irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));
                        stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
                        stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
                }
                break;
+       case I2S_HS_INSTANCE:
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
+                       stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
+                       stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
+               } else {
+                       irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
+                       stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
+                       stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
+               }
+               break;
        default:
                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                return -EINVAL;
@@ -319,6 +459,7 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
 {
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_resource *rsrc = adata->rsrc;
        unsigned int val;
 
        if (!adata->acp_base) {
@@ -326,8 +467,8 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
                return -EINVAL;
        }
 
-       val = readl(adata->acp_base + ACP_I2S_PIN_CONFIG);
-       if (val != I2S_MODE) {
+       val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset);
+       if (val != rsrc->i2s_mode) {
                dev_err(dev, "I2S Mode not supported val %x\n", val);
                return -EINVAL;
        }
index 7f04a048ca3a2db6f2ead248e2639fca66298390..1f4878ff7d3721dc1122a2c27288687477e23105 100644 (file)
@@ -47,6 +47,28 @@ static struct acp_card_drvdata rt5682s_rt1019_data = {
        .dmic_codec_id = DMIC,
 };
 
+static struct acp_card_drvdata max_nau8825_data = {
+       .hs_cpu_id = I2S_HS,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = DMIC,
+       .hs_codec_id = NAU8825,
+       .amp_codec_id = MAX98360A,
+       .dmic_codec_id = DMIC,
+       .soc_mclk = true,
+       .platform = REMBRANDT,
+};
+
+static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
+       .hs_cpu_id = I2S_HS,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = DMIC,
+       .hs_codec_id = RT5682S,
+       .amp_codec_id = RT1019,
+       .dmic_codec_id = DMIC,
+       .soc_mclk = true,
+       .platform = REMBRANDT,
+};
+
 static const struct snd_kcontrol_new acp_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -112,6 +134,14 @@ static const struct platform_device_id board_ids[] = {
                .name = "acp3xalc5682s1019",
                .driver_data = (kernel_ulong_t)&rt5682s_rt1019_data,
        },
+       {
+               .name = "rmb-nau8825-max",
+               .driver_data = (kernel_ulong_t)&max_nau8825_data,
+       },
+       {
+               .name = "rmb-rt5682s-rt1019",
+               .driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data,
+       },
        { }
 };
 static struct platform_driver acp_asoc_audio = {
@@ -130,4 +160,6 @@ MODULE_DESCRIPTION("ACP chrome audio support");
 MODULE_ALIAS("platform:acp3xalc56821019");
 MODULE_ALIAS("platform:acp3xalc5682sm98360");
 MODULE_ALIAS("platform:acp3xalc5682s1019");
+MODULE_ALIAS("platform:rmb-nau8825-max");
+MODULE_ALIAS("platform:rmb-rt5682s-rt1019");
 MODULE_LICENSE("GPL v2");
index 6ae454bf60afa97f9c5f380c2dc76122b6428f44..f0c49127aad11178770e2d186b8be62f50ea916d 100644 (file)
@@ -24,6 +24,7 @@
 #include "../../codecs/rt5682.h"
 #include "../../codecs/rt1019.h"
 #include "../../codecs/rt5682s.h"
+#include "../../codecs/nau8825.h"
 #include "acp-mach.h"
 
 #define PCO_PLAT_CLK 48000000
@@ -148,9 +149,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
        struct acp_card_drvdata *drvdata = card->drvdata;
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        int ret;
+       unsigned int fmt;
 
-       ret =  snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-                                  | SND_SOC_DAIFMT_CBP_CFP);
+       if (drvdata->soc_mclk)
+               fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+       else
+               fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+       ret =  snd_soc_dai_set_fmt(codec_dai, fmt);
        if (ret < 0) {
                dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
                return ret;
@@ -161,10 +167,13 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
                                      &constraints_channels);
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                      &constraints_rates);
-
-       ret = acp_clk_enable(drvdata);
-       if (ret < 0)
-               dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+       if (!drvdata->soc_mclk) {
+               ret = acp_clk_enable(drvdata);
+               if (ret < 0) {
+                       dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
+                       return ret;
+               }
+       }
 
        return ret;
 }
@@ -175,7 +184,8 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream)
        struct snd_soc_card *card = rtd->card;
        struct acp_card_drvdata *drvdata = card->drvdata;
 
-       clk_disable_unprepare(drvdata->wclk);
+       if (!drvdata->soc_mclk)
+               clk_disable_unprepare(drvdata->wclk);
 }
 
 static const struct snd_soc_ops acp_card_rt5682_ops = {
@@ -199,6 +209,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
        struct acp_card_drvdata *drvdata = card->drvdata;
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        struct snd_soc_component *component = codec_dai->component;
+       unsigned int fmt;
        int ret;
 
        dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
@@ -206,8 +217,12 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
        if (drvdata->hs_codec_id != RT5682S)
                return -EINVAL;
 
-       ret =  snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-                                  | SND_SOC_DAIFMT_CBP_CFP);
+       if (drvdata->soc_mclk)
+               fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+       else
+               fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+       ret =  snd_soc_dai_set_fmt(codec_dai, fmt);
        if (ret < 0) {
                dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
                return ret;
@@ -234,8 +249,10 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
-       drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
+       if (!drvdata->soc_mclk) {
+               drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
+               drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
+       }
 
        ret = snd_soc_card_jack_new(card, "Headset Jack",
                                    SND_JACK_HEADSET | SND_JACK_LINEOUT |
@@ -363,7 +380,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct acp_card_drvdata *drvdata = card->drvdata;
-       int ret;
+       int ret = 0;
 
        runtime->hw.channels_max = DUAL_CHANNEL;
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
@@ -371,10 +388,13 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream)
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                      &constraints_rates);
 
-       ret = acp_clk_enable(drvdata);
-       if (ret < 0)
-               dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
-
+       if (!drvdata->soc_mclk) {
+               ret = acp_clk_enable(drvdata);
+               if (ret < 0) {
+                       dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
+                       return ret;
+               }
+       }
        return ret;
 }
 
@@ -409,6 +429,104 @@ static const struct snd_soc_ops acp_card_maxim_ops = {
        .shutdown = acp_card_shutdown,
 };
 
+/* Declare nau8825 codec components */
+SND_SOC_DAILINK_DEF(nau8825,
+                   DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi")));
+
+static const struct snd_soc_dapm_route nau8825_map[] = {
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+};
+
+static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct acp_card_drvdata *drvdata = card->drvdata;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       unsigned int fmt;
+       int ret;
+
+       dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+       if (drvdata->hs_codec_id != NAU8825)
+               return -EINVAL;
+
+       if (drvdata->soc_mclk)
+               fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+       else
+               fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+
+       ret =  snd_soc_dai_set_fmt(codec_dai, fmt);
+       if (ret < 0) {
+               dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+               return ret;
+       }
+       ret = snd_soc_card_jack_new(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &pco_jack);
+       if (ret) {
+               dev_err(card->dev, "HP jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map));
+}
+
+static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS,
+                                    (48000 * 256), SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params),
+                                 params_rate(params) * 256);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set FLL: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int acp_nau8825_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = 2;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &constraints_channels);
+
+       runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
+       snd_pcm_hw_constraint_list(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+       return 0;
+}
+
+static const struct snd_soc_ops acp_card_nau8825_ops = {
+       .startup =  acp_nau8825_startup,
+       .hw_params = acp_nau8825_hw_params,
+};
+
 /* Declare DMIC codec components */
 SND_SOC_DAILINK_DEF(dmic_codec,
                DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
@@ -427,6 +545,12 @@ static struct snd_soc_dai_link_component platform_component[] = {
        }
 };
 
+static struct snd_soc_dai_link_component platform_rmb_component[] = {
+       {
+               .name = "acp_asoc_rembrandt.0",
+       }
+};
+
 static struct snd_soc_dai_link_component sof_component[] = {
        {
                 .name = "0000:04:00.5",
@@ -435,8 +559,12 @@ static struct snd_soc_dai_link_component sof_component[] = {
 
 SND_SOC_DAILINK_DEF(i2s_sp,
        DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
+SND_SOC_DAILINK_DEF(i2s_hs,
+                   DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-hs")));
 SND_SOC_DAILINK_DEF(sof_sp,
        DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
+SND_SOC_DAILINK_DEF(sof_hs,
+                   DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs")));
 SND_SOC_DAILINK_DEF(sof_dmic,
        DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
 SND_SOC_DAILINK_DEF(pdm_dmic,
@@ -491,6 +619,37 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
                i++;
        }
 
+       if (drv_data->hs_cpu_id == I2S_HS) {
+               links[i].name = "acp-headset-codec";
+               links[i].id = HEADSET_BE_ID;
+               links[i].cpus = sof_hs;
+               links[i].num_cpus = ARRAY_SIZE(sof_hs);
+               links[i].platforms = sof_component;
+               links[i].num_platforms = ARRAY_SIZE(sof_component);
+               links[i].dpcm_playback = 1;
+               links[i].dpcm_capture = 1;
+               links[i].nonatomic = true;
+               links[i].no_pcm = 1;
+               if (!drv_data->hs_codec_id) {
+                       /* Use dummy codec if codec id not specified */
+                       links[i].codecs = dummy_codec;
+                       links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+               }
+               if (drv_data->hs_codec_id == NAU8825) {
+                       links[i].codecs = nau8825;
+                       links[i].num_codecs = ARRAY_SIZE(nau8825);
+                       links[i].init = acp_card_nau8825_init;
+                       links[i].ops = &acp_card_nau8825_ops;
+               }
+               if (drv_data->hs_codec_id == RT5682S) {
+                       links[i].codecs = rt5682s;
+                       links[i].num_codecs = ARRAY_SIZE(rt5682s);
+                       links[i].init = acp_card_rt5682s_init;
+                       links[i].ops = &acp_card_rt5682s_ops;
+               }
+               i++;
+       }
+
        if (drv_data->amp_cpu_id == I2S_SP) {
                links[i].name = "acp-amp-codec";
                links[i].id = AMP_BE_ID;
@@ -523,6 +682,38 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
                i++;
        }
 
+       if (drv_data->amp_cpu_id == I2S_HS) {
+               links[i].name = "acp-amp-codec";
+               links[i].id = AMP_BE_ID;
+               links[i].cpus = sof_hs;
+               links[i].num_cpus = ARRAY_SIZE(sof_hs);
+               links[i].platforms = sof_component;
+               links[i].num_platforms = ARRAY_SIZE(sof_component);
+               links[i].dpcm_playback = 1;
+               links[i].nonatomic = true;
+               links[i].no_pcm = 1;
+               if (!drv_data->amp_codec_id) {
+                       /* Use dummy codec if codec id not specified */
+                       links[i].codecs = dummy_codec;
+                       links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+               }
+               if (drv_data->amp_codec_id == MAX98360A) {
+                       links[i].codecs = max98360a;
+                       links[i].num_codecs = ARRAY_SIZE(max98360a);
+                       links[i].ops = &acp_card_maxim_ops;
+                       links[i].init = acp_card_maxim_init;
+               }
+               if (drv_data->amp_codec_id == RT1019) {
+                       links[i].codecs = rt1019;
+                       links[i].num_codecs = ARRAY_SIZE(rt1019);
+                       links[i].ops = &acp_card_rt1019_ops;
+                       links[i].init = acp_card_rt1019_init;
+                       card->codec_conf = rt1019_conf;
+                       card->num_configs = ARRAY_SIZE(rt1019_conf);
+               }
+               i++;
+       }
+
        if (drv_data->dmic_cpu_id == DMIC) {
                links[i].name = "acp-dmic-codec";
                links[i].id = DMIC_BE_ID;
@@ -591,6 +782,40 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
                i++;
        }
 
+       if (drv_data->hs_cpu_id == I2S_HS) {
+               links[i].name = "acp-headset-codec";
+               links[i].id = HEADSET_BE_ID;
+               links[i].cpus = i2s_hs;
+               links[i].num_cpus = ARRAY_SIZE(i2s_hs);
+               if (drv_data->platform == REMBRANDT) {
+                       links[i].platforms = platform_rmb_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
+               } else {
+                       links[i].platforms = platform_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_component);
+               }
+               links[i].dpcm_playback = 1;
+               links[i].dpcm_capture = 1;
+               if (!drv_data->hs_codec_id) {
+                       /* Use dummy codec if codec id not specified */
+                       links[i].codecs = dummy_codec;
+                       links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+               }
+               if (drv_data->hs_codec_id == NAU8825) {
+                       links[i].codecs = nau8825;
+                       links[i].num_codecs = ARRAY_SIZE(nau8825);
+                       links[i].init = acp_card_nau8825_init;
+                       links[i].ops = &acp_card_nau8825_ops;
+               }
+               if (drv_data->hs_codec_id == RT5682S) {
+                       links[i].codecs = rt5682s;
+                       links[i].num_codecs = ARRAY_SIZE(rt5682s);
+                       links[i].init = acp_card_rt5682s_init;
+                       links[i].ops = &acp_card_rt5682s_ops;
+               }
+               i++;
+       }
+
        if (drv_data->amp_cpu_id == I2S_SP) {
                links[i].name = "acp-amp-codec";
                links[i].id = AMP_BE_ID;
@@ -621,6 +846,41 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
                i++;
        }
 
+       if (drv_data->amp_cpu_id == I2S_HS) {
+               links[i].name = "acp-amp-codec";
+               links[i].id = AMP_BE_ID;
+               links[i].cpus = i2s_hs;
+               links[i].num_cpus = ARRAY_SIZE(i2s_hs);
+               if (drv_data->platform == REMBRANDT) {
+                       links[i].platforms = platform_rmb_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
+               } else {
+                       links[i].platforms = platform_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_component);
+               }
+               links[i].dpcm_playback = 1;
+               if (!drv_data->amp_codec_id) {
+                       /* Use dummy codec if codec id not specified */
+                       links[i].codecs = dummy_codec;
+                       links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+               }
+               if (drv_data->amp_codec_id == MAX98360A) {
+                       links[i].codecs = max98360a;
+                       links[i].num_codecs = ARRAY_SIZE(max98360a);
+                       links[i].ops = &acp_card_maxim_ops;
+                       links[i].init = acp_card_maxim_init;
+               }
+               if (drv_data->amp_codec_id == RT1019) {
+                       links[i].codecs = rt1019;
+                       links[i].num_codecs = ARRAY_SIZE(rt1019);
+                       links[i].ops = &acp_card_rt1019_ops;
+                       links[i].init = acp_card_rt1019_init;
+                       card->codec_conf = rt1019_conf;
+                       card->num_configs = ARRAY_SIZE(rt1019_conf);
+               }
+               i++;
+       }
+
        if (drv_data->dmic_cpu_id == DMIC) {
                links[i].name = "acp-dmic-codec";
                links[i].id = DMIC_BE_ID;
@@ -634,8 +894,13 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
                }
                links[i].cpus = pdm_dmic;
                links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
-               links[i].platforms = platform_component;
-               links[i].num_platforms = ARRAY_SIZE(platform_component);
+               if (drv_data->platform == REMBRANDT) {
+                       links[i].platforms = platform_rmb_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
+               } else {
+                       links[i].platforms = platform_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_component);
+               }
                links[i].ops = &acp_card_dmic_ops;
                links[i].dpcm_capture = 1;
        }
index 5dc47cfbff10e5ff7080c42a391ec24a5fc3ee8b..20583ef902df7b6d0aef36e62a361ebfe648d094 100644 (file)
@@ -26,6 +26,7 @@ enum be_id {
 
 enum cpu_endpoints {
        NONE = 0,
+       I2S_HS,
        I2S_SP,
        I2S_BT,
        DMIC,
@@ -37,6 +38,12 @@ enum codec_endpoints {
        RT1019,
        MAX98360A,
        RT5682S,
+       NAU8825,
+};
+
+enum platform_end_point {
+       RENOIR = 0,
+       REMBRANDT,
 };
 
 struct acp_card_drvdata {
@@ -47,8 +54,10 @@ struct acp_card_drvdata {
        unsigned int amp_codec_id;
        unsigned int dmic_codec_id;
        unsigned int dai_fmt;
+       unsigned int platform;
        struct clk *wclk;
        struct clk *bclk;
+       bool soc_mclk;
 };
 
 int acp_sofdsp_dai_links_create(struct snd_soc_card *card);
index c893963ee2d062fb4cf5e02072f6048a5947a10d..2c8e960cc9a6a96fa4e9ad1eeb13075fcdec96fb 100644 (file)
@@ -29,7 +29,7 @@
 static struct platform_device *dmic_dev;
 static struct platform_device *pdev;
 
-static const struct resource acp3x_res[] = {
+static const struct resource acp_res[] = {
        {
                .start = 0,
                .end = ACP3x_REG_END - ACP3x_REG_START,
@@ -70,36 +70,49 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
        ret = pci_request_regions(pci, "AMD ACP3x audio");
        if (ret < 0) {
                dev_err(&pci->dev, "pci_request_regions failed\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto disable_pci;
        }
 
        pci_set_master(pci);
 
+       res_acp = acp_res;
+       num_res = ARRAY_SIZE(acp_res);
+
        switch (pci->revision) {
        case 0x01:
-               res_acp = acp3x_res;
-               num_res = ARRAY_SIZE(acp3x_res);
                chip->name = "acp_asoc_renoir";
                chip->acp_rev = ACP3X_DEV;
                break;
+       case 0x6f:
+               chip->name = "acp_asoc_rembrandt";
+               chip->acp_rev = ACP6X_DEV;
+               break;
        default:
                dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto release_regions;
        }
 
        dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(dmic_dev)) {
                dev_err(dev, "failed to create DMIC device\n");
-               return PTR_ERR(dmic_dev);
+               ret = PTR_ERR(dmic_dev);
+               goto release_regions;
        }
 
        addr = pci_resource_start(pci, 0);
        chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
+       if (!chip->base) {
+               ret = -ENOMEM;
+               goto release_regions;
+       }
 
        res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL);
        if (!res) {
                platform_device_unregister(dmic_dev);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto release_regions;
        }
 
        for (i = 0; i < num_res; i++, res_acp++) {
@@ -128,8 +141,16 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
                dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
                platform_device_unregister(dmic_dev);
                ret = PTR_ERR(pdev);
+               goto release_regions;
        }
 
+       return ret;
+
+release_regions:
+       pci_release_regions(pci);
+disable_pci:
+       pci_disable_device(pci);
+
        return ret;
 };
 
index 424c6e0bb9d6d5ec3ef952a68459e4c258e6f026..66ec6b6a597230b0a0c2b4e3c41339753597786a 100644 (file)
@@ -160,9 +160,9 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream,
        stream->reg_offset = ACP_REGION2_OFFSET;
 
        /* Enable DMIC Interrupts */
-       ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+       ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));
        ext_int_ctrl |= PDM_DMA_INTR_MASK;
-       writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+       writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));
 
        return 0;
 }
@@ -174,10 +174,10 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream,
        struct acp_dev_data *adata = dev_get_drvdata(dev);
        u32 ext_int_ctrl;
 
-       /* Disable DMIC interrrupts */
-       ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+       /* Disable DMIC interrupts */
+       ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));
        ext_int_ctrl |= ~PDM_DMA_INTR_MASK;
-       writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL);
+       writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));
 }
 
 const struct snd_soc_dai_ops acp_dmic_dai_ops = {
index 65a809e2c29fffc31533df6f56a27883ea3b6795..f561d39b33e2adb8638f36aada844ed609554c3e 100644 (file)
@@ -91,25 +91,38 @@ EXPORT_SYMBOL_NS_GPL(acp_machine_select, SND_SOC_ACP_COMMON);
 static irqreturn_t i2s_irq_handler(int irq, void *data)
 {
        struct acp_dev_data *adata = data;
+       struct acp_resource *rsrc = adata->rsrc;
        struct acp_stream *stream;
        u16 i2s_flag = 0;
-       u32 val, i;
+       u32 ext_intr_stat, ext_intr_stat1, i;
 
        if (!adata)
                return IRQ_NONE;
 
-       val = readl(adata->acp_base + ACP_EXTERNAL_INTR_STAT);
+       if (adata->rsrc->no_of_ctrls == 2)
+               ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1)));
+
+       ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
 
        for (i = 0; i < ACP_MAX_STREAM; i++) {
                stream = adata->stream[i];
-               if (stream && (val & stream->irq_bit)) {
-                       writel(stream->irq_bit, adata->acp_base + ACP_EXTERNAL_INTR_STAT);
+               if (stream && (ext_intr_stat & stream->irq_bit)) {
+                       writel(stream->irq_bit,
+                              ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
                        snd_pcm_period_elapsed(stream->substream);
                        i2s_flag = 1;
                        break;
                }
+               if (adata->rsrc->no_of_ctrls == 2) {
+                       if (stream && (ext_intr_stat1 & stream->irq_bit)) {
+                               writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata,
+                                      (rsrc->irqp_used - 1)));
+                               snd_pcm_period_elapsed(stream->substream);
+                               i2s_flag = 1;
+                               break;
+                       }
+               }
        }
-
        if (i2s_flag)
                return IRQ_HANDLED;
 
@@ -118,6 +131,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
 
 static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream)
 {
+       struct acp_resource *rsrc = adata->rsrc;
        u32 pte_reg, pte_size, reg_val;
 
        /* Use ATU base Group5 */
@@ -126,15 +140,17 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream
        stream->reg_offset = 0x02000000;
 
        /* Group Enable */
-       reg_val = ACP_SRAM_PTE_OFFSET;
+       reg_val = rsrc->sram_pte_offset;
        writel(reg_val | BIT(31), adata->acp_base + pte_reg);
        writel(PAGE_SIZE_4K_ENABLE,  adata->acp_base + pte_size);
+       writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
 }
 
 static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size)
 {
        struct acp_stream *stream = adata->stream[cpu_id];
        struct snd_pcm_substream *substream = stream->substream;
+       struct acp_resource *rsrc = adata->rsrc;
        dma_addr_t addr = substream->dma_buffer.addr;
        int num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
        u32 low, high, val;
@@ -146,9 +162,9 @@ static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size)
                /* Load the low address of page int ACP SRAM through SRBM */
                low = lower_32_bits(addr);
                high = upper_32_bits(addr);
-               writel(low, adata->acp_base + ACP_SCRATCH_REG_0 + val);
+               writel(low, adata->acp_base + rsrc->scratch_reg_offset + val);
                high |= BIT(31);
-               writel(high, adata->acp_base + ACP_SCRATCH_REG_0 + val + 4);
+               writel(high, adata->acp_base + rsrc->scratch_reg_offset + val + 4);
 
                /* Move to next physically contiguous page */
                val += 8;
@@ -187,7 +203,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
        }
        runtime->private_data = stream;
 
-       writel(1, adata->acp_base + ACP_EXTERNAL_INTR_ENB);
+       writel(1, ACP_EXTERNAL_INTR_ENB(adata));
 
        return ret;
 }
@@ -242,13 +258,6 @@ static int acp_dma_new(struct snd_soc_component *component,
        return 0;
 }
 
-static int acp_dma_mmap(struct snd_soc_component *component,
-                       struct snd_pcm_substream *substream,
-                       struct vm_area_struct *vma)
-{
-       return snd_pcm_lib_default_mmap(substream, vma);
-}
-
 static int acp_dma_close(struct snd_soc_component *component,
                         struct snd_pcm_substream *substream)
 {
@@ -267,13 +276,13 @@ static int acp_dma_close(struct snd_soc_component *component,
 }
 
 static const struct snd_soc_component_driver acp_pcm_component = {
-       .name           = DRV_NAME,
-       .open           = acp_dma_open,
-       .close          = acp_dma_close,
-       .hw_params      = acp_dma_hw_params,
-       .pointer        = acp_dma_pointer,
-       .mmap           = acp_dma_mmap,
-       .pcm_construct  = acp_dma_new,
+       .name                   = DRV_NAME,
+       .open                   = acp_dma_open,
+       .close                  = acp_dma_close,
+       .hw_params              = acp_dma_hw_params,
+       .pointer                = acp_dma_pointer,
+       .pcm_construct          = acp_dma_new,
+       .legacy_dai_naming      = 1,
 };
 
 int acp_platform_register(struct device *dev)
diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c
new file mode 100644 (file)
index 0000000..2b57c0c
--- /dev/null
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Advanced Micro Devices, Inc.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+//          V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
+/*
+ * Hardware interface for Renoir ACP block
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <linux/dma-mapping.h>
+
+#include "amd.h"
+
+#define DRV_NAME "acp_asoc_rembrandt"
+
+#define ACP6X_PGFSM_CONTROL                    0x1024
+#define ACP6X_PGFSM_STATUS                     0x1028
+
+#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK  0x00010001
+
+#define ACP_PGFSM_CNTL_POWER_ON_MASK           0x01
+#define ACP_PGFSM_CNTL_POWER_OFF_MASK          0x00
+#define ACP_PGFSM_STATUS_MASK                  0x03
+#define ACP_POWERED_ON                         0x00
+#define ACP_POWER_ON_IN_PROGRESS               0x01
+#define ACP_POWERED_OFF                                0x02
+#define ACP_POWER_OFF_IN_PROGRESS              0x03
+
+#define ACP_ERROR_MASK                         0x20000000
+#define ACP_EXT_INTR_STAT_CLEAR_MASK           0xFFFFFFFF
+
+
+static int rmb_acp_init(void __iomem *base);
+static int rmb_acp_deinit(void __iomem *base);
+
+static struct acp_resource rsrc = {
+       .offset = 0,
+       .no_of_ctrls = 2,
+       .irqp_used = 1,
+       .soc_mclk = true,
+       .irq_reg_offset = 0x1a00,
+       .i2s_pin_cfg_offset = 0x1440,
+       .i2s_mode = 0x0a,
+       .scratch_reg_offset = 0x12800,
+       .sram_pte_offset = 0x03802800,
+};
+
+static struct snd_soc_acpi_codecs amp_rt1019 = {
+       .num_codecs = 1,
+       .codecs = {"10EC1019"}
+};
+
+static struct snd_soc_acpi_codecs amp_max = {
+       .num_codecs = 1,
+       .codecs = {"MX98360A"}
+};
+
+static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = {
+       {
+               .id = "10508825",
+               .drv_name = "rmb-nau8825-max",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_max,
+       },
+       {
+               .id = "AMDI0007",
+               .drv_name = "rembrandt-acp",
+       },
+       {
+               .id = "RTL5682",
+               .drv_name = "rmb-rt5682s-rt1019",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_rt1019,
+       },
+       {},
+};
+
+static struct snd_soc_dai_driver acp_rmb_dai[] = {
+{
+       .name = "acp-i2s-sp",
+       .id = I2S_SP_INSTANCE,
+       .playback = {
+               .stream_name = "I2S SP Playback",
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .stream_name = "I2S SP Capture",
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &asoc_acp_cpu_dai_ops,
+       .probe = &asoc_acp_i2s_probe,
+},
+{
+       .name = "acp-i2s-bt",
+       .id = I2S_BT_INSTANCE,
+       .playback = {
+               .stream_name = "I2S BT Playback",
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .stream_name = "I2S BT Capture",
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &asoc_acp_cpu_dai_ops,
+       .probe = &asoc_acp_i2s_probe,
+},
+{
+       .name = "acp-i2s-hs",
+       .id = I2S_HS_INSTANCE,
+       .playback = {
+               .stream_name = "I2S HS Playback",
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .stream_name = "I2S HS Capture",
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &asoc_acp_cpu_dai_ops,
+       .probe = &asoc_acp_i2s_probe,
+},
+{
+       .name = "acp-pdm-dmic",
+       .id = DMIC_INSTANCE,
+       .capture = {
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &acp_dmic_dai_ops,
+},
+};
+
+static int acp6x_power_on(void __iomem *base)
+{
+       u32 val;
+       int timeout;
+
+       val = readl(base + ACP6X_PGFSM_STATUS);
+
+       if (val == ACP_POWERED_ON)
+               return 0;
+
+       if ((val & ACP_PGFSM_STATUS_MASK) !=
+                               ACP_POWER_ON_IN_PROGRESS)
+               writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
+                      base + ACP6X_PGFSM_CONTROL);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP6X_PGFSM_STATUS);
+               if (!val)
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int acp6x_power_off(void __iomem *base)
+{
+       u32 val;
+       int timeout;
+
+       writel(ACP_PGFSM_CNTL_POWER_OFF_MASK,
+              base + ACP6X_PGFSM_CONTROL);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP6X_PGFSM_STATUS);
+               if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF)
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int acp6x_reset(void __iomem *base)
+{
+       u32 val;
+       int timeout;
+
+       writel(1, base + ACP_SOFT_RESET);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP_SOFT_RESET);
+               if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
+                       break;
+               cpu_relax();
+       }
+       writel(0, base + ACP_SOFT_RESET);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP_SOFT_RESET);
+               if (!val)
+                       return 0;
+               cpu_relax();
+       }
+       return -ETIMEDOUT;
+}
+
+static void acp6x_enable_interrupts(struct acp_dev_data *adata)
+{
+       struct acp_resource *rsrc = adata->rsrc;
+       u32 ext_intr_ctrl;
+
+       writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));
+       ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+       ext_intr_ctrl |= ACP_ERROR_MASK;
+       writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+}
+
+static void acp6x_disable_interrupts(struct acp_dev_data *adata)
+{
+       struct acp_resource *rsrc = adata->rsrc;
+
+       writel(ACP_EXT_INTR_STAT_CLEAR_MASK,
+              ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
+       writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));
+}
+
+static int rmb_acp_init(void __iomem *base)
+{
+       int ret;
+
+       /* power on */
+       ret = acp6x_power_on(base);
+       if (ret) {
+               pr_err("ACP power on failed\n");
+               return ret;
+       }
+       writel(0x01, base + ACP_CONTROL);
+
+       /* Reset */
+       ret = acp6x_reset(base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmb_acp_deinit(void __iomem *base)
+{
+       int ret = 0;
+
+       /* Reset */
+       ret = acp6x_reset(base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+
+       writel(0x00, base + ACP_CONTROL);
+
+       /* power off */
+       ret = acp6x_power_off(base);
+       if (ret) {
+               pr_err("ACP power off failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rembrandt_audio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct acp_chip_info *chip;
+       struct acp_dev_data *adata;
+       struct resource *res;
+
+       chip = dev_get_platdata(&pdev->dev);
+       if (!chip || !chip->base) {
+               dev_err(&pdev->dev, "ACP chip data is NULL\n");
+               return -ENODEV;
+       }
+
+       if (chip->acp_rev != ACP6X_DEV) {
+               dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
+               return -ENODEV;
+       }
+
+       rmb_acp_init(chip->base);
+
+       adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
+       if (!adata)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
+               return -ENODEV;
+       }
+
+       adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!adata->acp_base)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+               return -ENODEV;
+       }
+
+       adata->i2s_irq = res->start;
+       adata->dev = dev;
+       adata->dai_driver = acp_rmb_dai;
+       adata->num_dai = ARRAY_SIZE(acp_rmb_dai);
+       adata->rsrc = &rsrc;
+
+       adata->machines = snd_soc_acpi_amd_rmb_acp_machines;
+       acp_machine_select(adata);
+
+       dev_set_drvdata(dev, adata);
+       acp6x_enable_interrupts(adata);
+       acp_platform_register(dev);
+
+       return 0;
+}
+
+static int rembrandt_audio_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_chip_info *chip;
+
+       chip = dev_get_platdata(&pdev->dev);
+       if (!chip || !chip->base) {
+               dev_err(&pdev->dev, "ACP chip data is NULL\n");
+               return -ENODEV;
+       }
+
+       rmb_acp_deinit(chip->base);
+
+       acp6x_disable_interrupts(adata);
+       acp_platform_unregister(dev);
+       return 0;
+}
+
+static struct platform_driver rembrandt_driver = {
+       .probe = rembrandt_audio_probe,
+       .remove = rembrandt_audio_remove,
+       .driver = {
+               .name = "acp_asoc_rembrandt",
+       },
+};
+
+module_platform_driver(rembrandt_driver);
+
+MODULE_DESCRIPTION("AMD ACP Rembrandt Driver");
+MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 75c9229ece97aa86baa1a6a5891641f3e7e14686..2a89a0d2e60192cd246db90711186eee63859f30 100644 (file)
 #define ACP_ERROR_MASK 0x20000000
 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
 
+static struct acp_resource rsrc = {
+       .offset = 20,
+       .no_of_ctrls = 1,
+       .irqp_used = 0,
+       .irq_reg_offset = 0x1800,
+       .i2s_pin_cfg_offset = 0x1400,
+       .i2s_mode = 0x04,
+       .scratch_reg_offset = 0x12800,
+       .sram_pte_offset = 0x02052800,
+};
+
 static struct snd_soc_acpi_codecs amp_rt1019 = {
        .num_codecs = 1,
        .codecs = {"10EC1019"}
@@ -186,20 +197,24 @@ static int acp3x_reset(void __iomem *base)
        return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
 }
 
-static void acp3x_enable_interrupts(void __iomem *base)
+static void acp3x_enable_interrupts(struct acp_dev_data *adata)
 {
+       struct acp_resource *rsrc = adata->rsrc;
        u32 ext_intr_ctrl;
 
-       writel(0x01, base + ACP_EXTERNAL_INTR_ENB);
-       ext_intr_ctrl = readl(base + ACP_EXTERNAL_INTR_CNTL);
+       writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));
+       ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
        ext_intr_ctrl |= ACP_ERROR_MASK;
-       writel(ext_intr_ctrl, base + ACP_EXTERNAL_INTR_CNTL);
+       writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
 }
 
-static void acp3x_disable_interrupts(void __iomem *base)
+static void acp3x_disable_interrupts(struct acp_dev_data *adata)
 {
-       writel(ACP_EXT_INTR_STAT_CLEAR_MASK, base + ACP_EXTERNAL_INTR_STAT);
-       writel(0x00, base + ACP_EXTERNAL_INTR_ENB);
+       struct acp_resource *rsrc = adata->rsrc;
+
+       writel(ACP_EXT_INTR_STAT_CLEAR_MASK,
+              ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
+       writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));
 }
 
 static int rn_acp_init(void __iomem *base)
@@ -218,8 +233,6 @@ static int rn_acp_init(void __iomem *base)
        if (ret)
                return ret;
 
-       acp3x_enable_interrupts(base);
-
        return 0;
 }
 
@@ -227,8 +240,6 @@ static int rn_acp_deinit(void __iomem *base)
 {
        int ret = 0;
 
-       acp3x_disable_interrupts(base);
-
        /* Reset */
        ret = acp3x_reset(base);
        if (ret)
@@ -290,11 +301,13 @@ static int renoir_audio_probe(struct platform_device *pdev)
        adata->dev = dev;
        adata->dai_driver = acp_renoir_dai;
        adata->num_dai = ARRAY_SIZE(acp_renoir_dai);
+       adata->rsrc = &rsrc;
 
        adata->machines = snd_soc_acpi_amd_acp_machines;
        acp_machine_select(adata);
 
        dev_set_drvdata(dev, adata);
+       acp3x_enable_interrupts(adata);
        acp_platform_register(dev);
 
        return 0;
@@ -303,20 +316,17 @@ static int renoir_audio_probe(struct platform_device *pdev)
 static int renoir_audio_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
        struct acp_chip_info *chip;
        int ret;
 
        chip = dev_get_platdata(&pdev->dev);
-       if (!chip || !chip->base) {
-               dev_err(&pdev->dev, "ACP chip data is NULL\n");
-               return -ENODEV;
-       }
+
+       acp3x_disable_interrupts(adata);
 
        ret = rn_acp_deinit(chip->base);
-       if (ret) {
-               dev_err(&pdev->dev, "ACP de-init Failed\n");
-               return -EINVAL;
-       }
+       if (ret)
+               dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret));
 
        acp_platform_unregister(dev);
        return 0;
index d1531cdab11028ccf70348045e3061e484712e5c..f19f064a752728aaddd7ad8baa0f32f945adc0a3 100644 (file)
@@ -56,6 +56,26 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
        .dmic_codec_id = DMIC,
 };
 
+static struct acp_card_drvdata sof_nau8825_data = {
+       .hs_cpu_id = I2S_HS,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = DMIC,
+       .hs_codec_id = NAU8825,
+       .amp_codec_id = MAX98360A,
+       .dmic_codec_id = DMIC,
+       .soc_mclk = true,
+};
+
+static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
+       .hs_cpu_id = I2S_HS,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = DMIC,
+       .hs_codec_id = RT5682S,
+       .amp_codec_id = RT1019,
+       .dmic_codec_id = DMIC,
+       .soc_mclk = true,
+};
+
 static const struct snd_kcontrol_new acp_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -124,6 +144,14 @@ static const struct platform_device_id board_ids[] = {
                .name = "rt5682s-rt1019",
                .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data
        },
+       {
+               .name = "nau8825-max",
+               .driver_data = (kernel_ulong_t)&sof_nau8825_data
+       },
+       {
+               .name = "rt5682s-hs-rt1019",
+               .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
+       },
        { }
 };
 static struct platform_driver acp_asoc_audio = {
@@ -143,4 +171,6 @@ MODULE_ALIAS("platform:rt5682-rt1019");
 MODULE_ALIAS("platform:rt5682-max");
 MODULE_ALIAS("platform:rt5682s-max");
 MODULE_ALIAS("platform:rt5682s-rt1019");
+MODULE_ALIAS("platform:nau8825-max");
+MODULE_ALIAS("platform:rt5682s-hs-rt1019");
 MODULE_LICENSE("GPL v2");
index 8fd38bf4d3bd60d16332288505a289c4d9af66af..af9603724a68c5d81c4d9634df29cd534c4db746 100644 (file)
 #include "chip_offset_byte.h"
 
 #define ACP3X_DEV                      3
+#define ACP6X_DEV                      6
 
 #define I2S_SP_INSTANCE                        0x00
 #define I2S_BT_INSTANCE                        0x01
 #define DMIC_INSTANCE                  0x02
+#define I2S_HS_INSTANCE                        0x03
 
 #define MEM_WINDOW_START               0x4080000
 
 #define ACP3x_I2STDM_REG_END           0x1242410
 #define ACP3x_BT_TDM_REG_START         0x1242800
 #define ACP3x_BT_TDM_REG_END           0x1242810
-#define I2S_MODE                       0x04
-#define I2S_RX_THRESHOLD               27
-#define I2S_TX_THRESHOLD               28
-#define BT_TX_THRESHOLD                        26
-#define BT_RX_THRESHOLD                        25
 
-#define ACP_SRAM_PTE_OFFSET            0x02052800
+#define THRESHOLD(bit, base)   ((bit) + (base))
+#define I2S_RX_THRESHOLD(base) THRESHOLD(7, base)
+#define I2S_TX_THRESHOLD(base) THRESHOLD(8, base)
+#define BT_TX_THRESHOLD(base)  THRESHOLD(6, base)
+#define BT_RX_THRESHOLD(base)  THRESHOLD(5, base)
+#define HS_TX_THRESHOLD(base)  THRESHOLD(4, base)
+#define HS_RX_THRESHOLD(base)  THRESHOLD(3, base)
 
 #define ACP_SRAM_SP_PB_PTE_OFFSET      0x0
 #define ACP_SRAM_SP_CP_PTE_OFFSET      0x100
 #define ACP_SRAM_BT_PB_PTE_OFFSET      0x200
 #define ACP_SRAM_BT_CP_PTE_OFFSET      0x300
 #define ACP_SRAM_PDM_PTE_OFFSET                0x400
+#define ACP_SRAM_HS_PB_PTE_OFFSET       0x500
+#define ACP_SRAM_HS_CP_PTE_OFFSET       0x600
 #define PAGE_SIZE_4K_ENABLE            0x2
 
 #define I2S_SP_TX_MEM_WINDOW_START     0x4000000
 #define I2S_SP_RX_MEM_WINDOW_START     0x4020000
 #define I2S_BT_TX_MEM_WINDOW_START     0x4040000
 #define I2S_BT_RX_MEM_WINDOW_START     0x4060000
+#define I2S_HS_TX_MEM_WINDOW_START      0x40A0000
+#define I2S_HS_RX_MEM_WINDOW_START      0x40C0000
 
 #define SP_PB_FIFO_ADDR_OFFSET         0x500
 #define SP_CAPT_FIFO_ADDR_OFFSET       0x700
 #define BT_PB_FIFO_ADDR_OFFSET         0x900
 #define BT_CAPT_FIFO_ADDR_OFFSET       0xB00
+#define HS_PB_FIFO_ADDR_OFFSET         0xD00
+#define HS_CAPT_FIFO_ADDR_OFFSET       0xF00
 #define PLAYBACK_MIN_NUM_PERIODS       2
 #define PLAYBACK_MAX_NUM_PERIODS       8
 #define PLAYBACK_MAX_PERIOD_SIZE       8192
@@ -73,7 +82,7 @@
 
 #define ACP3x_ITER_IRER_SAMP_LEN_MASK  0x38
 
-#define ACP_MAX_STREAM                 6
+#define ACP_MAX_STREAM                 8
 
 struct acp_chip_info {
        char *name;             /* Platform name */
@@ -92,6 +101,18 @@ struct acp_stream {
        u32 fifo_offset;
 };
 
+struct acp_resource {
+       int offset;
+       int no_of_ctrls;
+       int irqp_used;
+       bool soc_mclk;
+       u32 irq_reg_offset;
+       u32 i2s_pin_cfg_offset;
+       int i2s_mode;
+       u64 scratch_reg_offset;
+       u64 sram_pte_offset;
+};
+
 struct acp_dev_data {
        char *name;
        struct device *dev;
@@ -106,6 +127,22 @@ struct acp_dev_data {
 
        struct snd_soc_acpi_mach *machines;
        struct platform_device *mach_dev;
+
+       u32 bclk_div;
+       u32 lrclk_div;
+
+       struct acp_resource *rsrc;
+};
+
+union acp_i2stdm_mstrclkgen {
+       struct {
+               u32 i2stdm_master_mode : 1;
+               u32 i2stdm_format_mode : 1;
+               u32 i2stdm_lrclk_div_val : 9;
+               u32 i2stdm_bclk_div_val : 11;
+               u32:10;
+       } bitfields, bits;
+       u32  u32_all;
 };
 
 extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
@@ -134,6 +171,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
                        high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH);
                        low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
                        break;
+               case I2S_HS_INSTANCE:
+                       high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH);
+                       low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW);
+                       break;
                default:
                        dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
                        return -EINVAL;
@@ -148,6 +189,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
                        high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
                        low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
                        break;
+               case I2S_HS_INSTANCE:
+                       high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH);
+                       low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW);
+                       break;
                case DMIC_INSTANCE:
                        high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
                        low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
@@ -163,4 +208,31 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
        return byte_count;
 }
 
+static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
+{
+       union acp_i2stdm_mstrclkgen mclkgen;
+       u32 master_reg;
+
+       switch (dai_id) {
+       case I2S_SP_INSTANCE:
+               master_reg = ACP_I2STDM0_MSTRCLKGEN;
+               break;
+       case I2S_BT_INSTANCE:
+               master_reg = ACP_I2STDM1_MSTRCLKGEN;
+               break;
+       case I2S_HS_INSTANCE:
+               master_reg = ACP_I2STDM2_MSTRCLKGEN;
+               break;
+       default:
+               master_reg = ACP_I2STDM0_MSTRCLKGEN;
+               break;
+       }
+
+       mclkgen.bits.i2stdm_master_mode = 0x1;
+       mclkgen.bits.i2stdm_format_mode = 0x00;
+
+       mclkgen.bits.i2stdm_bclk_div_val = adata->bclk_div;
+       mclkgen.bits.i2stdm_lrclk_div_val = adata->lrclk_div;
+       writel(mclkgen.u32_all, adata->acp_base + master_reg);
+}
 #endif
index 88f6fa597cd6b2d366e6c7996448e670d9ebb237..ce3948e0679c564801325a7b69eb69c69e88fcde 100644 (file)
 #define ACP_SOFT_RESET                          0x1000
 #define ACP_CONTROL                             0x1004
 
-#define ACP_EXTERNAL_INTR_ENB                         0x1800
-#define ACP_EXTERNAL_INTR_CNTL                        0x1804
-#define ACP_EXTERNAL_INTR_STAT                        0x1808
-#define ACP_I2S_PIN_CONFIG                            0x1400
-#define ACP_SCRATCH_REG_0                             0x12800
+#define ACP_EXTERNAL_INTR_REG_ADDR(adata, offset, ctrl) \
+       (adata->acp_base + adata->rsrc->irq_reg_offset + offset + (ctrl * 0x04))
+
+#define ACP_EXTERNAL_INTR_ENB(adata) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x0, 0x0)
+#define ACP_EXTERNAL_INTR_CNTL(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x4, ctrl)
+#define ACP_EXTERNAL_INTR_STAT(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, \
+       (0x4 + (adata->rsrc->no_of_ctrls * 0x04)), ctrl)
 
 /* Registers from ACP_AUDIO_BUFFERS block */
 
 #define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH             0x2084
 #define ACP_BT_TX_LINEARPOSITIONCNTR_LOW              0x2088
 #define ACP_BT_TX_INTR_WATERMARK_SIZE                 0x208C
+#define ACP_HS_RX_RINGBUFADDR                        0x3A90
+#define ACP_HS_RX_RINGBUFSIZE                        0x3A94
+#define ACP_HS_RX_LINKPOSITIONCNTR                   0x3A98
+#define ACP_HS_RX_FIFOADDR                           0x3A9C
+#define ACP_HS_RX_FIFOSIZE                           0x3AA0
+#define ACP_HS_RX_DMA_SIZE                           0x3AA4
+#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH            0x3AA8
+#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW             0x3AAC
+#define ACP_HS_RX_INTR_WATERMARK_SIZE                0x3AB0
+#define ACP_HS_TX_RINGBUFADDR                        0x3AB4
+#define ACP_HS_TX_RINGBUFSIZE                        0x3AB8
+#define ACP_HS_TX_LINKPOSITIONCNTR                   0x3ABC
+#define ACP_HS_TX_FIFOADDR                           0x3AC0
+#define ACP_HS_TX_FIFOSIZE                           0x3AC4
+#define ACP_HS_TX_DMA_SIZE                           0x3AC8
+#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH            0x3ACC
+#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW             0x3AD0
+#define ACP_HS_TX_INTR_WATERMARK_SIZE                0x3AD4
 
 #define ACP_I2STDM_IER                                0x2400
 #define ACP_I2STDM_IRER                               0x2404
 #define ACP_BTTDM_ITER                                0x280C
 #define ACP_BTTDM_TXFRMT                              0x2810
 
+/* Registers from ACP_HS_TDM block */
+#define ACP_HSTDM_IER                                 0x2814
+#define ACP_HSTDM_IRER                                0x2818
+#define ACP_HSTDM_RXFRMT                              0x281C
+#define ACP_HSTDM_ITER                                0x2820
+#define ACP_HSTDM_TXFRMT                              0x2824
+
 /* Registers from ACP_WOV_PDM block */
 
 #define ACP_WOV_PDM_ENABLE                            0x2C04
 #define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN             0x2C64
 #define ACP_WOV_ERROR_STATUS_REGISTER                 0x2C68
 
+#define ACP_I2STDM0_MSTRCLKGEN                       0x2414
+#define ACP_I2STDM1_MSTRCLKGEN                       0x2418
+#define ACP_I2STDM2_MSTRCLKGEN                       0x241C
 #endif
index 0a54567a28415e29b6e961784c1bd83512d74696..7b4c625da40d8e9441b0f806f80ceff16e405486 100644 (file)
@@ -19,6 +19,7 @@
 #define ACP_PCI_DEV_ID                 0x15E2
 
 extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[];
 
 struct config_entry {
        u32 flags;
index de6f70d7ef3642e942c40dba496d97ec9c159e4a..aa38cef1776dae3136eb29fc85922dda377b65ca 100644 (file)
@@ -257,7 +257,8 @@ static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
 };
 
 static const struct snd_soc_component_driver acp3x_dai_component = {
-       .name           = DRV_NAME,
+       .name                   = DRV_NAME,
+       .legacy_dai_naming      = 1,
 };
 
 static struct snd_soc_dai_driver acp3x_i2s_dai = {
index 8c42345ee41e9f92a33d7ba697f709765e9eec99..7203c6488df0eb9d5a85a745e6bacb5f4391f2b9 100644 (file)
@@ -363,12 +363,13 @@ static struct snd_soc_dai_driver acp_pdm_dai_driver = {
 };
 
 static const struct snd_soc_component_driver acp_pdm_component = {
-       .name           = DRV_NAME,
-       .open           = acp_pdm_dma_open,
-       .close          = acp_pdm_dma_close,
-       .hw_params      = acp_pdm_dma_hw_params,
-       .pointer        = acp_pdm_dma_pointer,
-       .pcm_construct  = acp_pdm_dma_new,
+       .name                   = DRV_NAME,
+       .open                   = acp_pdm_dma_open,
+       .close                  = acp_pdm_dma_close,
+       .hw_params              = acp_pdm_dma_hw_params,
+       .pointer                = acp_pdm_dma_pointer,
+       .pcm_construct          = acp_pdm_dma_new,
+       .legacy_dai_naming      = 1,
 };
 
 static int acp_pdm_audio_probe(struct platform_device *pdev)
diff --git a/sound/soc/amd/rpl/Makefile b/sound/soc/amd/rpl/Makefile
new file mode 100644 (file)
index 0000000..11a33a0
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+# RPL platform Support
+snd-rpl-pci-acp6x-objs := rpl-pci-acp6x.o
+
+obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += snd-rpl-pci-acp6x.o
diff --git a/sound/soc/amd/rpl/rpl-pci-acp6x.c b/sound/soc/amd/rpl/rpl-pci-acp6x.c
new file mode 100644 (file)
index 0000000..a8e548e
--- /dev/null
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AMD RPL ACP PCI Driver
+ *
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "rpl_acp6x.h"
+
+struct rpl_dev_data {
+       void __iomem *acp6x_base;
+};
+
+static int rpl_power_on(void __iomem *acp_base)
+{
+       u32 val;
+       int timeout;
+
+       val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
+
+       if (!val)
+               return val;
+
+       if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
+               rpl_acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS);
+               if (!val)
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int rpl_reset(void __iomem *acp_base)
+{
+       u32 val;
+       int timeout;
+
+       rpl_acp_writel(1, acp_base + ACP_SOFT_RESET);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
+               if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
+                       break;
+               cpu_relax();
+       }
+       rpl_acp_writel(0, acp_base + ACP_SOFT_RESET);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = rpl_acp_readl(acp_base + ACP_SOFT_RESET);
+               if (!val)
+                       return 0;
+               cpu_relax();
+       }
+       return -ETIMEDOUT;
+}
+
+static int rpl_init(void __iomem *acp_base)
+{
+       int ret;
+
+       /* power on */
+       ret = rpl_power_on(acp_base);
+       if (ret) {
+               pr_err("ACP power on failed\n");
+               return ret;
+       }
+       rpl_acp_writel(0x01, acp_base + ACP_CONTROL);
+       /* Reset */
+       ret = rpl_reset(acp_base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+       rpl_acp_writel(0x03, acp_base + ACP_CLKMUX_SEL);
+       return 0;
+}
+
+static int rpl_deinit(void __iomem *acp_base)
+{
+       int ret;
+
+       /* Reset */
+       ret = rpl_reset(acp_base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+       rpl_acp_writel(0x00, acp_base + ACP_CLKMUX_SEL);
+       rpl_acp_writel(0x00, acp_base + ACP_CONTROL);
+       return 0;
+}
+
+static int snd_rpl_probe(struct pci_dev *pci,
+                        const struct pci_device_id *pci_id)
+{
+       struct rpl_dev_data *adata;
+       u32 addr;
+       int ret;
+
+       /* RPL device check */
+       switch (pci->revision) {
+       case 0x62:
+               break;
+       default:
+               dev_dbg(&pci->dev, "acp6x pci device not found\n");
+               return -ENODEV;
+       }
+       if (pci_enable_device(pci)) {
+               dev_err(&pci->dev, "pci_enable_device failed\n");
+               return -ENODEV;
+       }
+
+       ret = pci_request_regions(pci, "AMD ACP6x audio");
+       if (ret < 0) {
+               dev_err(&pci->dev, "pci_request_regions failed\n");
+               goto disable_pci;
+       }
+
+       adata = devm_kzalloc(&pci->dev, sizeof(struct rpl_dev_data),
+                            GFP_KERNEL);
+       if (!adata) {
+               ret = -ENOMEM;
+               goto release_regions;
+       }
+
+       addr = pci_resource_start(pci, 0);
+       adata->acp6x_base = devm_ioremap(&pci->dev, addr,
+                                        pci_resource_len(pci, 0));
+       if (!adata->acp6x_base) {
+               ret = -ENOMEM;
+               goto release_regions;
+       }
+       pci_set_master(pci);
+       pci_set_drvdata(pci, adata);
+       ret = rpl_init(adata->acp6x_base);
+       if (ret)
+               goto release_regions;
+       pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
+       pm_runtime_use_autosuspend(&pci->dev);
+       pm_runtime_put_noidle(&pci->dev);
+       pm_runtime_allow(&pci->dev);
+
+       return 0;
+release_regions:
+       pci_release_regions(pci);
+disable_pci:
+       pci_disable_device(pci);
+
+       return ret;
+}
+
+static int __maybe_unused snd_rpl_suspend(struct device *dev)
+{
+       struct rpl_dev_data *adata;
+       int ret;
+
+       adata = dev_get_drvdata(dev);
+       ret = rpl_deinit(adata->acp6x_base);
+       if (ret)
+               dev_err(dev, "ACP de-init failed\n");
+       return ret;
+}
+
+static int __maybe_unused snd_rpl_resume(struct device *dev)
+{
+       struct rpl_dev_data *adata;
+       int ret;
+
+       adata = dev_get_drvdata(dev);
+       ret = rpl_init(adata->acp6x_base);
+       if (ret)
+               dev_err(dev, "ACP init failed\n");
+       return ret;
+}
+
+static const struct dev_pm_ops rpl_pm = {
+       SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume)
+};
+
+static void snd_rpl_remove(struct pci_dev *pci)
+{
+       struct rpl_dev_data *adata;
+       int ret;
+
+       adata = pci_get_drvdata(pci);
+       ret = rpl_deinit(adata->acp6x_base);
+       if (ret)
+               dev_err(&pci->dev, "ACP de-init failed\n");
+       pm_runtime_forbid(&pci->dev);
+       pm_runtime_get_noresume(&pci->dev);
+       pci_release_regions(pci);
+       pci_disable_device(pci);
+}
+
+static const struct pci_device_id snd_rpl_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
+       .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
+       .class_mask = 0xffffff },
+       { 0, },
+};
+MODULE_DEVICE_TABLE(pci, snd_rpl_ids);
+
+static struct pci_driver rpl_acp6x_driver  = {
+       .name = KBUILD_MODNAME,
+       .id_table = snd_rpl_ids,
+       .probe = snd_rpl_probe,
+       .remove = snd_rpl_remove,
+       .driver = {
+               .pm = &rpl_pm,
+       }
+};
+
+module_pci_driver(rpl_acp6x_driver);
+
+MODULE_DESCRIPTION("AMD ACP RPL PCI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/rpl/rpl_acp6x.h b/sound/soc/amd/rpl/rpl_acp6x.h
new file mode 100644 (file)
index 0000000..f5816a3
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ACP Driver
+ *
+ * Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ */
+
+#include "rpl_acp6x_chip_offset_byte.h"
+
+#define ACP_DEVICE_ID 0x15E2
+#define ACP6x_PHY_BASE_ADDRESS 0x1240000
+
+#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK   0x00010001
+#define ACP_PGFSM_CNTL_POWER_ON_MASK    1
+#define ACP_PGFSM_CNTL_POWER_OFF_MASK   0
+#define ACP_PGFSM_STATUS_MASK           3
+#define ACP_POWERED_ON                  0
+#define ACP_POWER_ON_IN_PROGRESS        1
+#define ACP_POWERED_OFF                 2
+#define ACP_POWER_OFF_IN_PROGRESS       3
+
+#define DELAY_US        5
+#define ACP_COUNTER     20000
+
+/* time in ms for runtime suspend delay */
+#define ACP_SUSPEND_DELAY_MS    2000
+
+static inline u32 rpl_acp_readl(void __iomem *base_addr)
+{
+       return readl(base_addr - ACP6x_PHY_BASE_ADDRESS);
+}
+
+static inline void rpl_acp_writel(u32 val, void __iomem *base_addr)
+{
+       writel(val, base_addr - ACP6x_PHY_BASE_ADDRESS);
+}
diff --git a/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h b/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h
new file mode 100644 (file)
index 0000000..456498f
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * AMD ACP 6.2 Register Documentation
+ *
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _rpl_acp6x_OFFSET_HEADER
+#define _rpl_acp6x_OFFSET_HEADER
+
+/* Registers from ACP_CLKRST block */
+#define ACP_SOFT_RESET                                0x1241000
+#define ACP_CONTROL                                   0x1241004
+#define ACP_STATUS                                    0x1241008
+#define ACP_DYNAMIC_CG_MASTER_CONTROL                 0x1241010
+#define ACP_PGFSM_CONTROL                             0x124101C
+#define ACP_PGFSM_STATUS                              0x1241020
+#define ACP_CLKMUX_SEL                                0x1241024
+
+/* Registers from ACP_AON block */
+#define ACP_PME_EN                                    0x1241400
+#define ACP_DEVICE_STATE                              0x1241404
+#define AZ_DEVICE_STATE                               0x1241408
+#define ACP_PIN_CONFIG                                0x1241440
+#define ACP_PAD_PULLUP_CTRL                           0x1241444
+#define ACP_PAD_PULLDOWN_CTRL                         0x1241448
+#define ACP_PAD_DRIVE_STRENGTH_CTRL                   0x124144C
+#define ACP_PAD_SCHMEN_CTRL                           0x1241450
+
+#endif
index 59a98f89a669a7c840f31e66c5eebf79b82089d7..773e96f1b4dd6e47934e776c96988bd1bca19030 100644 (file)
@@ -37,10 +37,10 @@ static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        }
        mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
        switch (mode) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                adata->master_mode = I2S_MASTER_MODE_ENABLE;
                break;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                adata->master_mode = I2S_MASTER_MODE_DISABLE;
                break;
        }
@@ -345,6 +345,7 @@ static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = {
 
 static const struct snd_soc_component_driver acp5x_dai_component = {
        .name = "acp5x-i2s",
+       .legacy_dai_naming = 1,
 };
 
 static struct snd_soc_dai_driver acp5x_i2s_dai = {
index 727de46860b19329991088568ca6b4e5c0923aec..af3737ef970768976a2ab0c8f480b7bac4665f0f 100644 (file)
@@ -178,8 +178,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
        ret = 0;
        for (i = 0; i < num_codecs; i++) {
                codec_dai = asoc_rtd_to_codec(rtd, i);
-               if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) ||
-                   (strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) {
+               if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) {
                        switch (params_rate(params)) {
                        case 48000:
                                bclk_val = 1536000;
index f06e6c1a77992c49bb518add20b66f8cf7beec86..ecfe7a7907901533042b410378353fdf5264fa5d 100644 (file)
@@ -105,28 +105,14 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                .driver_data = &acp6x_card,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21AW"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21CM"),
                }
        },
        {
                .driver_data = &acp6x_card,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21AX"),
-               }
-       },
-       {
-               .driver_data = &acp6x_card,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21BN"),
-               }
-       },
-       {
-               .driver_data = &acp6x_card,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21BQ"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21CN"),
                }
        },
        {
@@ -157,20 +143,6 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "21CL"),
                }
        },
-       {
-               .driver_data = &acp6x_card,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21D8"),
-               }
-       },
-       {
-               .driver_data = &acp6x_card,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21D9"),
-               }
-       },
        {}
 };
 
index 7e66393e41535395506c0291f8744f5aee80dc01..acecd6a4ec4b1611a05fcf0a5bb47e09f0687ff1 100644 (file)
@@ -335,12 +335,13 @@ static struct snd_soc_dai_driver acp6x_pdm_dai_driver = {
 };
 
 static const struct snd_soc_component_driver acp6x_pdm_component = {
-       .name           = DRV_NAME,
-       .open           = acp6x_pdm_dma_open,
-       .close          = acp6x_pdm_dma_close,
-       .hw_params      = acp6x_pdm_dma_hw_params,
-       .pointer        = acp6x_pdm_dma_pointer,
-       .pcm_construct  = acp6x_pdm_dma_new,
+       .name                   = DRV_NAME,
+       .open                   = acp6x_pdm_dma_open,
+       .close                  = acp6x_pdm_dma_close,
+       .hw_params              = acp6x_pdm_dma_hw_params,
+       .pointer                = acp6x_pdm_dma_pointer,
+       .pcm_construct          = acp6x_pdm_dma_new,
+       .legacy_dai_naming      = 1,
 };
 
 static int acp6x_pdm_audio_probe(struct platform_device *pdev)
index 20f7a99783f20ee8048de546c993e9335952e294..77c5fa1f7af14036e5d56c5c5eae1585ac6e2408 100644 (file)
@@ -159,7 +159,7 @@ static int snd_acp6x_probe(struct pci_dev *pci,
        case 0x6f:
                break;
        default:
-               dev_err(&pci->dev, "acp6x pci device not found\n");
+               dev_dbg(&pci->dev, "acp6x pci device not found\n");
                return -ENODEV;
        }
        if (pci_enable_device(pci)) {
index 74b7b2611aa70988e286baee520060e23f6c7758..87d6d6ed026b321fd0c90bd9c0a5560074f9056a 100644 (file)
@@ -458,6 +458,7 @@ static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = {
        .num_controls           = ARRAY_SIZE(atmel_classd_snd_controls),
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
+       .legacy_dai_naming      = 1,
 };
 
 /* ASoC sound card */
index 1934767690b511f71f32ed53d84ff0ffc6539ddb..425d66edbf8671fd6713c5b21f5cea20c2576514 100644 (file)
@@ -343,7 +343,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
        }
 
        switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                /* codec is slave, so cpu is master */
                mr |= ATMEL_I2SC_MR_MODE_MASTER;
                ret = atmel_i2s_get_gck_param(dev, params_rate(params));
@@ -351,7 +351,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
                        return ret;
                break;
 
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                /* codec is master, so cpu is slave */
                mr |= ATMEL_I2SC_MR_MODE_SLAVE;
                dev->gck_param = NULL;
@@ -564,7 +564,8 @@ static struct snd_soc_dai_driver atmel_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver atmel_i2s_component = {
-       .name   = "atmel-i2s",
+       .name                   = "atmel-i2s",
+       .legacy_dai_naming      = 1,
 };
 
 static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
index ea34efac2fff5133a6d36c44711f2f9619fbe5ad..77ff12baead5bcef7970a167f03fa4ed1f4f145c 100644 (file)
@@ -481,6 +481,7 @@ static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = {
        .num_controls           = ARRAY_SIZE(atmel_pdmic_snd_controls),
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
+       .legacy_dai_naming      = 1,
 };
 
 /* ASoC sound card */
index c1dea8d624164f3e323237e0ab767174a0ef5e9f..e868b7e028d6cee698dfde1264a6cf8317652103 100644 (file)
@@ -210,7 +210,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
                return frame_size;
 
        switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BC_FP:
                if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
                    && ssc->clk_from_rk_pin)
                        /* Receiver Frame Synchro (i.e. capture)
@@ -220,7 +220,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
                        mck_div = 3;
                break;
 
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
                    && !ssc->clk_from_rk_pin)
                        /* Transmit Frame Synchro (i.e. playback)
@@ -233,7 +233,7 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
        }
 
        switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                r.num = ssc_p->mck_rate / mck_div / frame_size;
 
                ret = snd_interval_ratnum(i, 1, &r, &num, &den);
@@ -243,8 +243,8 @@ static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
                }
                break;
 
-       case SND_SOC_DAIFMT_CBP_CFC:
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FP:
+       case SND_SOC_DAIFMT_BC_FC:
                t.min = 8000;
                t.max = ssc_p->mck_rate / mck_div / frame_size;
                t.openmin = t.openmax = 0;
@@ -433,8 +433,8 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
 {
        switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFC:
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BC_FP:
+       case SND_SOC_DAIFMT_BP_FP:
                return 1;
        }
        return 0;
@@ -444,8 +444,8 @@ static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
 static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p)
 {
        switch (ssc_p->daifmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFP:
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FC:
+       case SND_SOC_DAIFMT_BP_FP:
                return 1;
        }
        return 0;
@@ -762,7 +762,6 @@ static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int atmel_ssc_suspend(struct snd_soc_component *component)
 {
        struct atmel_ssc_info *ssc_p;
@@ -821,10 +820,6 @@ static int atmel_ssc_resume(struct snd_soc_component *component)
 
        return 0;
 }
-#else /* CONFIG_PM */
-#  define atmel_ssc_suspend    NULL
-#  define atmel_ssc_resume     NULL
-#endif /* CONFIG_PM */
 
 #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
                          SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -858,9 +853,10 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
 };
 
 static const struct snd_soc_component_driver atmel_ssc_component = {
-       .name           = "atmel-ssc",
-       .suspend        = atmel_ssc_suspend,
-       .resume         = atmel_ssc_resume,
+       .name                   = "atmel-ssc",
+       .suspend                = pm_ptr(atmel_ssc_suspend),
+       .resume                 = pm_ptr(atmel_ssc_resume),
+       .legacy_dai_naming      = 1,
 };
 
 static int asoc_ssc_init(struct device *dev)
index 6d1227a1d67b517b7800f2f051752ac29c309225..6dfb96c576ff36747fc2ae991f3407cb2827ba17 100644 (file)
@@ -350,7 +350,7 @@ static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
 
        /* We can't generate only FSYNC */
-       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFC)
+       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_BC_FP)
                return -EINVAL;
 
        /* We can only reconfigure the IP when it's stopped */
@@ -547,19 +547,19 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
        }
 
        switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                /* cpu is BCLK and LRC master */
                mra |= MCHP_I2SMCC_MRA_MODE_MASTER;
                if (dev->sysclk)
                        mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN;
                set_divs = 1;
                break;
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BP_FC:
                /* cpu is BCLK master */
                mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT;
                set_divs = 1;
                fallthrough;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                /* cpu is slave */
                mra |= MCHP_I2SMCC_MRA_MODE_SLAVE;
                if (dev->sysclk)
@@ -928,7 +928,8 @@ static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
 };
 
 static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
-       .name   = "mchp-i2s-mcc",
+       .name                   = "mchp-i2s-mcc",
+       .legacy_dai_naming      = 1,
 };
 
 #ifdef CONFIG_OF
index a3856c73e221497a2e403328d8f0f291ada01a4d..44aefbd5b62c71f8019aeabb6e89865cc296e6cd 100644 (file)
@@ -423,6 +423,7 @@ static const struct snd_soc_component_driver mchp_pdmc_dai_component = {
        .num_controls = ARRAY_SIZE(mchp_pdmc_snd_controls),
        .open = &mchp_pdmc_open,
        .close = &mchp_pdmc_close,
+       .legacy_dai_naming = 1,
 };
 
 static const unsigned int mchp_pdmc_1mic[] = {1};
@@ -492,8 +493,8 @@ static int mchp_pdmc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        unsigned int fmt_format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
        /* IP needs to be bitclock master */
-       if (fmt_master != SND_SOC_DAIFMT_CBS_CFS &&
-           fmt_master != SND_SOC_DAIFMT_CBS_CFM)
+       if (fmt_master != SND_SOC_DAIFMT_BP_FP &&
+           fmt_master != SND_SOC_DAIFMT_BP_FC)
                return -EINVAL;
 
        /* IP supports only PDM interface */
@@ -984,7 +985,7 @@ static int mchp_pdmc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        dd->dev = &pdev->dev;
-       ret =  mchp_pdmc_dt_init(dd);
+       ret = mchp_pdmc_dt_init(dd);
        if (ret < 0)
                return ret;
 
index 5fc968483f2c812f8273d35db43c0cd72bda0b5c..ec0705cc40fab825c4054b5eea012a7841e6551f 100644 (file)
@@ -221,11 +221,11 @@ struct mchp_spdifrx_user_data {
 };
 
 struct mchp_spdifrx_mixer_control {
-               struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS];
-               struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS];
-               bool ulock;
-               bool badf;
-               bool signal;
+       struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS];
+       struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS];
+       bool ulock;
+       bool badf;
+       bool signal;
 };
 
 struct mchp_spdifrx_dev {
@@ -288,15 +288,17 @@ static void mchp_spdifrx_isr_blockend_en(struct mchp_spdifrx_dev *dev)
        spin_unlock_irqrestore(&dev->blockend_lock, flags);
 }
 
-/* called from atomic context only */
+/* called from atomic/non-atomic context */
 static void mchp_spdifrx_isr_blockend_dis(struct mchp_spdifrx_dev *dev)
 {
-       spin_lock(&dev->blockend_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->blockend_lock, flags);
        dev->blockend_refcount--;
        /* don't enable BLOCKEND interrupt if it's already enabled */
        if (dev->blockend_refcount == 0)
                regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND);
-       spin_unlock(&dev->blockend_lock);
+       spin_unlock_irqrestore(&dev->blockend_lock, flags);
 }
 
 static irqreturn_t mchp_spdif_interrupt(int irq, void *dev_id)
@@ -575,6 +577,7 @@ static int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev,
        if (ret <= 0) {
                dev_dbg(dev->dev, "user data for channel %d timeout\n",
                        channel);
+               mchp_spdifrx_isr_blockend_dis(dev);
                return ret;
        }
 
@@ -846,7 +849,8 @@ static struct snd_soc_dai_driver mchp_spdifrx_dai = {
 };
 
 static const struct snd_soc_component_driver mchp_spdifrx_component = {
-       .name           = "mchp-spdifrx",
+       .name                   = "mchp-spdifrx",
+       .legacy_dai_naming      = 1,
 };
 
 static const struct of_device_id mchp_spdifrx_dt_ids[] = {
index d24380046435296cd83a78e54fb0d055ef5d01ab..4850a177803dbee786c34a5aa93793cbc917d167 100644 (file)
@@ -196,7 +196,6 @@ struct mchp_spdiftx_dev {
        struct clk                              *pclk;
        struct clk                              *gclk;
        unsigned int                            fmt;
-       const struct mchp_i2s_caps              *caps;
        int                                     gclk_enabled:1;
 };
 
@@ -341,12 +340,10 @@ static int mchp_spdiftx_trigger(struct snd_pcm_substream *substream, int cmd,
 
        ret = regmap_write(dev->regmap, SPDIFTX_MR, mr);
        spin_unlock(&ctrl->lock);
-       if (ret) {
+       if (ret)
                dev_err(dev->dev, "unable to disable TX: %d\n", ret);
-               return ret;
-       }
 
-       return 0;
+       return ret;
 }
 
 static int mchp_spdiftx_hw_params(struct snd_pcm_substream *substream,
@@ -753,7 +750,8 @@ static struct snd_soc_dai_driver mchp_spdiftx_dai = {
 };
 
 static const struct snd_soc_component_driver mchp_spdiftx_component = {
-       .name           = "mchp-spdiftx",
+       .name                   = "mchp-spdiftx",
+       .legacy_dai_naming      = 1,
 };
 
 static const struct of_device_id mchp_spdiftx_dt_ids[] = {
@@ -762,12 +760,10 @@ static const struct of_device_id mchp_spdiftx_dt_ids[] = {
        },
        { /* sentinel */ }
 };
-
 MODULE_DEVICE_TABLE(of, mchp_spdiftx_dt_ids);
+
 static int mchp_spdiftx_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
-       const struct of_device_id *match;
        struct mchp_spdiftx_dev *dev;
        struct resource *mem;
        struct regmap *regmap;
@@ -781,11 +777,6 @@ static int mchp_spdiftx_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
 
-       /* Get hardware capabilities. */
-       match = of_match_node(mchp_spdiftx_dt_ids, np);
-       if (match)
-               dev->caps = match->data;
-
        /* Map I/O registers. */
        base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
        if (IS_ERR(base))
@@ -847,12 +838,10 @@ static int mchp_spdiftx_probe(struct platform_device *pdev)
        err = devm_snd_soc_register_component(&pdev->dev,
                                              &mchp_spdiftx_component,
                                              &mchp_spdiftx_dai, 1);
-       if (err) {
+       if (err)
                dev_err(&pdev->dev, "failed to register component: %d\n", err);
-               return err;
-       }
 
-       return 0;
+       return err;
 }
 
 static struct platform_driver mchp_spdiftx_driver = {
index ce46d8a0b7e43441720e6d5306e245c8edb2a01e..954460719aa3d0b8ad225fad0470ba3acad8033e 100644 (file)
@@ -157,7 +157,9 @@ put_codec_node:
 
 static int snd_proto_remove(struct platform_device *pdev)
 {
-       return snd_soc_unregister_card(&snd_proto);
+       snd_soc_unregister_card(&snd_proto);
+
+       return 0;
 }
 
 static const struct of_device_id snd_proto_of_match[] = {
index 3b1700e665f52a13fa3ce4ed8d2f615eb42d102e..b18512ca25781ab150f9f66a6a6a52a126100473 100644 (file)
@@ -223,7 +223,8 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = {
 };
 
 static const struct snd_soc_component_driver au1xac97c_component = {
-       .name           = "au1xac97c",
+       .name                   = "au1xac97c",
+       .legacy_dai_naming      = 1,
 };
 
 static int au1xac97c_drvprobe(struct platform_device *pdev)
index 740d4e052e4df93075f523c46f9a4fcdad7295cc..b15c8baa9ee454903017e9dfe3a05e83c2799ec4 100644 (file)
@@ -121,7 +121,7 @@ static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 
        /* I2S controller only supports provider */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:    /* CODEC consumer */
+       case SND_SOC_DAIFMT_BP_FP:      /* CODEC consumer */
                break;
        default:
                goto out;
@@ -227,7 +227,8 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
 };
 
 static const struct snd_soc_component_driver au1xi2s_component = {
-       .name           = "au1xi2s",
+       .name                   = "au1xi2s",
+       .legacy_dai_naming      = 1,
 };
 
 static int au1xi2s_drvprobe(struct platform_device *pdev)
index 05eb36991f147a8dcbeb631961e4e4b76a31c776..b536394b9ca08309f9c8391d67424107592741fe 100644 (file)
@@ -356,7 +356,8 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
 };
 
 static const struct snd_soc_component_driver au1xpsc_ac97_component = {
-       .name           = "au1xpsc-ac97",
+       .name                   = "au1xpsc-ac97",
+       .legacy_dai_naming      = 1,
 };
 
 static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
index b2b8896bb593c2b8bb8206e3e06e1d82e8750974..79b5ae4e494cb6410350cbc0e9331674193cbadc 100644 (file)
@@ -91,10 +91,10 @@ static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        }
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:    /* CODEC provider */
+       case SND_SOC_DAIFMT_BC_FC:      /* CODEC provider */
                ct |= PSC_I2SCFG_MS;    /* PSC I2S consumer mode */
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:    /* CODEC consumer */
+       case SND_SOC_DAIFMT_BP_FP:      /* CODEC consumer */
                ct &= ~PSC_I2SCFG_MS;   /* PSC I2S provider mode */
                break;
        default:
@@ -286,7 +286,8 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
 };
 
 static const struct snd_soc_component_driver au1xpsc_i2s_component = {
-       .name           = "au1xpsc-i2s",
+       .name                   = "au1xpsc-i2s",
+       .legacy_dai_naming      = 1,
 };
 
 static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
index e3fc4bee8cfdcbdea506bd1de6b01dfdab8d025d..f4d84774dac72851551456f2981f332ddbd0c1ff 100644 (file)
@@ -133,8 +133,8 @@ static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
                return;
 
        switch (provider) {
-       case SND_SOC_DAIFMT_CBC_CFC:
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_BP_FC:
                clk_prepare_enable(dev->clk);
                dev->clk_prepared = true;
                break;
@@ -385,12 +385,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
 
        /* Check if CPU is bit clock provider */
        switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_BP_FC:
                bit_clock_provider = true;
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FP:
+       case SND_SOC_DAIFMT_BC_FC:
                bit_clock_provider = false;
                break;
        default:
@@ -399,12 +399,12 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
 
        /* Check if CPU is frame sync provider */
        switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_BC_FP:
                frame_sync_provider = true;
                break;
-       case SND_SOC_DAIFMT_CBC_CFP:
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BP_FC:
+       case SND_SOC_DAIFMT_BC_FC:
                frame_sync_provider = false;
                break;
        default:
@@ -821,7 +821,8 @@ static const struct regmap_config bcm2835_regmap_config = {
 };
 
 static const struct snd_soc_component_driver bcm2835_i2s_component = {
-       .name           = "bcm2835-i2s-comp",
+       .name                   = "bcm2835-i2s-comp",
+       .legacy_dai_naming      = 1,
 };
 
 static int bcm2835_i2s_probe(struct platform_device *pdev)
index 527caf430715bc8c0a0b080d448eb26fcfa64c3f..2da1384ffe911a586d659eaa999c2a01d72ff961 100644 (file)
@@ -218,6 +218,7 @@ static struct snd_soc_dai_driver bcm63xx_i2s_dai = {
 
 static const struct snd_soc_component_driver bcm63xx_i2s_component = {
        .name = "bcm63xx",
+       .legacy_dai_naming = 1,
 };
 
 static int bcm63xx_i2s_dev_probe(struct platform_device *pdev)
index b0254e724ec97c72759961558b06c9787e65acad..2a92e33e1fbf1d0b22a59d353fe7312793139683 100644 (file)
@@ -839,11 +839,11 @@ static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        ssp_newcfg = 0;
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE);
                aio->is_slave = 1;
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE);
                aio->is_slave = 0;
                break;
@@ -1191,9 +1191,10 @@ static const struct snd_soc_dai_driver cygnus_spdif_dai_info = {
 static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS];
 
 static const struct snd_soc_component_driver cygnus_ssp_component = {
-       .name           = "cygnus-audio",
-       .suspend        = cygnus_ssp_suspend,
-       .resume         = cygnus_ssp_resume,
+       .name                   = "cygnus-audio",
+       .suspend                = cygnus_ssp_suspend,
+       .resume                 = cygnus_ssp_resume,
+       .legacy_dai_naming      = 1,
 };
 
 /*
index 16f9bb283b5cb2800c0ef5e7dd5c8342251df8f6..37593abe60532a63e55c3b2f08c285ba4b22a71f 100644 (file)
@@ -355,7 +355,8 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
 };
 
 static const struct snd_soc_component_driver ep93xx_ac97_component = {
-       .name           = "ep93xx-ac97",
+       .name                   = "ep93xx-ac97",
+       .legacy_dai_naming      = 1,
 };
 
 static int ep93xx_ac97_probe(struct platform_device *pdev)
index 2c8cd843d049cdb2a5d60d0ef68bf34a85e2f7ac..982151330c896a2c02481ab51a1dc6b1077d0879 100644 (file)
@@ -246,12 +246,12 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        }
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                /* CPU is provider */
                clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
                break;
 
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                /* Codec is provider */
                clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
                break;
@@ -422,9 +422,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver ep93xx_i2s_component = {
-       .name           = "ep93xx-i2s",
-       .suspend        = ep93xx_i2s_suspend,
-       .resume         = ep93xx_i2s_resume,
+       .name                   = "ep93xx-i2s",
+       .suspend                = ep93xx_i2s_suspend,
+       .resume                 = ep93xx_i2s_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static int ep93xx_i2s_probe(struct platform_device *pdev)
index c6043fa58c740dbdcf2a12cff80e178a05eb879c..fc65283031cdc2a1faf0cadebcbd1207d36e8d83 100644 (file)
@@ -1345,7 +1345,6 @@ static const struct snd_soc_component_driver soc_component_dev_pm860x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int pm860x_codec_probe(struct platform_device *pdev)
index 6165db92a62970cbfed6542ff6e525774ed17e6a..d16b4efb88a77b2c9a91ebc6f97db86d4321cb5a 100644 (file)
@@ -219,6 +219,7 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_TAS2562
        imply SND_SOC_TAS2764
        imply SND_SOC_TAS2770
+       imply SND_SOC_TAS2780
        imply SND_SOC_TAS5086
        imply SND_SOC_TAS571X
        imply SND_SOC_TAS5720
@@ -308,6 +309,7 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_WM9712
        imply SND_SOC_WM9713
        imply SND_SOC_WSA881X
+       imply SND_SOC_WSA883X
        imply SND_SOC_ZL38060
        help
          Normally ASoC codec drivers are only built if a machine driver which
@@ -937,6 +939,16 @@ config SND_SOC_HDAC_HDA
        tristate
        select SND_HDA
 
+config SND_SOC_HDA
+       tristate "HD-Audio codec driver"
+       select SND_HDA_EXT_CORE
+       select SND_HDA
+       help
+         This enables HD-Audio codec support in ASoC subsystem. Compared
+         to SND_SOC_HDAC_HDA, driver's behavior is identical to HD-Audio
+         legacy solution - including the dynamic resource allocation
+         based on actual codec capabilities.
+
 config SND_SOC_ICS43432
        tristate "ICS43423 and compatible i2s microphones"
 
@@ -1524,6 +1536,13 @@ config SND_SOC_TAS2770
        tristate "Texas Instruments TAS2770 speaker amplifier"
        depends on I2C
 
+config SND_SOC_TAS2780
+       tristate "Texas Instruments TAS2780 Mono Audio amplifier"
+       depends on I2C
+       help
+         Enable support for Texas Instruments TAS2780 high-efficiency
+         digital input mono Class-D audio power amplifiers.
+
 config SND_SOC_TAS5086
        tristate "Texas Instruments TAS5086 speaker amplifier"
        depends on I2C
@@ -1975,6 +1994,15 @@ config SND_SOC_WSA881X
          This enables support for Qualcomm WSA8810/WSA8815 Class-D
          Smart Speaker Amplifier.
 
+config SND_SOC_WSA883X
+       tristate "WSA883X Codec"
+       depends on SOUNDWIRE
+       select REGMAP_SOUNDWIRE
+       tristate
+       help
+         This enables support for Qualcomm WSA8830/WSA8835 Class-D
+         Smart Speaker Amplifier.
+
 config SND_SOC_ZL38060
        tristate "Microsemi ZL38060 Connected Home Audio Processor"
        depends on SPI_MASTER
index 28dc4edfd01fdd4578f4bf21090a02786c57f8c7..92fd441d426a83f4f2c2454b6eaa4a59208e07fe 100644 (file)
@@ -106,6 +106,7 @@ snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-gtm601-objs := gtm601.o
 snd-soc-hdac-hdmi-objs := hdac_hdmi.o
 snd-soc-hdac-hda-objs := hdac_hda.o
+snd-soc-hda-codec-objs := hda.o hda-dai.o
 snd-soc-ics43432-objs := ics43432.o
 snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
@@ -337,6 +338,7 @@ snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-wsa881x-objs := wsa881x.o
+snd-soc-wsa883x-objs := wsa883x.o
 snd-soc-zl38060-objs := zl38060.o
 # Amp
 snd-soc-max9877-objs := max9877.o
@@ -346,6 +348,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-tas2552-objs := tas2552.o
 snd-soc-tas2562-objs := tas2562.o
 snd-soc-tas2764-objs := tas2764.o
+snd-soc-tas2780-objs := tas2780.o
 # Mux
 snd-soc-simple-mux-objs := simple-mux.o
 
@@ -458,6 +461,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_GTM601)    += snd-soc-gtm601.o
 obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o
 obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o
+obj-$(CONFIG_SND_SOC_HDA) += snd-soc-hda-codec.o
 obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
 obj-$(CONFIG_SND_SOC_INNO_RK3036)      += snd-soc-inno-rk3036.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
@@ -589,6 +593,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS)       += snd-soc-sti-sas.o
 obj-$(CONFIG_SND_SOC_TAS2552)  += snd-soc-tas2552.o
 obj-$(CONFIG_SND_SOC_TAS2562)  += snd-soc-tas2562.o
 obj-$(CONFIG_SND_SOC_TAS2764)  += snd-soc-tas2764.o
+obj-$(CONFIG_SND_SOC_TAS2780)  += snd-soc-tas2780.o
 obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TAS571X)  += snd-soc-tas571x.o
 obj-$(CONFIG_SND_SOC_TAS5720)  += snd-soc-tas5720.o
@@ -688,6 +693,7 @@ obj-$(CONFIG_SND_SOC_WM9713)        += snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_ADSP)  += snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)  += snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_WSA881X)  += snd-soc-wsa881x.o
+obj-$(CONFIG_SND_SOC_WSA883X)  += snd-soc-wsa883x.o
 obj-$(CONFIG_SND_SOC_ZL38060)  += snd-soc-zl38060.o
 
 # Amp
index aefafb0b7b974a89fd049443f986b49b60050ac8..68342917419e4e0c869a6d9a46d458947dabaf55 100644 (file)
@@ -12,8 +12,6 @@
  *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
  *         Jarmo K. Kuronen <jarmo.kuronen@symbio.com>,
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #include <linux/kernel.h>
@@ -2525,7 +2523,6 @@ static const struct snd_soc_component_driver ab8500_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ab8500_codec_driver_probe(struct platform_device *pdev)
index 0ac87d0446c2a3a4dc2f9bbdbbdd846bcd683a93..2a6f6409f1f85ad88d6969d7865c0a226e5041d5 100644 (file)
@@ -11,8 +11,6 @@
  *         Mikko J. Lehto <mikko.lehto@symbio.com>,
  *         Mikko Sarmanne <mikko.sarmanne@symbio.com>,
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #ifndef AB8500_CODEC_REGISTERS_H
index 6ad9c9443b5db7558c9a01bf45066a83bc81dba6..cc12052e19204666b49b7a3c3907283e1ddb683e 100644 (file)
@@ -119,7 +119,6 @@ static const struct snd_soc_component_driver soc_component_dev_ac97 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ac97_probe(struct platform_device *pdev)
index 29e1689da67ff5b87609057c2b760b7d5330a727..2c64df96b5ce92213e58826c684bc3eec1d983cf 100644 (file)
@@ -332,7 +332,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad1836 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct reg_default ad1836_reg_defaults[] = {
index 30b98b4267e131d8093c329d94e31d17536f680d..1d3c4d94b4ae91c5dfcbfae9295f2478b39a3700 100644 (file)
@@ -523,7 +523,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad193x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 const struct regmap_config ad193x_regmap_config = {
index 9fd2023da218f69623762f29d3dc1142cc97e064..5e777d7fd5d91e6eec7d5ddd5c97511dcb2573d9 100644 (file)
@@ -302,7 +302,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad1980 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ad1980_probe(struct platform_device *pdev)
index b98bf19f594e097fae688195bff99c7e877e1cd1..f6090ac57e93721c39f4210d01ed05beddd21352 100644 (file)
@@ -58,7 +58,6 @@ static const struct snd_soc_component_driver soc_component_dev_ad73311 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ad73311_probe(struct platform_device *pdev)
index a9032b5c8d782fd8741c97e19a3e1ac7841bc755..7f832d00ab177638061fd2ef21c791d13f3f446d 100644 (file)
@@ -1470,7 +1470,6 @@ static const struct snd_soc_component_driver adau1373_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(adau1373_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int adau1373_i2c_probe(struct i2c_client *client)
index 98768e5300f09b9c8036f956b3fef67ab0db88f1..135a7db7fcf95263642a3d1ee225e7640276b2e6 100644 (file)
@@ -772,7 +772,6 @@ static const struct snd_soc_component_driver adau1701_component_drv = {
        .set_sysclk             = adau1701_set_sysclk,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config adau1701_regmap = {
index 8f887227981f1a9c3858bbec5205ae608efb19c6..3ccc7acac20560d38ad935239956f29d6b7fde09 100644 (file)
@@ -930,7 +930,6 @@ static const struct snd_soc_component_driver adau1761_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #define ADAU1761_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
index 74dc3344b25904f270e2d57eb924d9c51dae28d7..ff6be24863bfb801bac56a4194dd0ddc843ce9c0 100644 (file)
@@ -439,7 +439,6 @@ static const struct snd_soc_component_driver adau1781_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #define ADAU1781_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
index 5fcbdf2ec313c6130c782aef9098697e9260c987..7a9672f94fc6cd719392f8de6ef4489808c35fef 100644 (file)
@@ -876,7 +876,6 @@ static const struct snd_soc_component_driver adau1977_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(adau1977_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int adau1977_setup_micbias(struct adau1977 *adau1977)
index 0e00de6ce3fb1feb9e4bf0cc2cda76ef6c7cf4d1..401bafabc8eb4bf1b555e463d25d305bbafac1a2 100644 (file)
@@ -91,7 +91,6 @@ static const struct snd_soc_component_driver adau7002_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int adau7002_probe(struct platform_device *pdev)
index 841229dcbca108f49f7abaa1a5adb46cec19beeb..bbb09724988766f46b5fb2ae1d13669a5414e8d7 100644 (file)
@@ -442,7 +442,6 @@ static const struct snd_soc_component_driver adau7118_component_driver = {
        .num_dapm_widgets       = ARRAY_SIZE(adau7118_widgets),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void adau7118_regulator_disable(void *data)
index 90f3a5e9e31f461c4cd48f529d80c2d60ff9395f..fcff35f26cecb0c99b7020fabf27165922d3e613 100644 (file)
@@ -842,7 +842,6 @@ static const struct snd_soc_component_driver adav80x_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
index 1d07e2699f04d356e90783195fef0a6abf3fcc22..44aa06e034869b76f41c31d7d13164c1707e958e 100644 (file)
@@ -62,7 +62,6 @@ static const struct snd_soc_component_driver soc_component_dev_ads117x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ads117x_probe(struct platform_device *pdev)
index dc4747c77a7a1204c493cfcf069fa060d941ef2e..ce99f30b4613ac929e0a6797d71b249bae44a03d 100644 (file)
@@ -248,7 +248,6 @@ static const struct snd_soc_component_driver soc_component_device_ak4104 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4104_regmap = {
index 5c4a78c16733b77a64008b26b46e37a3a9328c26..b6d9a10bdccdcf75d042d21a46aece335b61ac2b 100644 (file)
@@ -342,7 +342,6 @@ static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4118_regmap = {
index 9a7b662016b9e335969a9acf367e1f5e16a5f7e9..1ed004ba7cd2333c728c48d6a239946e90fa086f 100644 (file)
@@ -473,7 +473,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4375 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4375_regmap = {
index baa9ff5d0ce503f6960be344ee978ca37a88acd5..ea33cc83c86c2da05233ffe8ebdbeb003837846a 100644 (file)
@@ -725,7 +725,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver soc_codec_dev_ak4497 = {
@@ -740,7 +739,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4497 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4458_regmap = {
index cc803e730c6ecbeb8d73ed264e056340f339c0e3..8c8c93eea704888d188728efd3e5f5ad178c7bab 100644 (file)
@@ -402,7 +402,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4535 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ak4535_i2c_probe(struct i2c_client *i2c)
index 8e60e2b56ad6d2afe6ad3eac8e8db4797ca2e34a..b9607de5a19120406c54e67c4a39f05ad2b4830f 100644 (file)
@@ -67,7 +67,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4554 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ak4554_soc_probe(struct platform_device *pdev)
index 93606e5afd8f1424b8a8f4af6d6efd7d2fd6d7cf..f75c19ef355110e60c7886e3cd23f705d6c3edd4 100644 (file)
@@ -827,7 +827,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4613 = {
        .num_dapm_routes        = ARRAY_SIZE(ak4613_intercon),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void ak4613_parse_of(struct ak4613_priv *priv,
@@ -921,18 +920,12 @@ static int ak4613_i2c_probe(struct i2c_client *i2c)
                                      &ak4613_dai, 1);
 }
 
-static int ak4613_i2c_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static struct i2c_driver ak4613_i2c_driver = {
        .driver = {
                .name = "ak4613-codec",
                .of_match_table = ak4613_of_match,
        },
        .probe_new      = ak4613_i2c_probe,
-       .remove         = ak4613_i2c_remove,
        .id_table       = ak4613_i2c_id,
 };
 
index d8d9cc712d679dc06bc098a2a7fc71818822fc8c..88851e94b045219832b9b4d3e4b9c21d28028769 100644 (file)
@@ -535,7 +535,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4641 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4641_regmap = {
index 3c20ff5595eb4603859b3ccba86f844412e000f1..914d5b1969f8c927a926ce4fd9663364c83c4e03 100644 (file)
@@ -559,7 +559,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4642 = {
        .num_dapm_routes        = ARRAY_SIZE(ak4642_intercon),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4642_regmap = {
index 60edcbe560141b86d684c15e1f9a2c1a4d296560..cd76765f8cc0822ac0d303f34fb284e05337999a 100644 (file)
@@ -616,7 +616,6 @@ static const struct snd_soc_component_driver soc_component_dev_ak4671 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak4671_regmap = {
index c76bfff246028e161afb517175f3d24ac2760a56..0c5e00679c7d8e47ee14d4e15ce8e19850050f11 100644 (file)
@@ -77,7 +77,6 @@ static const struct snd_soc_component_driver soc_component_ak5386 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
index c94cfde3e4a866372204783b61dfaed54cf5a951..887d2c04d647a11a40efafb5536efc1bc553e710 100644 (file)
@@ -393,7 +393,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver soc_codec_dev_ak5552 = {
@@ -408,7 +407,6 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5552 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ak5558_regmap = {
index 8e6235d2c544507c90657406adeadb4ce09052eb..9ef01b1dd2941b4870c4aee71550b8e7bcbe0eb0 100644 (file)
@@ -956,7 +956,6 @@ static const struct snd_soc_component_driver soc_component_device_alc5623 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config alc5623_regmap = {
index 641bdfddae160258354e04f748ec2d31db106930..a770704a4e1708c748be4fd9b190b74c6e414102 100644 (file)
@@ -1078,7 +1078,6 @@ static const struct snd_soc_component_driver soc_component_device_alc5632 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config alc5632_regmap = {
index a6267cb86d86003d5d2ee9d14748eed2025ebacc..82a94211d0123c676a4fca0cb855a4417d62b402 100644 (file)
@@ -161,7 +161,6 @@ static const struct snd_soc_component_driver soc_codec_bd = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver soc_dai_bd = {
index cf17b9741bd8329162e3e68781a70b10e81052f0..4086b6a53de8ca3a52734d500d3c76c916d67fb7 100644 (file)
@@ -69,7 +69,6 @@ static const struct snd_soc_component_driver soc_component_dev_bt_sco = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int bt_sco_probe(struct platform_device *pdev)
index ffdf8b615efaa0d631be0997726d5d9344038155..4f9dabd9d78a671cf2bcc48c1b65285388c68a3b 100644 (file)
@@ -1660,7 +1660,6 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cpcap_codec_probe(struct platform_device *pdev)
index 0aae5790222aef28b905ac83c86b584a356d70f3..14403b76c724343715f4a675c21076ac4765f27f 100644 (file)
@@ -126,7 +126,6 @@ static const struct snd_soc_component_driver soc_component_dev_cq93vc = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cq93vc_platform_probe(struct platform_device *pdev)
index 8b0a9c788a264b14eddada9c00ec4e7e11479ddc..11e7b3f6d410bb47f31eb0c2110cd7f08d39d46c 100644 (file)
@@ -995,6 +995,7 @@ static int cros_ec_codec_platform_probe(struct platform_device *pdev)
                        dev_dbg(dev, "ap_shm_phys_addr=%#llx len=%#x\n",
                                priv->ap_shm_phys_addr, priv->ap_shm_len);
                }
+               of_node_put(node);
        }
 #endif
 
index badfc55bc5fa0330778cec671e35d9cca75d2cf3..8ff6f66be86fa92dfd3483080e9c85d2bbf2498d 100644 (file)
@@ -236,7 +236,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l32 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /* Current and threshold powerup sequence Pg37 in datasheet */
index 47dc0f6d90a2a9d06cdc95312af220e5ca2891e7..082025fa0370c06942a21fe12218f1060579f8dc 100644 (file)
@@ -840,7 +840,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l33 = {
        .num_dapm_routes        = ARRAY_SIZE(cs35l33_audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config cs35l33_regmap = {
index 50d509a0607133b391fcb9f2c62e8d08f173b7a4..472ac982779be55811b40837a3016dc4eadfe2b0 100644 (file)
@@ -787,7 +787,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l34 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct regmap_config cs35l34_regmap = {
index 6b70afb70a674d99fa42a661a4b86083c4bf3c46..714a759dca21bf160b5daee0cba7f26bddfb1e01 100644 (file)
@@ -1087,7 +1087,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l35 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct regmap_config cs35l35_regmap = {
index dfe85dc2cd20fbddf8d4f125e87c3abae42795ba..4dc13e6f4874cbf85ffa7ed8e86e95788d8855f0 100644 (file)
@@ -1300,7 +1300,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l36 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct regmap_config cs35l36_regmap = {
index 198cfe54a46fc14beb6b1c526181bfdc729642fb..04be71435491e27089cc58e0276697707545db1f 100644 (file)
@@ -1308,7 +1308,8 @@ int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
                        return 0;
        }
 
-       dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);
+       if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
+               dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);
 
        return -ENOMSG;
 }
@@ -1327,6 +1328,85 @@ int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap)
 }
 EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata);
 
+int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap,
+                           enum cs35l41_boost_type b_type)
+{
+       if (!cs35l41_safe_reset(regmap, b_type)) {
+               dev_dbg(dev, "System does not support Suspend\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "Enter hibernate\n");
+       regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088);
+       regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188);
+
+       // Don't wait for ACK since bus activity would wake the device
+       regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate);
+
+static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap)
+{
+       const int pwrmgt_retries = 10;
+       unsigned int sts;
+       int i, ret;
+
+       for (i = 0; i < pwrmgt_retries; i++) {
+               ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts);
+               if (ret)
+                       dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret);
+               else if (!(sts & CS35L41_WR_PEND_STS_MASK))
+                       return;
+
+               udelay(20);
+       }
+
+       dev_err(dev, "Timed out reading PWRMGT_STS\n");
+}
+
+int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap)
+{
+       const int wake_retries = 20;
+       const int sleep_retries = 5;
+       int ret, i, j;
+
+       for (i = 0; i < sleep_retries; i++) {
+               dev_dbg(dev, "Exit hibernate\n");
+
+               for (j = 0; j < wake_retries; j++) {
+                       ret = cs35l41_set_cspl_mbox_cmd(dev, regmap,
+                                                       CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
+                       if (!ret)
+                               break;
+
+                       usleep_range(100, 200);
+               }
+
+               if (j < wake_retries) {
+                       dev_dbg(dev, "Wake success at cycle: %d\n", j);
+                       return 0;
+               }
+
+               dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret);
+
+               cs35l41_wait_for_pwrmgt_sts(dev, regmap);
+               regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088);
+
+               cs35l41_wait_for_pwrmgt_sts(dev, regmap);
+               regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188);
+
+               cs35l41_wait_for_pwrmgt_sts(dev, regmap);
+               regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3);
+       }
+
+       dev_err(dev, "Timed out waking device\n");
+
+       return -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate);
+
 MODULE_DESCRIPTION("CS35L41 library");
 MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
 MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
index 9e19c946a66b5aa28ecf9f913c2510988e512c31..5c8bb24909eb40596142cd3fdfe9f22880288fff 100644 (file)
@@ -74,6 +74,7 @@ MODULE_DEVICE_TABLE(of, cs35l41_of_match);
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id cs35l41_acpi_match[] = {
        { "CSC3541", 0 }, /* Cirrus Logic PnP ID + part ID */
+       { "CLSA3541", 0 }, /* Cirrus Logic PnP ID + part ID */
        {},
 };
 MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_match);
index 71ab2a5d1c559c6b6e8d8977e87aff1a551c0bdd..c223d83e02cfb26eb769dcca3339cdfcfbf0937b 100644 (file)
@@ -6,6 +6,7 @@
 //
 // Author: David Rhodes <david.rhodes@cirrus.com>
 
+#include <linux/acpi.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -1142,6 +1143,30 @@ err_dsp:
        return ret;
 }
 
+static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41)
+{
+       acpi_handle handle = ACPI_HANDLE(cs35l41->dev);
+       const char *sub;
+
+       /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
+       if (!handle)
+               return 0;
+
+       sub = acpi_get_subsystem_id(handle);
+       if (IS_ERR(sub)) {
+               /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */
+               if (PTR_ERR(sub) == -ENODATA)
+                       return 0;
+               else
+                       return PTR_ERR(sub);
+       }
+
+       cs35l41->dsp.system_name = sub;
+       dev_dbg(cs35l41->dev, "Subsystem ID: %s\n", cs35l41->dsp.system_name);
+
+       return 0;
+}
+
 int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg)
 {
        u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match;
@@ -1270,6 +1295,10 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
                goto err;
        }
 
+       ret = cs35l41_acpi_get_name(cs35l41);
+       if (ret < 0)
+               goto err;
+
        ret = cs35l41_dsp_init(cs35l41);
        if (ret < 0)
                goto err;
@@ -1316,6 +1345,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41)
        pm_runtime_disable(cs35l41->dev);
 
        regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
+       kfree(cs35l41->dsp.system_name);
        wm_adsp2_remove(&cs35l41->dsp);
        cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
 
@@ -1335,15 +1365,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
        if (!cs35l41->dsp.preloaded || !cs35l41->dsp.cs_dsp.running)
                return 0;
 
-       dev_dbg(cs35l41->dev, "Enter hibernate\n");
-
-       cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
-       regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
-       regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
-
-       // Don't wait for ACK since bus activity would wake the device
-       regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1,
-                    CSPL_MBOX_CMD_HIBERNATE);
+       cs35l41_enter_hibernate(dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type);
 
        regcache_cache_only(cs35l41->regmap, true);
        regcache_mark_dirty(cs35l41->regmap);
@@ -1351,65 +1373,6 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static void cs35l41_wait_for_pwrmgt_sts(struct cs35l41_private *cs35l41)
-{
-       const int pwrmgt_retries = 10;
-       unsigned int sts;
-       int i, ret;
-
-       for (i = 0; i < pwrmgt_retries; i++) {
-               ret = regmap_read(cs35l41->regmap, CS35L41_PWRMGT_STS, &sts);
-               if (ret)
-                       dev_err(cs35l41->dev, "Failed to read PWRMGT_STS: %d\n", ret);
-               else if (!(sts & CS35L41_WR_PEND_STS_MASK))
-                       return;
-
-               udelay(20);
-       }
-
-       dev_err(cs35l41->dev, "Timed out reading PWRMGT_STS\n");
-}
-
-static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41)
-{
-       const int wake_retries = 20;
-       const int sleep_retries = 5;
-       int ret, i, j;
-
-       for (i = 0; i < sleep_retries; i++) {
-               dev_dbg(cs35l41->dev, "Exit hibernate\n");
-
-               for (j = 0; j < wake_retries; j++) {
-                       ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
-                                                       CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
-                       if (!ret)
-                               break;
-
-                       usleep_range(100, 200);
-               }
-
-               if (j < wake_retries) {
-                       dev_dbg(cs35l41->dev, "Wake success at cycle: %d\n", j);
-                       return 0;
-               }
-
-               dev_err(cs35l41->dev, "Wake failed, re-enter hibernate: %d\n", ret);
-
-               cs35l41_wait_for_pwrmgt_sts(cs35l41);
-               regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
-
-               cs35l41_wait_for_pwrmgt_sts(cs35l41);
-               regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
-
-               cs35l41_wait_for_pwrmgt_sts(cs35l41);
-               regmap_write(cs35l41->regmap, CS35L41_PWRMGT_CTL, 0x3);
-       }
-
-       dev_err(cs35l41->dev, "Timed out waking device\n");
-
-       return -ETIMEDOUT;
-}
-
 static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
 {
        struct cs35l41_private *cs35l41 = dev_get_drvdata(dev);
@@ -1422,7 +1385,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
 
        regcache_cache_only(cs35l41->regmap, false);
 
-       ret = cs35l41_exit_hibernate(cs35l41);
+       ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
        if (ret)
                return ret;
 
index 38a4dbc9e9feadc5e199356ada8eeb10b367d85b..06c2ddffb9c53c2d69bf34da9bcb7295b7e1f5f2 100644 (file)
@@ -40,7 +40,9 @@ static int cs35l45_i2c_remove(struct i2c_client *client)
 {
        struct cs35l45_private *cs35l45 = i2c_get_clientdata(client);
 
-       return cs35l45_remove(cs35l45);
+       cs35l45_remove(cs35l45);
+
+       return 0;
 }
 
 static const struct of_device_id cs35l45_of_match[] = {
index 2367c1a4c10eb74a0367ca2f60928a1e6233b5b2..d15b3b77c7eb090bca61948cf7a29d9daab4ce25 100644 (file)
@@ -500,6 +500,8 @@ static const struct snd_soc_component_driver cs35l45_component = {
        .num_controls = ARRAY_SIZE(cs35l45_controls),
 
        .name = "cs35l45",
+
+       .endianness = 1,
 };
 
 static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
@@ -665,7 +667,7 @@ err:
 }
 EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45);
 
-int cs35l45_remove(struct cs35l45_private *cs35l45)
+void cs35l45_remove(struct cs35l45_private *cs35l45)
 {
        pm_runtime_disable(cs35l45->dev);
 
@@ -673,8 +675,6 @@ int cs35l45_remove(struct cs35l45_private *cs35l45)
        regulator_disable(cs35l45->vdd_a);
        /* VDD_BATT must be the last to power-off */
        regulator_disable(cs35l45->vdd_batt);
-
-       return 0;
 }
 EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
 
index 4e266d19cd1cda73b23b51501525103bf35d137b..53fe9d2b7b15f44d80c2063c97daacea6ccc6113 100644 (file)
@@ -209,9 +209,9 @@ struct cs35l45_private {
 extern const struct dev_pm_ops cs35l45_pm_ops;
 extern const struct regmap_config cs35l45_i2c_regmap;
 extern const struct regmap_config cs35l45_spi_regmap;
-int cs35l45_apply_patch(struct cs35l45_private *cs43l45);
+int cs35l45_apply_patch(struct cs35l45_private *cs35l45);
 unsigned int cs35l45_get_clk_freq_id(unsigned int freq);
 int cs35l45_probe(struct cs35l45_private *cs35l45);
-int cs35l45_remove(struct cs35l45_private *cs35l45);
+void cs35l45_remove(struct cs35l45_private *cs35l45);
 
 #endif /* CS35L45_H */
index 881c5ba70c0edaee3054100d003b696596a50d41..b49a3cf21ebe275138a07129a7a6dfa993ff44c9 100644 (file)
@@ -660,7 +660,6 @@ static const struct snd_soc_component_driver soc_component_cs4234 = {
        .controls               = cs4234_snd_controls,
        .num_controls           = ARRAY_SIZE(cs4234_snd_controls),
        .set_bias_level         = cs4234_set_bias_level,
-       .non_legacy_dai_naming  = 1,
        .idle_bias_on           = 1,
        .suspend_bias_off       = 1,
        .endianness             = 1,
index 86bfa8d5ec7872277acfa5b889aa525f68ebb4de..76c19802d5fe1ea03c16dc9ec9c54112095d7ac2 100644 (file)
@@ -553,7 +553,6 @@ static const struct snd_soc_component_driver soc_component_cs4265 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config cs4265_regmap = {
index 531f63b0155475462c7e1a4dc3a1cd98eb76c913..ba67e43edf35139ac96985ab720996abc320761d 100644 (file)
@@ -619,7 +619,6 @@ static const struct snd_soc_component_driver soc_component_device_cs4270 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /*
@@ -663,7 +662,6 @@ static int cs4270_i2c_remove(struct i2c_client *i2c_client)
 /**
  * cs4270_i2c_probe - initialize the I2C interface of the CS4270
  * @i2c_client: the I2C client object
- * @id: the I2C device ID (ignored)
  *
  * This function is called whenever the I2C subsystem finds a device that
  * matches the device ID given via a prior call to i2c_add_driver().
index 7663f89ac6a2420587b7976f528be6e71b904191..2021cf4426061ef7d8ced6f394c311dfcf1724b8 100644 (file)
@@ -642,7 +642,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs4271_common_probe(struct device *dev,
index 4fade2388797289d15177ed8ca1c7aade042880a..d545a593a2516603979ddf6c731cd80e0c64d2d6 100644 (file)
@@ -581,7 +581,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
        .num_controls           = ARRAY_SIZE(cs42l42_snd_controls),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */
@@ -1701,8 +1700,7 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data)
                        break;
 
                default:
-                       if (cs42l42->plug_state != CS42L42_TS_TRANS)
-                               cs42l42->plug_state = CS42L42_TS_TRANS;
+                       cs42l42->plug_state = CS42L42_TS_TRANS;
                }
        }
 
index 0e933181b5dbb98623c938953e4eb3a3aa9eaf39..51721edd8f53c756ca92dd05702931219660e2be 100644 (file)
@@ -600,7 +600,6 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg)
index 10e696406a71b161476ea50fa8e68ca7e6a7f9b8..90bf535fc5a524d9ddff1e7b3bb25121dee55bf7 100644 (file)
@@ -1061,7 +1061,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l52 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /* Current and threshold powerup sequence Pg37 */
index 510c94265b1f0da025825b3673bd19fae1d1887c..03e2540a0ba1264cbce4244139a1649094acacd7 100644 (file)
@@ -1114,7 +1114,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l56 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config cs42l56_regmap = {
index 5a9166289f366b40f67c7c6d890b53df34ad7944..0a146319755a6513e50f21ff7d999a2383359f5e 100644 (file)
@@ -1256,7 +1256,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l73 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config cs42l73_regmap = {
index 5d6ef660f851f8f4dc20385a2b3b059f415f0672..d14eb2f6e1dd4b1d6d5a1f5893893ce0b93ce415 100644 (file)
@@ -497,7 +497,6 @@ static const struct snd_soc_component_driver cs42xx8_driver = {
        .num_dapm_routes        = ARRAY_SIZE(cs42xx8_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 const struct cs42xx8_driver_data cs42448_data = {
index a2bce0f9f247b137d17c557593d13cd402b072fb..ca4d47cc9c915013488c85e81a68535e284710c0 100644 (file)
@@ -2345,7 +2345,6 @@ static struct snd_soc_component_driver soc_component_dev_cs43130 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config cs43130_regmap = {
index 8ac043f1aae0158ecb99e9d298a580c7dc3e9a99..ac1696034846d441250a92caeecd16b8ea9513db 100644 (file)
@@ -202,7 +202,6 @@ static const struct snd_soc_component_driver soc_component_cs4341 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id __maybe_unused cs4341_dt_ids[] = {
index 7069e9b548576d049df5a441357bf96a8ebe8e2a..f7c5c2fd430462cae969c34afa0c29f410ede1b4 100644 (file)
@@ -260,7 +260,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs4349 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config cs4349_regmap = {
index 1c7d52bef8935beae1518972529f09d2f92ce210..06c4214382e33a7fadef311c62b873bfeea5ce3a 100644 (file)
@@ -1356,7 +1356,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l15 = {
        .num_dapm_routes        = ARRAY_SIZE(cs47l15_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs47l15_probe(struct platform_device *pdev)
index 6356f81aafc563a0135cdf14e650465a7dabfff0..f9a2b865d71761cac4c31167b5734962b1f29e8c 100644 (file)
@@ -1203,7 +1203,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l24 = {
        .num_dapm_routes        = ARRAY_SIZE(cs47l24_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs47l24_probe(struct platform_device *pdev)
index db2f844b8b17f1a8983216d1f63c469e4eb91c8b..c1032d6c9143f9664ea4a7aedf6a15c5c9ca5d1f 100644 (file)
@@ -1638,7 +1638,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l35 = {
        .num_dapm_routes        = ARRAY_SIZE(cs47l35_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs47l35_probe(struct platform_device *pdev)
index d4fedc5ad516eb888d7b1276a89fa6264150f48b..215d8211aa59b77961534214db5494a8275436b9 100644 (file)
@@ -2582,7 +2582,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l85 = {
        .num_dapm_routes        = ARRAY_SIZE(cs47l85_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs47l85_probe(struct platform_device *pdev)
index 5aec937a24629851ab4491f96efa75febcc38bec..1ad6526c78717e11e0ec3ff6fe8e42318ad96b73 100644 (file)
@@ -2497,7 +2497,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l90 = {
        .num_dapm_routes        = ARRAY_SIZE(cs47l90_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs47l90_probe(struct platform_device *pdev)
index 444026b7d54b3243d393349eb04c704c79e36e24..fe576d64e0893de4b4a581a20e44a2ccac6b45c6 100644 (file)
@@ -1964,7 +1964,6 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l92 = {
        .num_dapm_routes        = ARRAY_SIZE(cs47l92_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cs47l92_probe(struct platform_device *pdev)
index 360ca2ffd506968ddc8bfb266b0b6fb52e833728..8796d8e84b7a26fe1da146a86e9c67ebf786c748 100644 (file)
@@ -899,7 +899,6 @@ static const struct snd_soc_component_driver cs53l30_driver = {
        .num_dapm_routes        = ARRAY_SIZE(cs53l30_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct regmap_config cs53l30_regmap = {
index 1af0bf5f1e2f5b0ffd1a2563cad944f9151d0460..43c0cac0ec9e84d140ac9eac11b9ffb37488ffd9 100644 (file)
@@ -411,7 +411,6 @@ static const struct snd_soc_component_driver cx20442_component_dev = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int cx20442_platform_probe(struct platform_device *pdev)
index b35debb5818db6bad0decca33a12e66c282b72a7..b6667e8a6099946bf81bb0a6e7f121bd6bbd9fde 100644 (file)
@@ -710,22 +710,19 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x)
 
        regdbt2.ulval = 0xac;
 
-       /* set master/slave */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                reg2.r.tx_master = 1;
                reg3.r.rx_master = 1;
-               dev_dbg(dev, "Sets Master mode\n");
                break;
 
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                reg2.r.tx_master = 0;
                reg3.r.rx_master = 0;
-               dev_dbg(dev, "Sets Slave mode\n");
                break;
 
        default:
-               dev_err(dev, "Unsupported DAI master mode\n");
+               dev_err(dev, "Unsupported DAI clocking mode\n");
                return -EINVAL;
        }
 
@@ -1009,9 +1006,9 @@ static int cx2072x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        dev_dbg(dev, "set_dai_fmt- %08x\n", fmt);
        /* set master/slave */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
 
        default:
index 3fa3042e44242307fd8518de4899d6a344c66a67..f838466bfebf8330918126120a3e2ed0d5c38c5d 100644 (file)
@@ -1173,7 +1173,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7210 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #if IS_ENABLED(CONFIG_I2C)
@@ -1335,6 +1334,8 @@ static int __init da7210_modinit(void)
        int ret = 0;
 #if IS_ENABLED(CONFIG_I2C)
        ret = i2c_add_driver(&da7210_i2c_driver);
+       if (ret)
+               return ret;
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&da7210_spi_driver);
index 2e645dc60eda4f357f9a821757bced3b086eeceb..544ccbcfc884421624c8795bbd285de9ad5314cc 100644 (file)
@@ -1922,7 +1922,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7213 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config da7213_regmap_config = {
index a5d7c350a3ded178dd9289a853323b4415a1d719..91372909d184b46597f304f2fe6f2e8c4f47d806 100644 (file)
@@ -3040,7 +3040,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7218 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 
index 7fdef38ed8cd365d6cfefdd4994edc177d962dae..50ecf30e6136ae7a1c6030f8c9754fefcc1f9a85 100644 (file)
@@ -2647,7 +2647,6 @@ static const struct snd_soc_component_driver soc_component_dev_da7219 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 
@@ -2693,11 +2692,6 @@ static int da7219_i2c_probe(struct i2c_client *i2c)
        return ret;
 }
 
-static int da7219_i2c_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id da7219_i2c_id[] = {
        { "da7219", },
        { }
@@ -2711,7 +2705,6 @@ static struct i2c_driver da7219_i2c_driver = {
                .acpi_match_table = ACPI_PTR(da7219_acpi_match),
        },
        .probe_new      = da7219_i2c_probe,
-       .remove         = da7219_i2c_remove,
        .id_table       = da7219_i2c_id,
 };
 
index f14cddf23f4271f7de848306c7992b317cd8f883..2c5b0b74201c71fed99b2c79552a96197be77c2f 100644 (file)
@@ -1503,7 +1503,6 @@ static const struct snd_soc_component_driver soc_component_dev_da732x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int da732x_i2c_probe(struct i2c_client *i2c)
@@ -1546,11 +1545,6 @@ err:
        return ret;
 }
 
-static int da732x_i2c_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id da732x_i2c_id[] = {
        { "da7320", 0},
        { }
@@ -1562,7 +1556,6 @@ static struct i2c_driver da732x_i2c_driver = {
                .name   = "da7320",
        },
        .probe_new      = da732x_i2c_probe,
-       .remove         = da732x_i2c_remove,
        .id_table       = da732x_i2c_id,
 };
 
index 9d8c8adc5d768ca5982a5ce77be43061904f5b5a..28043b4530df89878e1e5cf5fc972af826f06685 100644 (file)
@@ -1460,7 +1460,6 @@ static const struct snd_soc_component_driver soc_component_dev_da9055 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config da9055_regmap_config = {
index d1a30ca4571ad3d596375ebf702ddf150bb2b91a..4fd6f97e5a493c91c8b1c596661f7521bf7a138e 100644 (file)
@@ -140,7 +140,6 @@ static const struct snd_soc_component_driver soc_dmic = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int dmic_dev_probe(struct platform_device *pdev)
index f443351677dfe153e33ada0f06247372a347a14a..f5150d2f95da68f7cd3cbfaec7343e90fd5e54eb 100644 (file)
@@ -213,7 +213,6 @@ static const struct snd_soc_component_driver es7134_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver es7154_dai = {
index 0baa86241cf938f316d64729dece48a420ff4e69..339553cfbb48e7d7f1d52fa550a52f33491540ba 100644 (file)
@@ -232,7 +232,6 @@ static const struct snd_soc_component_driver es7241_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(es7241_dapm_routes),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv)
index 4407166bb3388e62d47dcb88b150b3076181706a..de7185f73e1e726dc73df15b096b21623d183d9e 100644 (file)
@@ -401,10 +401,8 @@ static int es8316_set_dai_fmt(struct snd_soc_dai *codec_dai,
        u8 clksw;
        u8 mask;
 
-       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
-               dev_err(component->dev, "Codec driver only supports consumer mode\n");
-               return -EINVAL;
-       }
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP)
+               serdata1 |= ES8316_SERDATA1_MASTER;
 
        if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) {
                dev_err(component->dev, "Codec driver only supports I2S format\n");
@@ -464,6 +462,8 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_component *component = dai->component;
        struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
        u8 wordlen = 0;
+       u8 bclk_divider;
+       u16 lrck_divider;
        int i;
 
        /* Validate supported sample rates that are autodetected from MCLK */
@@ -477,19 +477,24 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
        }
        if (i == NR_SUPPORTED_MCLK_LRCK_RATIOS)
                return -EINVAL;
-
+       lrck_divider = es8316->sysclk / params_rate(params);
+       bclk_divider = lrck_divider / 4;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                wordlen = ES8316_SERDATA2_LEN_16;
+               bclk_divider /= 16;
                break;
        case SNDRV_PCM_FORMAT_S20_3LE:
                wordlen = ES8316_SERDATA2_LEN_20;
+               bclk_divider /= 20;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
                wordlen = ES8316_SERDATA2_LEN_24;
+               bclk_divider /= 24;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                wordlen = ES8316_SERDATA2_LEN_32;
+               bclk_divider /= 32;
                break;
        default:
                return -EINVAL;
@@ -499,6 +504,11 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
                            ES8316_SERDATA2_LEN_MASK, wordlen);
        snd_soc_component_update_bits(component, ES8316_SERDATA_ADC,
                            ES8316_SERDATA2_LEN_MASK, wordlen);
+       snd_soc_component_update_bits(component, ES8316_SERDATA1, 0x1f, bclk_divider);
+       snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV1, 0x0f, lrck_divider >> 8);
+       snd_soc_component_update_bits(component, ES8316_CLKMGR_ADCDIV2, 0xff, lrck_divider & 0xff);
+       snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV1, 0x0f, lrck_divider >> 8);
+       snd_soc_component_update_bits(component, ES8316_CLKMGR_DACDIV2, 0xff, lrck_divider & 0xff);
        return 0;
 }
 
@@ -769,7 +779,6 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = {
        .num_dapm_routes        = ARRAY_SIZE(es8316_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_range es8316_volatile_ranges[] = {
index dd53dfd87b04ee0c28d9a2419898be5fb9565567..160adc706cc69e07ac7b71233a8776ccca9baf31 100644 (file)
@@ -844,7 +844,6 @@ static const struct snd_soc_component_driver es8328_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int es8328_probe(struct device *dev, struct regmap *regmap)
index e1235e695b0fb28a3de9d7e99817470f4595dd4f..c6b1e77ffccd0aa441a757ad62bedd7351a3d947 100644 (file)
@@ -73,7 +73,6 @@ static const struct snd_soc_component_driver soc_component_dev_gtm601 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int gtm601_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/hda-dai.c b/sound/soc/codecs/hda-dai.c
new file mode 100644 (file)
index 0000000..5371ff0
--- /dev/null
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <sound/soc.h>
+#include <sound/hda_codec.h>
+#include "hda.h"
+
+static int hda_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct hda_pcm_stream *stream_info;
+       struct hda_codec *codec;
+       struct hda_pcm *pcm;
+       int ret;
+
+       codec = dev_to_hda_codec(dai->dev);
+       stream_info = snd_soc_dai_get_dma_data(dai, substream);
+       pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
+
+       dev_dbg(dai->dev, "open stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
+               codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
+
+       snd_hda_codec_pcm_get(pcm);
+
+       ret = stream_info->ops.open(stream_info, codec, substream);
+       if (ret < 0) {
+               dev_err(dai->dev, "codec open failed: %d\n", ret);
+               snd_hda_codec_pcm_put(pcm);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void hda_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct hda_pcm_stream *stream_info;
+       struct hda_codec *codec;
+       struct hda_pcm *pcm;
+       int ret;
+
+       codec = dev_to_hda_codec(dai->dev);
+       stream_info = snd_soc_dai_get_dma_data(dai, substream);
+       pcm = container_of(stream_info, struct hda_pcm, stream[substream->stream]);
+
+       dev_dbg(dai->dev, "close stream codec: %08x, info: %p, pcm: %p %s substream: %p\n",
+               codec->core.vendor_id, stream_info, pcm, pcm->name, substream);
+
+       ret = stream_info->ops.close(stream_info, codec, substream);
+       if (ret < 0)
+               dev_err(dai->dev, "codec close failed: %d\n", ret);
+
+       snd_hda_codec_pcm_put(pcm);
+}
+
+static int hda_codec_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct hda_pcm_stream *stream_info;
+       struct hda_codec *codec;
+
+       codec = dev_to_hda_codec(dai->dev);
+       stream_info = snd_soc_dai_get_dma_data(dai, substream);
+
+       snd_hda_codec_cleanup(codec, stream_info, substream);
+
+       return 0;
+}
+
+static int hda_codec_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct hda_pcm_stream *stream_info;
+       struct hdac_stream *stream;
+       struct hda_codec *codec;
+       unsigned int format;
+       int ret;
+
+       codec = dev_to_hda_codec(dai->dev);
+       stream = substream->runtime->private_data;
+       stream_info = snd_soc_dai_get_dma_data(dai, substream);
+       format = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
+                                            runtime->sample_bits, 0);
+
+       ret = snd_hda_codec_prepare(codec, stream_info, stream->stream_tag, format, substream);
+       if (ret < 0) {
+               dev_err(dai->dev, "codec prepare failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops = {
+       .startup = hda_codec_dai_startup,
+       .shutdown = hda_codec_dai_shutdown,
+       .hw_free = hda_codec_dai_hw_free,
+       .prepare = hda_codec_dai_prepare,
+};
+EXPORT_SYMBOL_GPL(snd_soc_hda_codec_dai_ops);
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
new file mode 100644 (file)
index 0000000..ad20a3d
--- /dev/null
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/hdaudio_ext.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
+#include "hda.h"
+
+static int hda_codec_create_dais(struct hda_codec *codec, int pcm_count,
+                                struct snd_soc_dai_driver **drivers)
+{
+       struct device *dev = &codec->core.dev;
+       struct snd_soc_dai_driver *drvs;
+       struct hda_pcm *pcm;
+       int i;
+
+       drvs = devm_kcalloc(dev, pcm_count, sizeof(*drvs), GFP_KERNEL);
+       if (!drvs)
+               return -ENOMEM;
+
+       pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+       for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+               struct snd_soc_pcm_stream *stream;
+               int dir;
+
+               dev_info(dev, "creating for %s %d\n", pcm->name, i);
+               drvs[i].id = i;
+               drvs[i].name = pcm->name;
+               drvs[i].ops = &snd_soc_hda_codec_dai_ops;
+
+               dir = SNDRV_PCM_STREAM_PLAYBACK;
+               stream = &drvs[i].playback;
+               if (!pcm->stream[dir].substreams) {
+                       dev_info(dev, "skipping playback dai for %s\n", pcm->name);
+                       goto capture_dais;
+               }
+
+               stream->stream_name =
+                       devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+                                      snd_pcm_direction_name(dir));
+               if (!stream->stream_name)
+                       return -ENOMEM;
+               stream->channels_min = pcm->stream[dir].channels_min;
+               stream->channels_max = pcm->stream[dir].channels_max;
+               stream->rates = pcm->stream[dir].rates;
+               stream->formats = pcm->stream[dir].formats;
+               stream->sig_bits = pcm->stream[dir].maxbps;
+
+capture_dais:
+               dir = SNDRV_PCM_STREAM_CAPTURE;
+               stream = &drvs[i].capture;
+               if (!pcm->stream[dir].substreams) {
+                       dev_info(dev, "skipping capture dai for %s\n", pcm->name);
+                       continue;
+               }
+
+               stream->stream_name =
+                       devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+                                      snd_pcm_direction_name(dir));
+               if (!stream->stream_name)
+                       return -ENOMEM;
+               stream->channels_min = pcm->stream[dir].channels_min;
+               stream->channels_max = pcm->stream[dir].channels_max;
+               stream->rates = pcm->stream[dir].rates;
+               stream->formats = pcm->stream[dir].formats;
+               stream->sig_bits = pcm->stream[dir].maxbps;
+       }
+
+       *drivers = drvs;
+       return 0;
+}
+
+static int hda_codec_register_dais(struct hda_codec *codec, struct snd_soc_component *component)
+{
+       struct snd_soc_dai_driver *drvs = NULL;
+       struct snd_soc_dapm_context *dapm;
+       struct hda_pcm *pcm;
+       int ret, pcm_count = 0;
+
+       if (list_empty(&codec->pcm_list_head))
+               return -EINVAL;
+       list_for_each_entry(pcm, &codec->pcm_list_head, list)
+               pcm_count++;
+
+       ret = hda_codec_create_dais(codec, pcm_count, &drvs);
+       if (ret < 0)
+               return ret;
+
+       dapm = snd_soc_component_get_dapm(component);
+
+       list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+               struct snd_soc_dai *dai;
+
+               dai = snd_soc_register_dai(component, drvs, false);
+               if (!dai) {
+                       dev_err(component->dev, "register dai for %s failed\n", pcm->name);
+                       return -EINVAL;
+               }
+
+               ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
+               if (ret < 0) {
+                       dev_err(component->dev, "create widgets failed: %d\n", ret);
+                       snd_soc_unregister_dai(dai);
+                       return ret;
+               }
+
+               snd_soc_dai_init_dma_data(dai, &pcm->stream[0], &pcm->stream[1]);
+               drvs++;
+       }
+
+       return 0;
+}
+
+static void hda_codec_unregister_dais(struct hda_codec *codec,
+                                     struct snd_soc_component *component)
+{
+       struct snd_soc_dai *dai, *save;
+       struct hda_pcm *pcm;
+
+       for_each_component_dais_safe(component, dai, save) {
+               list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+                       if (strcmp(dai->driver->name, pcm->name))
+                               continue;
+
+                       if (dai->playback_widget)
+                               snd_soc_dapm_free_widget(dai->playback_widget);
+                       if (dai->capture_widget)
+                               snd_soc_dapm_free_widget(dai->capture_widget);
+                       snd_soc_unregister_dai(dai);
+                       break;
+               }
+       }
+}
+
+int hda_codec_probe_complete(struct hda_codec *codec)
+{
+       struct hdac_device *hdev = &codec->core;
+       struct hdac_bus *bus = hdev->bus;
+       int ret;
+
+       ret = snd_hda_codec_build_controls(codec);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "unable to create controls %d\n", ret);
+               goto out;
+       }
+
+       /* Bus suspended codecs as it does not manage their pm */
+       pm_runtime_set_active(&hdev->dev);
+       /* rpm was forbidden in snd_hda_codec_device_new() */
+       snd_hda_codec_set_power_save(codec, 2000);
+       snd_hda_codec_register(codec);
+out:
+       /* Complement pm_runtime_get_sync(bus) in probe */
+       pm_runtime_mark_last_busy(bus->dev);
+       pm_runtime_put_autosuspend(bus->dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
+
+/* Expects codec with usage_count=1 and status=suspended */
+static int hda_codec_probe(struct snd_soc_component *component)
+{
+       struct hda_codec *codec = dev_to_hda_codec(component->dev);
+       struct hdac_device *hdev = &codec->core;
+       struct hdac_bus *bus = hdev->bus;
+       struct hdac_ext_link *hlink;
+       hda_codec_patch_t patch;
+       int ret;
+
+#ifdef CONFIG_PM
+       WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
+               !pm_runtime_status_suspended(&hdev->dev));
+#endif
+
+       hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+       if (!hlink) {
+               dev_err(&hdev->dev, "hdac link not found\n");
+               return -EIO;
+       }
+
+       pm_runtime_get_sync(bus->dev);
+       if (hda_codec_is_display(codec))
+               snd_hdac_display_power(bus, hdev->addr, true);
+       snd_hdac_ext_bus_link_get(bus, hlink);
+
+       ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec,
+                                      false);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "create hda codec failed: %d\n", ret);
+               goto device_new_err;
+       }
+
+       ret = snd_hda_codec_set_name(codec, codec->preset->name);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "name failed %s\n", codec->preset->name);
+               goto err;
+       }
+
+       ret = snd_hdac_regmap_init(&codec->core);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "regmap init failed\n");
+               goto err;
+       }
+
+       patch = (hda_codec_patch_t)codec->preset->driver_data;
+       if (!patch) {
+               dev_err(&hdev->dev, "no patch specified?\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = patch(codec);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "patch failed %d\n", ret);
+               goto err;
+       }
+
+       /* configure codec for 1:1 PCM:DAI mapping */
+       codec->mst_no_extra_pcms = 1;
+
+       ret = snd_hda_codec_parse_pcms(codec);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret);
+               goto parse_pcms_err;
+       }
+
+       ret = hda_codec_register_dais(codec, component);
+       if (ret < 0) {
+               dev_err(&hdev->dev, "update dais failed: %d\n", ret);
+               goto parse_pcms_err;
+       }
+
+       if (!hda_codec_is_display(codec)) {
+               ret = hda_codec_probe_complete(codec);
+               if (ret < 0)
+                       goto complete_err;
+       }
+
+       codec->core.lazy_cache = true;
+
+       return 0;
+
+complete_err:
+       hda_codec_unregister_dais(codec, component);
+parse_pcms_err:
+       if (codec->patch_ops.free)
+               codec->patch_ops.free(codec);
+err:
+       snd_hda_codec_cleanup_for_unbind(codec);
+device_new_err:
+       if (hda_codec_is_display(codec))
+               snd_hdac_display_power(bus, hdev->addr, false);
+
+       snd_hdac_ext_bus_link_put(bus, hlink);
+
+       pm_runtime_mark_last_busy(bus->dev);
+       pm_runtime_put_autosuspend(bus->dev);
+       return ret;
+}
+
+/* Leaves codec with usage_count=1 and status=suspended */
+static void hda_codec_remove(struct snd_soc_component *component)
+{
+       struct hda_codec *codec = dev_to_hda_codec(component->dev);
+       struct hdac_device *hdev = &codec->core;
+       struct hdac_bus *bus = hdev->bus;
+       struct hdac_ext_link *hlink;
+       bool was_registered = codec->core.registered;
+
+       /* Don't allow any more runtime suspends */
+       pm_runtime_forbid(&hdev->dev);
+
+       hda_codec_unregister_dais(codec, component);
+
+       if (codec->patch_ops.free)
+               codec->patch_ops.free(codec);
+
+       snd_hda_codec_cleanup_for_unbind(codec);
+       pm_runtime_put_noidle(&hdev->dev);
+       /* snd_hdac_device_exit() is only called on bus remove */
+       pm_runtime_set_suspended(&hdev->dev);
+
+       if (hda_codec_is_display(codec))
+               snd_hdac_display_power(bus, hdev->addr, false);
+
+       hlink = snd_hdac_ext_bus_link_at(bus, hdev->addr);
+       if (hlink)
+               snd_hdac_ext_bus_link_put(bus, hlink);
+       /*
+        * HDMI card's hda_codec_probe_complete() (see late_probe()) may
+        * not be called due to early error, leaving bus uc unbalanced
+        */
+       if (!was_registered) {
+               pm_runtime_mark_last_busy(bus->dev);
+               pm_runtime_put_autosuspend(bus->dev);
+       }
+
+#ifdef CONFIG_PM
+       WARN_ON(atomic_read(&hdev->dev.power.usage_count) != 1 ||
+               !pm_runtime_status_suspended(&hdev->dev));
+#endif
+}
+
+static const struct snd_soc_dapm_route hda_dapm_routes[] = {
+       {"AIF1TX", NULL, "Codec Input Pin1"},
+       {"AIF2TX", NULL, "Codec Input Pin2"},
+       {"AIF3TX", NULL, "Codec Input Pin3"},
+
+       {"Codec Output Pin1", NULL, "AIF1RX"},
+       {"Codec Output Pin2", NULL, "AIF2RX"},
+       {"Codec Output Pin3", NULL, "AIF3RX"},
+};
+
+static const struct snd_soc_dapm_widget hda_dapm_widgets[] = {
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Input Pins */
+       SND_SOC_DAPM_INPUT("Codec Input Pin1"),
+       SND_SOC_DAPM_INPUT("Codec Input Pin2"),
+       SND_SOC_DAPM_INPUT("Codec Input Pin3"),
+
+       /* Output Pins */
+       SND_SOC_DAPM_OUTPUT("Codec Output Pin1"),
+       SND_SOC_DAPM_OUTPUT("Codec Output Pin2"),
+       SND_SOC_DAPM_OUTPUT("Codec Output Pin3"),
+};
+
+static struct snd_soc_dai_driver card_binder_dai = {
+       .id = -1,
+       .name = "codec-probing-DAI",
+};
+
+static int hda_hdev_attach(struct hdac_device *hdev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
+       struct snd_soc_component_driver *comp_drv;
+
+       comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL);
+       if (!comp_drv)
+               return -ENOMEM;
+
+       /*
+        * It's save to rely on dev_name() rather than a copy as component
+        * driver's lifetime is directly tied to hda codec one
+        */
+       comp_drv->name = dev_name(&hdev->dev);
+       comp_drv->probe = hda_codec_probe;
+       comp_drv->remove = hda_codec_remove;
+       comp_drv->idle_bias_on = false;
+       if (!hda_codec_is_display(codec)) {
+               comp_drv->dapm_widgets = hda_dapm_widgets;
+               comp_drv->num_dapm_widgets = ARRAY_SIZE(hda_dapm_widgets);
+               comp_drv->dapm_routes = hda_dapm_routes;
+               comp_drv->num_dapm_routes = ARRAY_SIZE(hda_dapm_routes);
+       }
+
+       return snd_soc_register_component(&hdev->dev, comp_drv, &card_binder_dai, 1);
+}
+
+static int hda_hdev_detach(struct hdac_device *hdev)
+{
+       struct hda_codec *codec = dev_to_hda_codec(&hdev->dev);
+
+       if (codec->core.registered)
+               cancel_delayed_work_sync(&codec->jackpoll_work);
+
+       snd_soc_unregister_component(&hdev->dev);
+
+       return 0;
+}
+
+const struct hdac_ext_bus_ops soc_hda_ext_bus_ops = {
+       .hdev_attach = hda_hdev_attach,
+       .hdev_detach = hda_hdev_detach,
+};
+EXPORT_SYMBOL_GPL(soc_hda_ext_bus_ops);
+
+MODULE_DESCRIPTION("HD-Audio codec driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/hda.h b/sound/soc/codecs/hda.h
new file mode 100644 (file)
index 0000000..78a2be4
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+ *
+ * Author: Cezary Rojewski <cezary.rojewski@intel.com>
+ */
+
+#ifndef SND_SOC_CODECS_HDA_H
+#define SND_SOC_CODECS_HDA_H
+
+#define hda_codec_is_display(codec) \
+       ((((codec)->core.vendor_id >> 16) & 0xFFFF) == 0x8086)
+
+extern const struct snd_soc_dai_ops snd_soc_hda_codec_dai_ops;
+
+extern const struct hdac_ext_bus_ops soc_hda_ext_bus_ops;
+int hda_codec_probe_complete(struct hda_codec *codec);
+
+#endif
index 66408a98298be1234b5099ff4266020ccc28c929..cb23650ad5223e98193042c853d8af7c50e28d74 100644 (file)
@@ -2058,7 +2058,6 @@ static const struct snd_soc_component_driver hdmi_hda_codec = {
        .remove                 = hdmi_codec_remove,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx,
index b773466619b235a931f318b09ffe2e29174631b1..5679102de91f8d2510bc570bf51f979ff0b47384 100644 (file)
@@ -606,18 +606,18 @@ static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai,
        /* Reset daifmt */
        memset(cf, 0, sizeof(*cf));
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               cf->bit_clk_master = 1;
-               cf->frame_clk_master = 1;
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
+               cf->bit_clk_provider = 1;
+               cf->frame_clk_provider = 1;
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
-               cf->frame_clk_master = 1;
+       case SND_SOC_DAIFMT_CBC_CFP:
+               cf->frame_clk_provider = 1;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               cf->bit_clk_master = 1;
+       case SND_SOC_DAIFMT_CBP_CFC:
+               cf->bit_clk_provider = 1;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -977,7 +977,6 @@ static const struct snd_soc_component_driver hdmi_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
        .set_jack               = hdmi_codec_set_jack,
 };
 
index de4c8460ab3df05ebbbbfc3dd4b2e65bbd22a660..58a3822547189a011a316349b8978c758cb7b1a0 100644 (file)
@@ -41,7 +41,6 @@ static const struct snd_soc_component_driver ics43432_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int ics43432_probe(struct platform_device *pdev)
index ca0f4c1911e483c18b88ad1aae7252d9bd080f26..8222cde6e3b90ec7771484b0311385120c2c9a63 100644 (file)
@@ -387,7 +387,6 @@ static const struct snd_soc_component_driver rk3036_codec_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rk3036_codec_regmap_config = {
index 39be31e1282e7d87a79fccb11faed1cd1a70e52b..50105d72b2b74c540a7eb3e54d6eb6700a0b0c4a 100644 (file)
@@ -1095,7 +1095,6 @@ static const struct snd_soc_component_driver soc_component_dev_isabelle = {
        .num_dapm_routes        = ARRAY_SIZE(isabelle_intercon),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config isabelle_regmap_config = {
index 081485f784e9bc588fcfcb41ed9697919f9621a2..7c25acf6ff0dedff6070c870c85984b7b83e2f10 100644 (file)
@@ -291,8 +291,6 @@ static const struct snd_soc_component_driver soc_codec_dev_jz4740_codec = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
-
 };
 
 static const struct regmap_config jz4740_codec_regmap_config = {
index bd0078e4499bb52ab5e87cfab025e747932c61d0..a2e782cc4276a28e65e717ebd7d3f03a5e8442f8 100644 (file)
@@ -1399,7 +1399,6 @@ static const struct snd_soc_component_driver soc_component_dev_lm49453 = {
        .num_dapm_routes        = ARRAY_SIZE(lm49453_audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config lm49453_regmap_config = {
@@ -1442,11 +1441,6 @@ static int lm49453_i2c_probe(struct i2c_client *i2c)
        return ret;
 }
 
-static int lm49453_i2c_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id lm49453_i2c_id[] = {
        { "lm49453", 0 },
        { }
@@ -1458,7 +1452,6 @@ static struct i2c_driver lm49453_i2c_driver = {
                .name = "lm49453",
        },
        .probe_new = lm49453_i2c_probe,
-       .remove = lm49453_i2c_remove,
        .id_table = lm49453_i2c_id,
 };
 
index 54a8ba7ed3c2090dce1147d420662967d47dbd1d..13fbd8830b09fdd3b01cc859f40b690ad7062ec7 100644 (file)
@@ -217,7 +217,6 @@ static const struct snd_soc_component_driver lochnagar_sc_driver = {
        .dapm_routes = lochnagar_sc_routes,
        .num_dapm_routes = ARRAY_SIZE(lochnagar_sc_routes),
 
-       .non_legacy_dai_naming = 1,
        .endianness = 1,
 };
 
index d18b56e6043305a3ae0e7670286727f6a97eb761..1ea10dc70748a1cf66a0fb39043d1e734b3dfb0c 100644 (file)
@@ -199,6 +199,7 @@ struct va_macro {
        struct clk *mclk;
        struct clk *macro;
        struct clk *dcodec;
+       struct clk *fsgen;
        struct clk_hw hw;
        struct lpass_macro *pds;
 
@@ -467,9 +468,9 @@ static int va_macro_mclk_event(struct snd_soc_dapm_widget *w,
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               return va_macro_mclk_enable(va, true);
+               return clk_prepare_enable(va->fsgen);
        case SND_SOC_DAPM_POST_PMD:
-               return va_macro_mclk_enable(va, false);
+               clk_disable_unprepare(va->fsgen);
        }
 
        return 0;
@@ -1473,6 +1474,12 @@ static int va_macro_probe(struct platform_device *pdev)
        if (ret)
                goto err_clkout;
 
+       va->fsgen = clk_hw_get_clk(&va->hw, "fsgen");
+       if (IS_ERR(va->fsgen)) {
+               ret = PTR_ERR(va->fsgen);
+               goto err_clkout;
+       }
+
        ret = devm_snd_soc_register_component(dev, &va_macro_component_drv,
                                              va_macro_dais,
                                              ARRAY_SIZE(va_macro_dais));
index 5ef2e1279ee714b241993d9792026ef5568b0f7b..5435a49604cf1e5136570b26e8352bf6bdf6c308 100644 (file)
@@ -1734,7 +1734,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98088 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct i2c_device_id max98088_i2c_id[] = {
@@ -1746,18 +1745,18 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
 
 static int max98088_i2c_probe(struct i2c_client *i2c)
 {
-       struct max98088_priv *max98088;
-       int ret;
-       const struct i2c_device_id *id;
+       struct max98088_priv *max98088;
+       int ret;
+       const struct i2c_device_id *id;
 
-       max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv),
-                              GFP_KERNEL);
-       if (max98088 == NULL)
-               return -ENOMEM;
+       max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv),
+                               GFP_KERNEL);
+       if (max98088 == NULL)
+               return -ENOMEM;
 
-       max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap);
-       if (IS_ERR(max98088->regmap))
-              return PTR_ERR(max98088->regmap);
+       max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap);
+       if (IS_ERR(max98088->regmap))
+               return PTR_ERR(max98088->regmap);
 
        max98088->mclk = devm_clk_get(&i2c->dev, "mclk");
        if (IS_ERR(max98088->mclk))
@@ -1765,14 +1764,14 @@ static int max98088_i2c_probe(struct i2c_client *i2c)
                        return PTR_ERR(max98088->mclk);
 
        id = i2c_match_id(max98088_i2c_id, i2c);
-       max98088->devtype = id->driver_data;
+       max98088->devtype = id->driver_data;
 
-       i2c_set_clientdata(i2c, max98088);
-       max98088->pdata = i2c->dev.platform_data;
+       i2c_set_clientdata(i2c, max98088);
+       max98088->pdata = i2c->dev.platform_data;
 
-       ret = devm_snd_soc_register_component(&i2c->dev,
-                       &soc_component_dev_max98088, &max98088_dai[0], 2);
-       return ret;
+       ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_max98088,
+                                             &max98088_dai[0], 2);
+       return ret;
 }
 
 #if defined(CONFIG_OF)
index 576277a82d41a95e0cd6db8a329f0178509b7712..142083b13ac3be0ae4383b5d48917eb5090fa107 100644 (file)
@@ -1591,9 +1591,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
                cdata->fmt = fmt;
 
                regval = 0;
-               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-               case SND_SOC_DAIFMT_CBS_CFS:
-                       /* Set to slave mode PLL - MAS mode off */
+               switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+               case SND_SOC_DAIFMT_CBC_CFC:
+                       /* Set to consumer mode PLL - MAS mode off */
                        snd_soc_component_write(component,
                                M98090_REG_CLOCK_RATIO_NI_MSB, 0x00);
                        snd_soc_component_write(component,
@@ -1602,8 +1602,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
                                M98090_USE_M1_MASK, 0);
                        max98090->master = false;
                        break;
-               case SND_SOC_DAIFMT_CBM_CFM:
-                       /* Set to master mode */
+               case SND_SOC_DAIFMT_CBP_CFP:
+                       /* Set to provider mode */
                        if (max98090->tdm_slots == 4) {
                                /* TDM */
                                regval |= M98090_MAS_MASK |
@@ -1619,8 +1619,6 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
                        }
                        max98090->master = true;
                        break;
-               case SND_SOC_DAIFMT_CBS_CFM:
-               case SND_SOC_DAIFMT_CBM_CFS:
                default:
                        dev_err(component->dev, "DAI clock mode unsupported");
                        return -EINVAL;
@@ -2521,7 +2519,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98090 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98090_regmap = {
index 7bca99fa61b54753b5aa85f89507102ab971122c..44aa58fcc23f829861c35070427538ea9be0b421 100644 (file)
@@ -2103,7 +2103,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98095 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct i2c_device_id max98095_i2c_id[] = {
index 918812763884861252d433f2094c59560f29df1c..2a2b286f1747f2ba76474ac79f1962ef219338aa 100644 (file)
@@ -93,7 +93,6 @@ static const struct snd_soc_component_driver max98357a_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops max98357a_dai_ops = {
index 800f2bca6a0f1226a5e498695662a090255f53df..bac9d1bcf60aec5fc293f01a43ec1f3ca1f22ec6 100644 (file)
@@ -351,7 +351,6 @@ static const struct snd_soc_component_driver max98371_component = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98371_regmap = {
index 4fe065ece17cb3e0655a25dcae154aa9dd69c6af..3e04c7f0cce43bff93d981e7d38acd7ef88ee99a 100644 (file)
@@ -442,7 +442,6 @@ static bool max98373_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case MAX98373_R2000_SW_RESET ... MAX98373_R2009_INT_FLAG3:
-       case MAX98373_R203E_AMP_PATH_GAIN:
        case MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK:
        case MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK:
        case MAX98373_R20B6_BDE_CUR_STATE_READBACK:
index e14fe98349a5eaf6102f12659b7ec55bc4649fe7..f90a6a7ba83b8cb122a8192c197f6e4d57788dc6 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/cdev.h>
@@ -436,12 +437,22 @@ const struct snd_soc_component_driver soc_codec_dev_max98373 = {
        .num_dapm_routes        = ARRAY_SIZE(max98373_audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_max98373);
 
+static int max98373_sdw_probe(struct snd_soc_component *component)
+{
+       int ret;
+
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
 const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = {
-       .probe                  = NULL,
+       .probe                  = max98373_sdw_probe,
        .controls               = max98373_snd_controls,
        .num_controls           = ARRAY_SIZE(max98373_snd_controls),
        .dapm_widgets           = max98373_dapm_widgets,
@@ -450,7 +461,6 @@ const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = {
        .num_dapm_routes        = ARRAY_SIZE(max98373_audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_max98373_sdw);
 
index 2a6b1648c8844eafa395089e5c2b96efcdadd28b..5c08166a8dc62a6116161f2237d17637c80e2d56 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/cdev.h>
 #include <linux/dmi.h>
 #include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of_gpio.h>
@@ -983,7 +983,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98390 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98390_regmap = {
index 34db38812807566706ef07f3233c08ab572f076f..364b4b7ee033ffc17a1ae45ae6e70d7439fa37cb 100644 (file)
@@ -5,11 +5,18 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <sound/pcm_params.h>
+#include <linux/regulator/consumer.h>
 #include <sound/soc.h>
 #include <linux/gpio.h>
 #include <sound/tlv.h>
 #include "max98396.h"
 
+static const char * const max98396_core_supplies[MAX98396_NUM_CORE_SUPPLIES] = {
+       "avdd",
+       "dvdd",
+       "dvddio",
+};
+
 static struct reg_default max98396_reg[] = {
        {MAX98396_R2000_SW_RESET, 0x00},
        {MAX98396_R2001_INT_RAW1, 0x00},
@@ -368,7 +375,8 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                break;
 
        default:
-               dev_err(component->dev, "DAI invert mode unsupported\n");
+               dev_err(component->dev, "DAI invert mode %d unsupported\n",
+                       fmt & SND_SOC_DAIFMT_INV_MASK);
                return -EINVAL;
        }
 
@@ -387,6 +395,8 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                format |= MAX98396_PCM_FORMAT_TDM_MODE0;
                break;
        default:
+               dev_err(component->dev, "DAI format %d unsupported\n",
+                       fmt & SND_SOC_DAIFMT_FORMAT_MASK);
                return -EINVAL;
        }
 
@@ -428,46 +438,68 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        return 0;
 }
 
-/* BCLKs per LRCLK */
-static const int bclk_sel_table[] = {
-       32, 48, 64, 96, 128, 192, 256, 384, 512, 320,
+#define MAX98396_BSEL_32       0x2
+#define MAX98396_BSEL_48       0x3
+#define MAX98396_BSEL_64       0x4
+#define MAX98396_BSEL_96       0x5
+#define MAX98396_BSEL_128      0x6
+#define MAX98396_BSEL_192      0x7
+#define MAX98396_BSEL_256      0x8
+#define MAX98396_BSEL_384      0x9
+#define MAX98396_BSEL_512      0xa
+#define MAX98396_BSEL_320      0xb
+#define MAX98396_BSEL_250      0xc
+#define MAX98396_BSEL_125      0xd
+
+/* Refer to table 5 in the datasheet */
+static const struct max98396_pcm_config {
+       int in, out, width, bsel, max_sr;
+} max98396_pcm_configs[] = {
+       { .in = 2,  .out = 4,  .width = 16, .bsel = MAX98396_BSEL_32,  .max_sr = 192000 },
+       { .in = 2,  .out = 6,  .width = 24, .bsel = MAX98396_BSEL_48,  .max_sr = 192000 },
+       { .in = 2,  .out = 8,  .width = 32, .bsel = MAX98396_BSEL_64,  .max_sr = 192000 },
+       { .in = 3,  .out = 15, .width = 32, .bsel = MAX98396_BSEL_125, .max_sr = 192000 },
+       { .in = 4,  .out = 8,  .width = 16, .bsel = MAX98396_BSEL_64,  .max_sr = 192000 },
+       { .in = 4,  .out = 12, .width = 24, .bsel = MAX98396_BSEL_96,  .max_sr = 192000 },
+       { .in = 4,  .out = 16, .width = 32, .bsel = MAX98396_BSEL_128, .max_sr = 192000 },
+       { .in = 5,  .out = 15, .width = 24, .bsel = MAX98396_BSEL_125, .max_sr = 192000 },
+       { .in = 7,  .out = 15, .width = 16, .bsel = MAX98396_BSEL_125, .max_sr = 192000 },
+       { .in = 2,  .out = 4,  .width = 16, .bsel = MAX98396_BSEL_32,  .max_sr = 96000  },
+       { .in = 2,  .out = 6,  .width = 24, .bsel = MAX98396_BSEL_48,  .max_sr = 96000  },
+       { .in = 2,  .out = 8,  .width = 32, .bsel = MAX98396_BSEL_64,  .max_sr = 96000  },
+       { .in = 3,  .out = 15, .width = 32, .bsel = MAX98396_BSEL_125, .max_sr = 96000  },
+       { .in = 4,  .out = 8,  .width = 16, .bsel = MAX98396_BSEL_64,  .max_sr = 96000  },
+       { .in = 4,  .out = 12, .width = 24, .bsel = MAX98396_BSEL_96,  .max_sr = 96000  },
+       { .in = 4,  .out = 16, .width = 32, .bsel = MAX98396_BSEL_128, .max_sr = 96000  },
+       { .in = 5,  .out = 15, .width = 24, .bsel = MAX98396_BSEL_125, .max_sr = 96000  },
+       { .in = 7,  .out = 15, .width = 16, .bsel = MAX98396_BSEL_125, .max_sr = 96000  },
+       { .in = 7,  .out = 31, .width = 32, .bsel = MAX98396_BSEL_250, .max_sr = 96000  },
+       { .in = 8,  .out = 16, .width = 16, .bsel = MAX98396_BSEL_128, .max_sr = 96000  },
+       { .in = 8,  .out = 24, .width = 24, .bsel = MAX98396_BSEL_192, .max_sr = 96000  },
+       { .in = 8,  .out = 32, .width = 32, .bsel = MAX98396_BSEL_256, .max_sr = 96000  },
+       { .in = 10, .out = 31, .width = 24, .bsel = MAX98396_BSEL_250, .max_sr = 96000  },
+       { .in = 15, .out = 31, .width = 16, .bsel = MAX98396_BSEL_250, .max_sr = 96000  },
+       { .in = 16, .out = 32, .width = 16, .bsel = MAX98396_BSEL_256, .max_sr = 96000  },
+       { .in = 7,  .out = 31, .width = 32, .bsel = MAX98396_BSEL_250, .max_sr = 48000  },
+       { .in = 10, .out = 31, .width = 24, .bsel = MAX98396_BSEL_250, .max_sr = 48000  },
+       { .in = 10, .out = 40, .width = 32, .bsel = MAX98396_BSEL_320, .max_sr = 48000  },
+       { .in = 15, .out = 31, .width = 16, .bsel = MAX98396_BSEL_250, .max_sr = 48000  },
+       { .in = 16, .out = 48, .width = 24, .bsel = MAX98396_BSEL_384, .max_sr = 48000  },
+       { .in = 16, .out = 64, .width = 32, .bsel = MAX98396_BSEL_512, .max_sr = 48000  },
 };
 
-static int max98396_get_bclk_sel(int bclk)
+static int max98396_pcm_config_index(int in_slots, int out_slots, int width)
 {
        int i;
-       /* match BCLKs per LRCLK */
-       for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) {
-               if (bclk_sel_table[i] == bclk)
-                       return i + 2;
-       }
-       return 0;
-}
 
-static int max98396_set_clock(struct snd_soc_component *component,
-                             struct snd_pcm_hw_params *params)
-{
-       struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
-       /* BCLK/LRCLK ratio calculation */
-       int blr_clk_ratio = params_channels(params) * max98396->ch_size;
-       int value;
+       for (i = 0; i < ARRAY_SIZE(max98396_pcm_configs); i++) {
+               const struct max98396_pcm_config *c = &max98396_pcm_configs[i];
 
-       if (!max98396->tdm_mode) {
-               /* BCLK configuration */
-               value = max98396_get_bclk_sel(blr_clk_ratio);
-               if (!value) {
-                       dev_err(component->dev, "format unsupported %d\n",
-                               params_format(params));
-                       return -EINVAL;
-               }
-
-               regmap_update_bits(max98396->regmap,
-                                  MAX98396_R2042_PCM_CLK_SETUP,
-                                  MAX98396_PCM_CLK_SETUP_BSEL_MASK,
-                                  value);
+               if (in_slots == c->in && out_slots <= c->out && width == c->width)
+                       return i;
        }
 
-       return 0;
+       return -1;
 }
 
 static int max98396_dai_hw_params(struct snd_pcm_substream *substream,
@@ -478,8 +510,7 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream,
        struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
        unsigned int sampling_rate = 0;
        unsigned int chan_sz = 0;
-       int ret, reg;
-       int status;
+       int ret, reg, status, bsel = 0;
        bool update = false;
 
        /* pcm mode configuration */
@@ -499,8 +530,6 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream,
                goto err;
        }
 
-       max98396->ch_size = snd_pcm_format_width(params_format(params));
-
        dev_dbg(component->dev, "format supported %d",
                params_format(params));
 
@@ -548,6 +577,33 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream,
                goto err;
        }
 
+       if (max98396->tdm_mode) {
+               if (params_rate(params) > max98396->tdm_max_samplerate) {
+                       dev_err(component->dev, "TDM sample rate %d too high",
+                               params_rate(params));
+                       goto err;
+               }
+       } else {
+               /* BCLK configuration */
+               ret = max98396_pcm_config_index(params_channels(params),
+                                               params_channels(params),
+                                               snd_pcm_format_width(params_format(params)));
+               if (ret < 0) {
+                       dev_err(component->dev,
+                               "no PCM config for %d channels, format %d\n",
+                               params_channels(params), params_format(params));
+                       goto err;
+               }
+
+               bsel = max98396_pcm_configs[ret].bsel;
+
+               if (params_rate(params) > max98396_pcm_configs[ret].max_sr) {
+                       dev_err(component->dev, "sample rate %d too high",
+                               params_rate(params));
+                       goto err;
+               }
+       }
+
        ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status);
        if (ret < 0)
                goto err;
@@ -593,12 +649,16 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream,
                                   MAX98396_IVADC_SR_MASK,
                                   sampling_rate << MAX98396_IVADC_SR_SHIFT);
 
-       ret = max98396_set_clock(component, params);
+       if (bsel)
+               regmap_update_bits(max98396->regmap,
+                               MAX98396_R2042_PCM_CLK_SETUP,
+                               MAX98396_PCM_CLK_SETUP_BSEL_MASK,
+                               bsel);
 
        if (status && update)
                max98396_global_enable_onoff(max98396->regmap, true);
 
-       return ret;
+       return 0;
 
 err:
        return -EINVAL;
@@ -623,13 +683,16 @@ static int max98396_dai_tdm_slot(struct snd_soc_dai *dai,
                max98396->tdm_mode = true;
 
        /* BCLK configuration */
-       bsel = max98396_get_bclk_sel(slots * slot_width);
-       if (bsel == 0) {
-               dev_err(component->dev, "BCLK %d not supported\n",
-                       slots * slot_width);
+       ret = max98396_pcm_config_index(slots, slots, slot_width);
+       if (ret < 0) {
+               dev_err(component->dev, "no TDM config for %d slots %d bits\n",
+                       slots, slot_width);
                return -EINVAL;
        }
 
+       bsel = max98396_pcm_configs[ret].bsel;
+       max98396->tdm_max_samplerate = max98396_pcm_configs[ret].max_sr;
+
        /* Channel size configuration */
        switch (slot_width) {
        case 16:
@@ -642,7 +705,7 @@ static int max98396_dai_tdm_slot(struct snd_soc_dai *dai,
                chan_sz = MAX98396_PCM_MODE_CFG_CHANSZ_32;
                break;
        default:
-               dev_err(component->dev, "format unsupported %d\n",
+               dev_err(component->dev, "slot width %d unsupported\n",
                        slot_width);
                return -EINVAL;
        }
@@ -1331,6 +1394,12 @@ static int max98396_probe(struct snd_soc_component *component)
                regmap_write(max98396->regmap,
                             MAX98397_R2057_PCM_RX_SRC2, 0x10);
        }
+       /* Supply control */
+       regmap_update_bits(max98396->regmap,
+                          MAX98396_R20A0_AMP_SUPPLY_CTL,
+                          MAX98396_AMP_SUPPLY_NOVBAT,
+                          (max98396->vbat == NULL) ?
+                               MAX98396_AMP_SUPPLY_NOVBAT : 0);
        /* Enable DC blocker */
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2092_AMP_DSP_CFG, 1, 1);
@@ -1360,6 +1429,9 @@ static int max98396_probe(struct snd_soc_component *component)
        regmap_write(max98396->regmap,
                     MAX98396_R2045_PCM_TX_CTRL_2,
                     max98396->i_slot);
+       regmap_write(max98396->regmap,
+                    MAX98396_R204A_PCM_TX_CTRL_7,
+                    max98396->spkfb_slot);
 
        if (max98396->v_slot < 8)
                if (max98396->device_id == CODEC_TYPE_MAX98396)
@@ -1426,12 +1498,38 @@ static int max98396_suspend(struct device *dev)
 
        regcache_cache_only(max98396->regmap, true);
        regcache_mark_dirty(max98396->regmap);
+       regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
+                              max98396->core_supplies);
+       if (max98396->pvdd)
+               regulator_disable(max98396->pvdd);
+
+       if (max98396->vbat)
+               regulator_disable(max98396->vbat);
+
        return 0;
 }
 
 static int max98396_resume(struct device *dev)
 {
        struct max98396_priv *max98396 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES,
+                                   max98396->core_supplies);
+       if (ret < 0)
+               return ret;
+
+       if (max98396->pvdd) {
+               ret = regulator_enable(max98396->pvdd);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (max98396->vbat) {
+               ret = regulator_enable(max98396->vbat);
+               if (ret < 0)
+                       return ret;
+       }
 
        regcache_cache_only(max98396->regmap, false);
        max98396_reset(max98396, dev);
@@ -1455,7 +1553,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98396 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver soc_codec_dev_max98397 = {
@@ -1469,7 +1566,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98397 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98396_regmap = {
@@ -1509,17 +1605,35 @@ static void max98396_read_device_property(struct device *dev,
        else
                max98396->i_slot = 1;
 
+       if (!device_property_read_u32(dev, "adi,spkfb-slot-no", &value))
+               max98396->spkfb_slot = value & 0xF;
+       else
+               max98396->spkfb_slot = 2;
+
        if (!device_property_read_u32(dev, "adi,bypass-slot-no", &value))
                max98396->bypass_slot = value & 0xF;
        else
                max98396->bypass_slot = 0;
 }
 
+static void max98396_core_supplies_disable(void *priv)
+{
+       struct max98396_priv *max98396 = priv;
+
+       regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
+                              max98396->core_supplies);
+}
+
+static void max98396_supply_disable(void *r)
+{
+       regulator_disable((struct regulator *) r);
+}
+
 static int max98396_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
        struct max98396_priv *max98396 = NULL;
-       int ret, reg;
+       int i, ret, reg;
 
        max98396 = devm_kzalloc(&i2c->dev, sizeof(*max98396), GFP_KERNEL);
 
@@ -1545,6 +1659,69 @@ static int max98396_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
+       /* Obtain regulator supplies */
+       for (i = 0; i < MAX98396_NUM_CORE_SUPPLIES; i++)
+               max98396->core_supplies[i].supply = max98396_core_supplies[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, MAX98396_NUM_CORE_SUPPLIES,
+                                     max98396->core_supplies);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to request core supplies: %d\n", ret);
+               return ret;
+       }
+
+       max98396->vbat = devm_regulator_get_optional(&i2c->dev, "vbat");
+       if (IS_ERR(max98396->vbat)) {
+               if (PTR_ERR(max98396->vbat) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               max98396->vbat = NULL;
+       }
+
+       max98396->pvdd = devm_regulator_get_optional(&i2c->dev, "pvdd");
+       if (IS_ERR(max98396->pvdd)) {
+               if (PTR_ERR(max98396->pvdd) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               max98396->pvdd = NULL;
+       }
+
+       ret = regulator_bulk_enable(MAX98396_NUM_CORE_SUPPLIES,
+                                   max98396->core_supplies);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Unable to enable core supplies: %d", ret);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&i2c->dev, max98396_core_supplies_disable,
+                                      max98396);
+       if (ret < 0)
+               return ret;
+
+       if (max98396->pvdd) {
+               ret = regulator_enable(max98396->pvdd);
+               if (ret < 0)
+                       return ret;
+
+               ret = devm_add_action_or_reset(&i2c->dev,
+                                              max98396_supply_disable,
+                                              max98396->pvdd);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (max98396->vbat) {
+               ret = regulator_enable(max98396->vbat);
+               if (ret < 0)
+                       return ret;
+
+               ret = devm_add_action_or_reset(&i2c->dev,
+                                              max98396_supply_disable,
+                                              max98396->vbat);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* update interleave mode info */
        if (device_property_read_bool(&i2c->dev, "adi,interleave_mode"))
                max98396->interleave_mode = true;
index 694411038597b6b8ff517293662c54d4b82bd84e..7278c779989a21f2a4309c97037fde4167a92e63 100644 (file)
 #define MAX98396_DSP_SPK_SAFE_EN_SHIFT         (5)
 #define MAX98396_DSP_SPK_WB_FLT_EN_SHIFT       (6)
 
+/* MAX98396_R20A0_AMP_SUPPLY_CTL */
+#define MAX98396_AMP_SUPPLY_NOVBAT             (0x1 << 0)
+
 /* MAX98396_R20E0_IV_SENSE_PATH_CFG */
 #define MAX98396_IV_SENSE_DCBLK_EN_MASK                (0x3 << 0)
 #define MAX98396_IV_SENSE_DCBLK_EN_SHIFT       (0)
@@ -291,15 +294,20 @@ enum {
        CODEC_TYPE_MAX98397,
 };
 
+#define  MAX98396_NUM_CORE_SUPPLIES 3
+
 struct max98396_priv {
        struct regmap *regmap;
        struct gpio_desc *reset_gpio;
+       struct regulator_bulk_data core_supplies[MAX98396_NUM_CORE_SUPPLIES];
+       struct regulator *pvdd, *vbat;
        unsigned int v_slot;
        unsigned int i_slot;
+       unsigned int spkfb_slot;
        unsigned int bypass_slot;
        bool interleave_mode;
-       unsigned int ch_size;
        bool tdm_mode;
+       int tdm_max_samplerate;
        int device_id;
 };
 #endif
index 9ca6fc254883c96ca996d814ae8f5e31c203e2a6..a6733396b0cadaa93bc44f2d6eeb01b29424a3c1 100644 (file)
@@ -296,7 +296,6 @@ static const struct snd_soc_component_driver soc_component_dev_max9850 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int max9850_i2c_probe(struct i2c_client *i2c)
index f0f085ecab55073f0ae95c27182d88e90d7715ec..5edd6f90f8a7b47aeb4aa165d0748229f3b9a0c8 100644 (file)
@@ -657,7 +657,6 @@ static const struct snd_soc_component_driver soc_codec_dev_max98520 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98520_regmap = {
index 82f20a8e27ad5fd8d9fd4e733b84306cf2d21b94..771b3dcd6cc322cd2baa8852a06fb368c755a08a 100644 (file)
@@ -448,9 +448,9 @@ static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct snd_soc_component *component = dai->component;
        struct max9860_priv *max9860 = snd_soc_component_get_drvdata(component);
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_CBC_CFC:
                max9860->fmt = fmt;
                return 0;
 
@@ -537,7 +537,6 @@ static const struct snd_soc_component_driver max9860_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(max9860_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #ifdef CONFIG_PM
index eb628b7e84f5591526b5ccfc7995154344fe576d..6d2941a9dbd6ea76f824b679a282de55acb59a14 100644 (file)
@@ -589,7 +589,6 @@ static const struct snd_soc_component_driver max9867_component = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static bool max9867_volatile_register(struct device *dev, unsigned int reg)
index 63849ebcfd354e9cee999fae95f9a41a842acdb3..c24d9f2c8874d6e243d5d15091f8c2c23b641174 100644 (file)
@@ -544,7 +544,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98925 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98925_regmap = {
index 56e0a87c7112f4443b4b12cde186bdb7132e02b3..bffd56e240e9a3c14f0290669a13f8efd85c012e 100644 (file)
@@ -496,7 +496,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98926 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98926_regmap = {
index b7cff76d7b5b9e9f0ab3c2d401ebe261ab6ef233..9cce7c0f01424816aa8537233f161df5a48bb33e 100644 (file)
@@ -832,7 +832,6 @@ static const struct snd_soc_component_driver soc_component_dev_max98927 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config max98927_regmap = {
index 08517547e66c73f1e500526b61fef662be427ab7..71490f11d96ac2836cdc80d1b87f29028ebd1336 100644 (file)
@@ -727,7 +727,6 @@ static const struct snd_soc_component_driver soc_component_dev_mc13783 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int __init mc13783_codec_probe(struct platform_device *pdev)
index de8fcbdd85be4ff33ca2a7a5e990378fed85b763..3c6ac77379cbea601939b8a34e06f712fc916472 100644 (file)
@@ -537,7 +537,6 @@ static const struct snd_soc_component_driver soc_component_dev_ml26124 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ml26124_i2c_regmap = {
index e52a559c52d6889440acc285763f6720be6d77b3..78e543eb3c8341b90b4fb3f888eed07f08f9003b 100644 (file)
@@ -1128,7 +1128,6 @@ static const struct snd_soc_component_driver pm8916_wcd_analog = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int pm8916_wcd_analog_parse_dt(struct device *dev,
index 20a07c92b2fc29d5749c21453f04d0020bc823ff..d490a0f1867521fd62ed64e20b922c805f1b6c02 100644 (file)
@@ -328,8 +328,8 @@ static const struct snd_kcontrol_new rx1_mix2_inp1_mux = SOC_DAPM_ENUM(
 static const struct snd_kcontrol_new rx2_mix2_inp1_mux = SOC_DAPM_ENUM(
                                "RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
 
-/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */
-static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0);
+/* Digital Gain control -84 dB to +40 dB in 1 dB steps */
+static const DECLARE_TLV_DB_SCALE(digital_gain, -8400, 100, -8400);
 
 /* Cutoff Freq for High Pass Filter at -3dB */
 static const char * const hpf_cutoff_text[] = {
@@ -510,15 +510,15 @@ static int wcd_iir_filter_info(struct snd_kcontrol *kcontrol,
 
 static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = {
        SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL,
-                         -128, 127, digital_gain),
+                       -84, 40, digital_gain),
        SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL,
-                         -128, 127, digital_gain),
+                       -84, 40, digital_gain),
        SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL,
-                         -128, 127, digital_gain),
+                       -84, 40, digital_gain),
        SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN,
-                         -128, 127, digital_gain),
+                       -84, 40, digital_gain),
        SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN,
-                         -128, 127, digital_gain),
+                       -84, 40, digital_gain),
        SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum),
        SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum),
        SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0),
@@ -553,22 +553,22 @@ static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = {
        WCD_IIR_FILTER_CTL("IIR2 Band3", IIR2, BAND3),
        WCD_IIR_FILTER_CTL("IIR2 Band4", IIR2, BAND4),
        WCD_IIR_FILTER_CTL("IIR2 Band5", IIR2, BAND5),
-       SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL,
-                       0,  -84,        40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL,
-                       0,  -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", LPASS_CDC_IIR1_GAIN_B1_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", LPASS_CDC_IIR1_GAIN_B2_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", LPASS_CDC_IIR1_GAIN_B3_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", LPASS_CDC_IIR1_GAIN_B4_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR2 INP1 Volume", LPASS_CDC_IIR2_GAIN_B1_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR2 INP2 Volume", LPASS_CDC_IIR2_GAIN_B2_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR2 INP3 Volume", LPASS_CDC_IIR2_GAIN_B3_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("IIR2 INP4 Volume", LPASS_CDC_IIR2_GAIN_B4_CTL,
+                       -84, 40, digital_gain),
 
 };
 
@@ -1155,7 +1155,6 @@ static const struct snd_soc_component_driver msm8916_wcd_digital = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config msm8916_codec_regmap_config = {
index 60b209efe52d110f33be1295931d299239e38cad..93f35e8d26fce33620b8c3b6a88ef6e1a8f6c834 100644 (file)
@@ -2479,6 +2479,7 @@ static int mt6358_platform_driver_probe(struct platform_device *pdev)
 
 static const struct of_device_id mt6358_of_match[] = {
        {.compatible = "mediatek,mt6358-sound",},
+       {.compatible = "mediatek,mt6366-sound",},
        {}
 };
 MODULE_DEVICE_TABLE(of, mt6358_of_match);
index 6d3d170144a0ae35b28068b4d7bd96a40b5897a9..c190628e290566c26e4a56ca702818d7a2f30965 100644 (file)
@@ -675,6 +675,7 @@ static int mt6359_accdet_parse_dt(struct mt6359_accdet *priv)
                               sizeof(struct three_key_threshold));
        }
 
+       of_node_put(node);
        dev_warn(priv->dev, "accdet caps=%x\n", priv->caps);
 
        return 0;
index 23709b180409cd6695173670420ca9b8844573f0..c9a453ce8a2a888ef229bd36964a51cccd4e2a7a 100644 (file)
@@ -2778,6 +2778,7 @@ static int mt6359_parse_dt(struct mt6359_priv *priv)
 
        ret = of_property_read_u32(np, "mediatek,mic-type-2",
                                   &priv->mux_select[MUX_MIC_TYPE_2]);
+       of_node_put(np);
        if (ret) {
                dev_info(priv->dev,
                         "%s() failed to read mic-type-2, use default (%d)\n",
index 2b66e3f7a8b7f705928c7dc4956395c050b2b939..ad4dce9e508078870de6fa6ee5afb887fcc1eb2a 100644 (file)
@@ -93,7 +93,6 @@ static const struct snd_soc_component_driver nau8315_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops nau8315_dai_ops = {
index 347c715e22a4be4cdb1af5c8dd7de11307deab88..58f70a02f18aad83654420d8bd843bf4a1e37dc9 100644 (file)
@@ -806,7 +806,6 @@ static const struct snd_soc_component_driver nau8540_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config nau8540_regmap_config = {
index 7b3b1e4ac2465677f7c0267782fd74103e751352..ccb512c21d748c03ee910e86ac6dd58e4bc9fcf6 100644 (file)
@@ -866,7 +866,6 @@ static const struct snd_soc_component_driver nau8810_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int nau8810_i2c_probe(struct i2c_client *i2c)
index ce4e7f46bb067fde13385086fd4fa5ca2f1d38ea..2d21339932e651bdf24bf3b6a6ebf6bef5bfde40 100644 (file)
 #define NAU_FVCO_MAX 100000000
 #define NAU_FVCO_MIN 90000000
 
+#define NAU8821_BUTTON SND_JACK_BTN_0
+
 /* the maximum frequency of CLK_ADC and CLK_DAC */
 #define CLK_DA_AD_MAX 6144000
 
 static int nau8821_configure_sysclk(struct nau8821 *nau8821,
        int clk_id, unsigned int freq);
+static bool nau8821_is_jack_inserted(struct regmap *regmap);
 
 struct nau8821_fll {
        int mclk_src;
@@ -493,7 +496,33 @@ static int nau8821_output_dac_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int system_clock_control(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_component *component =
+               snd_soc_dapm_to_component(w->dapm);
+       struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               dev_dbg(nau8821->dev, "system clock control : POWER OFF\n");
+               /* Set clock source to disable or internal clock before the
+                * playback or capture end. Codec needs clock for Jack
+                * detection and button press if jack inserted; otherwise,
+                * the clock should be closed.
+                */
+               if (nau8821_is_jack_inserted(nau8821->regmap)) {
+                       nau8821_configure_sysclk(nau8821,
+                               NAU8821_CLK_INTERNAL, 0);
+               } else {
+                       nau8821_configure_sysclk(nau8821, NAU8821_CLK_DIS, 0);
+               }
+       }
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget nau8821_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0,
+               system_clock_control, SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8821_R74_MIC_BIAS,
                NAU8821_MICBIAS_POWERUP_SFT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0,
@@ -605,6 +634,9 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = {
        {"AIFTX", NULL, "ADCL Digital path"},
        {"AIFTX", NULL, "ADCR Digital path"},
 
+       {"AIFTX", NULL, "System Clock"},
+       {"AIFRX", NULL, "System Clock"},
+
        {"DDACL", NULL, "AIFRX"},
        {"DDACR", NULL, "AIFRX"},
 
@@ -911,6 +943,20 @@ static void nau8821_eject_jack(struct nau8821 *nau8821)
        /* Recover to normal channel input */
        regmap_update_bits(regmap, NAU8821_R2B_ADC_RATE,
                        NAU8821_ADC_R_SRC_EN, 0);
+       if (nau8821->key_enable) {
+               regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
+                       NAU8821_IRQ_KEY_RELEASE_EN |
+                       NAU8821_IRQ_KEY_PRESS_EN,
+                       NAU8821_IRQ_KEY_RELEASE_EN |
+                       NAU8821_IRQ_KEY_PRESS_EN);
+               regmap_update_bits(regmap,
+                       NAU8821_R12_INTERRUPT_DIS_CTRL,
+                       NAU8821_IRQ_KEY_RELEASE_DIS |
+                       NAU8821_IRQ_KEY_PRESS_DIS,
+                       NAU8821_IRQ_KEY_RELEASE_DIS |
+                       NAU8821_IRQ_KEY_PRESS_DIS);
+       }
+
 }
 
 static void nau8821_jdet_work(struct work_struct *work)
@@ -940,6 +986,15 @@ static void nau8821_jdet_work(struct work_struct *work)
                 */
                regmap_update_bits(regmap, NAU8821_R2B_ADC_RATE,
                        NAU8821_ADC_R_SRC_EN, NAU8821_ADC_R_SRC_EN);
+               if (nau8821->key_enable) {
+                       regmap_update_bits(regmap, NAU8821_R0F_INTERRUPT_MASK,
+                               NAU8821_IRQ_KEY_RELEASE_EN |
+                               NAU8821_IRQ_KEY_PRESS_EN, 0);
+                       regmap_update_bits(regmap,
+                               NAU8821_R12_INTERRUPT_DIS_CTRL,
+                               NAU8821_IRQ_KEY_RELEASE_DIS |
+                               NAU8821_IRQ_KEY_PRESS_DIS, 0);
+               }
        } else {
                dev_dbg(nau8821->dev, "Headphone connected\n");
                event |= SND_JACK_HEADPHONE;
@@ -999,6 +1054,13 @@ static irqreturn_t nau8821_interrupt(int irq, void *data)
                nau8821_eject_jack(nau8821);
                event_mask |= SND_JACK_HEADSET;
                clear_irq = NAU8821_JACK_EJECT_IRQ_MASK;
+       } else if (active_irq & NAU8821_KEY_SHORT_PRESS_IRQ) {
+               event |= NAU8821_BUTTON;
+               event_mask |= NAU8821_BUTTON;
+               clear_irq = NAU8821_KEY_SHORT_PRESS_IRQ;
+       } else if (active_irq & NAU8821_KEY_RELEASE_IRQ) {
+               event_mask = NAU8821_BUTTON;
+               clear_irq = NAU8821_KEY_RELEASE_IRQ;
        } else if ((active_irq & NAU8821_JACK_INSERT_IRQ_MASK) ==
                NAU8821_JACK_INSERT_DETECTED) {
                regmap_update_bits(regmap, NAU8821_R71_ANALOG_ADC_1,
@@ -1430,7 +1492,6 @@ static const struct snd_soc_component_driver nau8821_component_driver = {
        .dapm_routes            = nau8821_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(nau8821_dapm_routes),
        .suspend_bias_off       = 1,
-       .non_legacy_dai_naming  = 1,
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
@@ -1490,6 +1551,7 @@ static void nau8821_print_device_properties(struct nau8821 *nau8821)
                nau8821->jack_eject_debounce);
        dev_dbg(dev, "dmic-clk-threshold:       %d\n",
                nau8821->dmic_clk_threshold);
+       dev_dbg(dev, "key_enable:       %d\n", nau8821->key_enable);
 }
 
 static int nau8821_read_device_properties(struct device *dev,
@@ -1503,6 +1565,8 @@ static int nau8821_read_device_properties(struct device *dev,
                "nuvoton,jkdet-pull-enable");
        nau8821->jkdet_pull_up = device_property_read_bool(dev,
                "nuvoton,jkdet-pull-up");
+       nau8821->key_enable = device_property_read_bool(dev,
+               "nuvoton,key-enable");
        ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
                &nau8821->jkdet_polarity);
        if (ret)
@@ -1665,15 +1729,6 @@ static int nau8821_i2c_probe(struct i2c_client *i2c)
        return ret;
 }
 
-static int nau8821_i2c_remove(struct i2c_client *i2c_client)
-{
-       struct nau8821 *nau8821 = i2c_get_clientdata(i2c_client);
-
-       devm_free_irq(nau8821->dev, nau8821->irq, nau8821);
-
-       return 0;
-}
-
 static const struct i2c_device_id nau8821_i2c_ids[] = {
        { "nau8821", 0 },
        { }
@@ -1703,7 +1758,6 @@ static struct i2c_driver nau8821_driver = {
                .acpi_match_table = ACPI_PTR(nau8821_acpi_match),
        },
        .probe_new = nau8821_i2c_probe,
-       .remove = nau8821_i2c_remove,
        .id_table = nau8821_i2c_ids,
 };
 module_i2c_driver(nau8821_driver);
index a92edfeb9d3aafa975c075682c20f59136bc815d..c44251f54d48134f107736128b68bb9201d37ac7 100644 (file)
@@ -525,6 +525,7 @@ struct nau8821 {
        int jack_eject_debounce;
        int fs;
        int dmic_clk_threshold;
+       int key_enable;
 };
 
 int nau8821_enable_jack_detect(struct snd_soc_component *component,
index 08f6c56dc387f56ec148acaf8be10ca984673901..1aef281a997271d7cb6f488bbfdc65cd45df939b 100644 (file)
@@ -726,6 +726,17 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
        struct nau8822_pll *pll_param = &nau8822->pll;
        int ret, fs;
 
+       if (freq_in == pll_param->freq_in &&
+           freq_out == pll_param->freq_out)
+               return 0;
+
+       if (freq_out == 0) {
+               dev_dbg(component->dev, "PLL disabled\n");
+               snd_soc_component_update_bits(component,
+                       NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF);
+               return 0;
+       }
+
        fs = freq_out / 256;
 
        ret = nau8822_calc_pll(freq_in, fs, pll_param);
@@ -762,6 +773,9 @@ static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
        snd_soc_component_update_bits(component,
                NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_ON);
 
+       pll_param->freq_in = freq_in;
+       pll_param->freq_out = freq_out;
+
        return 0;
 }
 
@@ -1069,7 +1083,6 @@ static const struct snd_soc_component_driver soc_component_dev_nau8822 = {
        .idle_bias_on                   = 1,
        .use_pmdown_time                = 1,
        .endianness                     = 1,
-       .non_legacy_dai_naming          = 1,
 };
 
 static const struct regmap_config nau8822_regmap_config = {
index b45d42c15de6b679926b3184650854c6dd395b93..547ec057f853b38a7250a5714e62002bb9fd6fa8 100644 (file)
@@ -198,6 +198,8 @@ struct nau8822_pll {
        int mclk_scaler;
        int pll_frac;
        int pll_int;
+       int freq_in;
+       int freq_out;
 };
 
 /* Codec Private Data */
index 2a7c935085353986b7e0c0a1e3ab014786f17fb3..ad54d70f7d8e75d4eda4f527548852d60a132363 100644 (file)
@@ -1544,7 +1544,6 @@ static const struct snd_soc_component_driver nau8824_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops nau8824_dai_ops = {
index 20e45a337b8f270b1a18b27b280c21888127228b..54ef7b0fa87860ec7d6199f884dd7a5aa255492c 100644 (file)
@@ -1440,7 +1440,7 @@ static struct snd_soc_dai_driver nau8825_dai = {
        .capture = {
                .stream_name     = "Capture",
                .channels_min    = 1,
-               .channels_max    = 1,
+               .channels_max    = 2,   /* Only 1 channel of data */
                .rates           = NAU8825_RATES,
                .formats         = NAU8825_FORMATS,
        },
@@ -2478,7 +2478,6 @@ static const struct snd_soc_component_driver nau8825_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void nau8825_reset_chip(struct regmap *regmap)
index 20eb04c8a41a00411ff60fc5d9d41398da0aa795..3591f6f53901f3d5be0bbe0051bcc55e55e65a95 100644 (file)
@@ -290,7 +290,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1681 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct i2c_device_id pcm1681_i2c_id[] = {
index 35788b57e11f90912072df579a82379e629abd10..3ab381e9a856662ec58e8ad8e1a817086b56e1f3 100644 (file)
@@ -229,7 +229,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm1789 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int pcm1789_common_init(struct device *dev, struct regmap *regmap)
index ee60373d7d25426bdfa6b2a7acc6c6949dd5c44f..f52ff66b6e644e0c2ccae2aa45c87605822381c0 100644 (file)
@@ -207,7 +207,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm179x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int pcm179x_common_init(struct device *dev, struct regmap *regmap)
index fda9d7ee3fe6bc4606f69c8cfad5fbb5e20e6de4..dd21803ba13cb0256e7665dc8f1f2fea4cc1dad5 100644 (file)
@@ -578,7 +578,6 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
@@ -593,7 +592,6 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static bool pcm186x_volatile(struct device *dev, unsigned int reg)
index aef40ec40aa16b640295454c98d3f4d2fc7d8ca5..09c6c1326833d66dd12c60ff243c9bd9ffda36d9 100644 (file)
@@ -102,7 +102,6 @@ static const struct snd_soc_component_driver soc_component_dev_pcm3008 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int pcm3008_codec_probe(struct platform_device *pdev)
index cf27f05dc46ab30fd0d394621a444e33c89e0fda..9d6431338fb7153cbe47b994a79220dfa5a5561a 100644 (file)
@@ -716,7 +716,6 @@ static const struct snd_soc_component_driver pcm3168a_driver = {
        .num_dapm_routes        = ARRAY_SIZE(pcm3168a_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int pcm3168a_probe(struct device *dev, struct regmap *regmap)
index f39f98bbc97fdca6df036b0a78457fac2d1ab8d9..3401a25341e616e74769c5668a13dfe97fab29e8 100644 (file)
@@ -28,7 +28,6 @@ static struct snd_soc_component_driver soc_component_dev_pcm5102a = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int pcm5102a_probe(struct platform_device *pdev)
index a3ff4a07aff72ed60ade9593cf81887f3e2a1156..767463e82665c920b3a32fce291c15c44c8b901e 100644 (file)
@@ -1512,7 +1512,6 @@ static const struct snd_soc_component_driver pcm512x_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(pcm512x_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_range_cfg pcm512x_range = {
index 86b679cf7aef9f80873ad6306317c59cf9053b5a..1d523bfd9d84f83df2ad7ce1d45d9580224dc007 100644 (file)
@@ -69,11 +69,11 @@ static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                snd_soc_component_get_drvdata(dai->component);
        unsigned int val;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBP_CFP:
                val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;
                break;
        default:
index cce6f4e7992f552f31c1bec749596047c7b79258..2a5b274bfc0f53febe21d34d24c884e6d989386c 100644 (file)
@@ -444,7 +444,6 @@ static const struct snd_soc_component_driver soc_codec_dev_rk817 = {
        .idle_bias_on = 1,
        .use_pmdown_time = 1,
        .endianness = 1,
-       .non_legacy_dai_naming = 1,
        .controls = rk817_volume_controls,
        .num_controls = ARRAY_SIZE(rk817_volume_controls),
        .dapm_routes = rk817_dapm_routes,
index 08dbaef84d4e188d44a31711d3b334056d35c833..c1568216126ef775af88cd1f7bfb2cb57449a81c 100644 (file)
@@ -2176,7 +2176,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1011 = {
        .set_pll = rt1011_set_component_pll,
        .use_pmdown_time = 1,
        .endianness = 1,
-       .non_legacy_dai_naming = 1,
 };
 
 static const struct regmap_config rt1011_regmap = {
index 7a06f2654afb037f52d8760deb7f07ab92f30007..57d0f1c69e46c6f629cf48abdf8251fc4e079dec 100644 (file)
@@ -1071,7 +1071,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1015 = {
        .set_pll = rt1015_set_component_pll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt1015_regmap = {
index 415cfb3b2f0d068b792789ce166fb0fbfe6db09c..06800dad879812a14e9d5a58ba095e5bbc142570 100644 (file)
@@ -89,7 +89,6 @@ static const struct snd_soc_component_driver rt1015p_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver rt1015p_dai_driver = {
index e31c4736627f048e653b01f804c0a3b24fe28373..37eeec650f035b0b3e1f752d466b793c82322b92 100644 (file)
@@ -595,7 +595,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1016 = {
        .set_pll = rt1016_set_component_pll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt1016_regmap = {
index f3f15fbe85d0e92bc773df918b82d4ffd6f1ccf4..b66bfecbb879bafc804f2cd1d46eed942e6a708a 100644 (file)
@@ -522,7 +522,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1019 = {
        .num_dapm_widgets       = ARRAY_SIZE(rt1019_dapm_widgets),
        .dapm_routes            = rt1019_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(rt1019_dapm_routes),
-       .non_legacy_dai_naming  = 1,
        .endianness             = 1,
 };
 
index 58d97e3c5087d4993e64dfe8241c0c9769fdade0..5b39a440b6dc120fcda0a5007cc523faa2f4aebd 100644 (file)
@@ -946,7 +946,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1305 = {
        .set_pll = rt1305_set_component_pll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt1305_regmap = {
index 72f673f278eeccdc47c9554185d47f096281e817..0be6e72ff5a9a97880e2c2adab2aa286298406fb 100644 (file)
@@ -608,7 +608,19 @@ static const struct sdw_slave_ops rt1308_slave_ops = {
        .bus_config = rt1308_bus_config,
 };
 
+static int rt1308_sdw_component_probe(struct snd_soc_component *component)
+{
+       int ret;
+
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
 static const struct snd_soc_component_driver soc_component_sdw_rt1308 = {
+       .probe = rt1308_sdw_component_probe,
        .controls = rt1308_snd_controls,
        .num_controls = ARRAY_SIZE(rt1308_snd_controls),
        .dapm_widgets = rt1308_dapm_widgets,
index eec2b1760408907702b391ee2e16cf4430d8fd4f..d2a8e9fe3e2341748336a5e75bf85331f03cb69b 100644 (file)
@@ -765,7 +765,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt1308 = {
        .set_pll = rt1308_set_component_pll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt1308_regmap = {
index 2d6b5f9d4d77041b2623e63f3c1ec2cac20b1775..e53396606a1c6f8af317dbf2904427137027f9ff 100644 (file)
@@ -590,7 +590,19 @@ static struct sdw_slave_ops rt1316_slave_ops = {
        .update_status = rt1316_update_status,
 };
 
+static int rt1316_sdw_component_probe(struct snd_soc_component *component)
+{
+       int ret;
+
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
 static const struct snd_soc_component_driver soc_component_sdw_rt1316 = {
+       .probe = rt1316_sdw_component_probe,
        .controls = rt1316_snd_controls,
        .num_controls = ARRAY_SIZE(rt1316_snd_controls),
        .dapm_widgets = rt1316_dapm_widgets,
index ab093bdb55523e81a6f9b4dfb6313a35d4943d44..f2c50b11e4d0c734a462fc9a2bf729e0454f1e56 100644 (file)
@@ -980,14 +980,11 @@ static int rt274_probe(struct snd_soc_component *component)
        struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
        rt274->component = component;
+       INIT_DELAYED_WORK(&rt274->jack_detect_work, rt274_jack_detect_work);
 
-       if (rt274->i2c->irq) {
-               INIT_DELAYED_WORK(&rt274->jack_detect_work,
-                                       rt274_jack_detect_work);
+       if (rt274->i2c->irq)
                schedule_delayed_work(&rt274->jack_detect_work,
-                                       msecs_to_jiffies(1250));
-       }
-
+                                     msecs_to_jiffies(1250));
        return 0;
 }
 
@@ -996,6 +993,7 @@ static void rt274_remove(struct snd_soc_component *component)
        struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
 
        cancel_delayed_work_sync(&rt274->jack_detect_work);
+       rt274->component = NULL;
 }
 
 #ifdef CONFIG_PM
@@ -1075,7 +1073,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt274 = {
        .num_dapm_routes        = ARRAY_SIZE(rt274_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt274_regmap = {
index ad8ea1fa7c2322a4b97b978b2204984d0d07804f..c4f7c4c2d7939b15bde36ffc04c4681b6335f41f 100644 (file)
@@ -311,7 +311,8 @@ static void rt286_jack_detect_work(struct work_struct *work)
                SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
 }
 
-int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+static int rt286_mic_detect(struct snd_soc_component *component,
+                           struct snd_soc_jack *jack, void *data)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
        struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
@@ -335,7 +336,6 @@ int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt286_mic_detect);
 
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
@@ -947,17 +947,11 @@ static int rt286_probe(struct snd_soc_component *component)
        struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
        rt286->component = component;
+       INIT_DELAYED_WORK(&rt286->jack_detect_work, rt286_jack_detect_work);
 
-       if (rt286->i2c->irq) {
-               regmap_update_bits(rt286->regmap,
-                                       RT286_IRQ_CTRL, 0x2, 0x2);
-
-               INIT_DELAYED_WORK(&rt286->jack_detect_work,
-                                       rt286_jack_detect_work);
+       if (rt286->i2c->irq)
                schedule_delayed_work(&rt286->jack_detect_work,
-                                       msecs_to_jiffies(1250));
-       }
-
+                                     msecs_to_jiffies(50));
        return 0;
 }
 
@@ -966,6 +960,7 @@ static void rt286_remove(struct snd_soc_component *component)
        struct rt286_priv *rt286 = snd_soc_component_get_drvdata(component);
 
        cancel_delayed_work_sync(&rt286->jack_detect_work);
+       rt286->component = NULL;
 }
 
 #ifdef CONFIG_PM
@@ -1055,6 +1050,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = {
        .suspend                = rt286_suspend,
        .resume                 = rt286_resume,
        .set_bias_level         = rt286_set_bias_level,
+       .set_jack               = rt286_mic_detect,
        .controls               = rt286_snd_controls,
        .num_controls           = ARRAY_SIZE(rt286_snd_controls),
        .dapm_widgets           = rt286_dapm_widgets,
@@ -1063,7 +1059,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt286 = {
        .num_dapm_routes        = ARRAY_SIZE(rt286_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt286_regmap = {
index f27a4e71d5b6fb04e232f7e7ca433c8601da30e8..4b7a3bd6043d76c88faf2df0b0a8ee418f45edea 100644 (file)
@@ -196,7 +196,5 @@ enum {
        RT286_AIFS,
 };
 
-int rt286_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
-
 #endif /* __RT286_H__ */
 
index c291786dc82def3e777841b7f11aaff977f2ba37..b0b53d4f07df91b565c43cc470af063fe1aa8479 100644 (file)
@@ -326,39 +326,37 @@ static void rt298_jack_detect_work(struct work_struct *work)
                SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
 }
 
-int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack)
+static int rt298_mic_detect(struct snd_soc_component *component,
+                           struct snd_soc_jack *jack, void *data)
 {
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
        struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
-       struct snd_soc_dapm_context *dapm;
-       bool hp = false;
-       bool mic = false;
-       int status = 0;
 
-       /* If jack in NULL, disable HS jack */
-       if (!jack) {
+       rt298->jack = jack;
+
+       if (jack) {
+               /* Enable IRQ */
+               if (rt298->jack->status & SND_JACK_HEADPHONE)
+                       snd_soc_dapm_force_enable_pin(dapm, "LDO1");
+               if (rt298->jack->status & SND_JACK_MICROPHONE) {
+                       snd_soc_dapm_force_enable_pin(dapm, "HV");
+                       snd_soc_dapm_force_enable_pin(dapm, "VREF");
+               }
+               regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2);
+               /* Send an initial empty report */
+               snd_soc_jack_report(rt298->jack, rt298->jack->status,
+                                   SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+       } else {
+               /* Disable IRQ */
                regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0);
-               dapm = snd_soc_component_get_dapm(component);
+               snd_soc_dapm_disable_pin(dapm, "HV");
+               snd_soc_dapm_disable_pin(dapm, "VREF");
                snd_soc_dapm_disable_pin(dapm, "LDO1");
-               snd_soc_dapm_sync(dapm);
-               return 0;
        }
-
-       rt298->jack = jack;
-       regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2);
-
-       rt298_jack_detect(rt298, &hp, &mic);
-       if (hp)
-               status |= SND_JACK_HEADPHONE;
-
-       if (mic)
-               status |= SND_JACK_MICROPHONE;
-
-       snd_soc_jack_report(rt298->jack, status,
-               SND_JACK_MICROPHONE | SND_JACK_HEADPHONE);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rt298_mic_detect);
 
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
@@ -1011,17 +1009,11 @@ static int rt298_probe(struct snd_soc_component *component)
        struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
        rt298->component = component;
+       INIT_DELAYED_WORK(&rt298->jack_detect_work, rt298_jack_detect_work);
 
-       if (rt298->i2c->irq) {
-               regmap_update_bits(rt298->regmap,
-                                       RT298_IRQ_CTRL, 0x2, 0x2);
-
-               INIT_DELAYED_WORK(&rt298->jack_detect_work,
-                                       rt298_jack_detect_work);
+       if (rt298->i2c->irq)
                schedule_delayed_work(&rt298->jack_detect_work,
-                                       msecs_to_jiffies(1250));
-       }
-
+                                     msecs_to_jiffies(1250));
        return 0;
 }
 
@@ -1030,6 +1022,7 @@ static void rt298_remove(struct snd_soc_component *component)
        struct rt298_priv *rt298 = snd_soc_component_get_drvdata(component);
 
        cancel_delayed_work_sync(&rt298->jack_detect_work);
+       rt298->component = NULL;
 }
 
 #ifdef CONFIG_PM
@@ -1120,6 +1113,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = {
        .suspend                = rt298_suspend,
        .resume                 = rt298_resume,
        .set_bias_level         = rt298_set_bias_level,
+       .set_jack               = rt298_mic_detect,
        .controls               = rt298_snd_controls,
        .num_controls           = ARRAY_SIZE(rt298_snd_controls),
        .dapm_widgets           = rt298_dapm_widgets,
@@ -1128,7 +1122,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt298 = {
        .num_dapm_routes        = ARRAY_SIZE(rt298_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt298_regmap = {
index ed2b8fd87f4c6ee44f43b5c44032516b5f7613a0..f1be9c13540120ea8441c558635fd72b560ce5e6 100644 (file)
@@ -207,7 +207,5 @@ enum {
        RT298_AIFS,
 };
 
-int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack);
-
 #endif /* __RT298_H__ */
 
index be8ece4630df5c330085c41b799f2d0919671448..b9bcf04d4dc938d5c51cd7f562d73b6d1b776f1c 100644 (file)
@@ -1173,7 +1173,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5514 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5514_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5514_i2c_regmap = {
index 37f1bf552eff49861c5e1021f751c330f898df09..970d6c4a358e01c26e150e3d7f7594f7d6899ecc 100644 (file)
@@ -1304,7 +1304,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5616 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5616_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5616_regmap = {
index c941e878471c16b7274dacea1f859e040d2d99b9..957f6b19beec931ca6d084f3860d0fc6c7adb6a3 100644 (file)
@@ -1666,7 +1666,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5631 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct i2c_device_id rt5631_i2c_id[] = {
index 18b3da9211e325341addd6068931480d92948161..38ab8d4291c2d0bff9b68bf7386ec147b8a883f0 100644 (file)
@@ -2567,10 +2567,18 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
        queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
 }
 
+static const struct snd_soc_dapm_route rt5640_hda_jack_dapm_routes[] = {
+       {"IN1P", NULL, "MICBIAS1"},
+       {"IN2P", NULL, "MICBIAS1"},
+       {"IN3P", NULL, "MICBIAS1"},
+};
+
 static void rt5640_enable_hda_jack_detect(
        struct snd_soc_component *component, struct snd_soc_jack *jack)
 {
        struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
+       struct snd_soc_dapm_context *dapm =
+               snd_soc_component_get_dapm(component);
        int ret;
 
        /* Select JD1 for Mic */
@@ -2609,6 +2617,9 @@ static void rt5640_enable_hda_jack_detect(
 
        /* sync initial jack state */
        queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
+
+       snd_soc_dapm_add_routes(dapm, rt5640_hda_jack_dapm_routes,
+               ARRAY_SIZE(rt5640_hda_jack_dapm_routes));
 }
 
 static int rt5640_set_jack(struct snd_soc_component *component,
@@ -2881,8 +2892,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5640_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
-
 };
 
 static const struct regmap_config rt5640_regmap = {
index 507aba8de3cc9dd348ef4f70b353ff2983e12cc3..8635bc6567dcecae372a120a98925e2dd692e55f 100644 (file)
@@ -3534,7 +3534,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5645_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5645_regmap = {
index d11d201b1d03ef3a470168cc12237d6477b3da33..df90af906563abb330a04aab0ff49aefc1f9ff6f 100644 (file)
@@ -2161,7 +2161,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5651 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5651_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5651_regmap = {
index 6efa90f46362b67d0a575e1d7fcb4bdc717d8271..5e21e3c37ab575f1b872f7a40baceb62980ab7f9 100644 (file)
@@ -3801,7 +3801,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5659 = {
        .set_pll                = rt5659_set_component_pll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 
index d5f9926625d23bd2237854b5ad26a28d0f469df5..341baa29fdb189051ab06fb66ed2610e081b240a 100644 (file)
@@ -1208,7 +1208,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5660 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5660_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5660_regmap = {
index e51eed8a79ab766fb1e3ea5fd8639a9695f6ab8c..ca981b374b0c8538ca450eec114ed9db28008abe 100644 (file)
@@ -3258,7 +3258,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5663 = {
        .set_jack               = rt5663_set_jack_detect,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5663_v2_regmap = {
index 4a8d62e1dd2b59926700691acb5f4d055c44720f..6e66cc218fa8dc981df511357a4644c7334681fa 100644 (file)
@@ -4617,7 +4617,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5665 = {
        .set_jack               = rt5665_set_jack_detect,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 
index 01566f036ca17da2cc14c3fc0fc44831d528c6bd..beb0951ff680bd0d357784ae0388fed1e189cd09 100644 (file)
@@ -2362,7 +2362,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5668 = {
        .set_jack = rt5668_set_jack_detect,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5668_regmap = {
index 8a97f6db04d56c81921325b8863ff0356c34e8cb..60dbfa2a54f1b86a073ec4721016d88c844f315e 100644 (file)
@@ -2852,7 +2852,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5670 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5670_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5670_regmap = {
index 4a8c267d4fbc89031f59bf2e3e52b1cbaa397d82..31a2dd0aafb64f0bca2be5a1eec3d9530e966d50 100644 (file)
@@ -5189,7 +5189,6 @@ static const struct snd_soc_component_driver soc_component_dev_rt5677 = {
        .num_dapm_routes        = ARRAY_SIZE(rt5677_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config rt5677_regmap_physical = {
index 2b6c6d6b9771e09b8e776f0c54db33890b57e543..2df95e792900c621f3ad907818ed29b7bedbfc0f 100644 (file)
@@ -3064,7 +3064,6 @@ const struct snd_soc_component_driver rt5682_soc_component_dev = {
        .set_jack = rt5682_set_jack_detect,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 EXPORT_SYMBOL_GPL(rt5682_soc_component_dev);
 
index 4d44eddee901c658137e76d18e9c0f0a7386c4c5..eb47e7cd485aa11f39528d7b9008e9b4ef9741a9 100644 (file)
@@ -2893,7 +2893,6 @@ static const struct snd_soc_component_driver rt5682s_soc_component_dev = {
        .set_jack = rt5682s_set_jack_detect,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev)
index 9bceeeb830b15a5cb8c66e0b7bdc70b412baf022..055c3ae974d804f603575029b2adf92498783b0a 100644 (file)
@@ -818,9 +818,14 @@ static const struct snd_soc_dapm_route rt700_audio_map[] = {
 static int rt700_probe(struct snd_soc_component *component)
 {
        struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt700->component = component;
 
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
        return 0;
 }
 
index 5ad53bbc852843feaec6b8026c19fe1641b62eaa..9252681219017efbf3d70003918e3664e6030197 100644 (file)
@@ -1194,10 +1194,15 @@ static int rt711_sdca_parse_dt(struct rt711_sdca_priv *rt711, struct device *dev
 static int rt711_sdca_probe(struct snd_soc_component *component)
 {
        struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711_sdca_parse_dt(rt711, &rt711->slave->dev);
        rt711->component = component;
 
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
        return 0;
 }
 
index 9df800abfc2d8ca729e6561850e6e339fe95f083..1bf61808919424fc72a548ebd1d93ebb40aa5241 100644 (file)
@@ -935,10 +935,15 @@ static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev)
 static int rt711_probe(struct snd_soc_component *component)
 {
        struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711_parse_dt(rt711, &rt711->slave->dev);
        rt711->component = component;
 
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
        return 0;
 }
 
index 5857d08663073573e8c8e87931f6729fc31f0aca..ce8bbc76199a888e505da6d922da1bb659ed4a6a 100644 (file)
@@ -758,7 +758,19 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = {
        {"ADC 25 Mux", "DMIC4", "DMIC4"},
 };
 
+static int rt715_sdca_probe(struct snd_soc_component *component)
+{
+       int ret;
+
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
 static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = {
+       .probe = rt715_sdca_probe,
        .controls = rt715_sdca_snd_controls,
        .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls),
        .dapm_widgets = rt715_sdca_dapm_widgets,
index 418e006b19ef5426cfcb8a2dcc1b270827ea7b88..e93240521c74e217b83fdd6275311571f6ce65dd 100644 (file)
@@ -737,7 +737,19 @@ static int rt715_set_bias_level(struct snd_soc_component *component,
        return 0;
 }
 
+static int rt715_probe(struct snd_soc_component *component)
+{
+       int ret;
+
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
 static const struct snd_soc_component_driver soc_codec_dev_rt715 = {
+       .probe = rt715_probe,
        .set_bias_level = rt715_set_bias_level,
        .controls = rt715_snd_controls,
        .num_controls = ARRAY_SIZE(rt715_snd_controls),
index 3363d1696ad7cbe5955f73fd7b520f716685a8eb..3fafd9fc5cfd61bdc3159b68db0c450dc32bd08d 100644 (file)
@@ -1536,7 +1536,6 @@ static const struct snd_soc_component_driver sgtl5000_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config sgtl5000_regmap = {
index 8bd2edf70f137604b0718e69b67cfb3c46bdf852..d87141ba84388c5037949df1699ab04446c6bbf4 100644 (file)
@@ -239,7 +239,6 @@ static const struct snd_soc_component_driver soc_component_dev_si476x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int si476x_platform_probe(struct platform_device *pdev)
index 276db978e5871ff5c29841eb5bb2154faba2fc24..862e0b654a1c2aff79b2f19326ace40a4b91d957 100644 (file)
@@ -43,7 +43,6 @@ static struct snd_soc_component_driver soc_codec_spdif_dir = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver dir_stub_dai = {
index 2c8cebfc66031e4b3e0a44f0f21bcb02495479c1..73651892155586d1e616c7ea11ae1aa496c44b7c 100644 (file)
@@ -43,7 +43,6 @@ static struct snd_soc_component_driver soc_codec_spdif_dit = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver dit_stub_dai = {
index 83acbdbb8e0dabf11632229776b28a877a3b7618..6d8847848299003a95b1a8813185fef3eabdddca 100644 (file)
@@ -409,8 +409,8 @@ static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        bool invert_fclk;
        int ret;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -721,7 +721,6 @@ static const struct snd_soc_component_driver ssm2518_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(ssm2518_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ssm2518_regmap_config = {
index 7964e922b07f6532363a721ca2dfd284de65b3e2..cbbe83b85adafbff2a8ccf84c4732591dd8dbece 100644 (file)
@@ -411,11 +411,11 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
        unsigned int iface = 0;
 
        /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                iface |= 0x0040;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -624,7 +624,6 @@ static const struct snd_soc_component_driver soc_component_dev_ssm2602 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
index 08ced09ef001d02529adf67ca6fd67be907240c9..4b0265617c7b53bdb3158808a018432cd7a9bc20 100644 (file)
@@ -278,8 +278,8 @@ static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        unsigned int ctrl1 = 0;
        bool invert_fclk;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -427,7 +427,6 @@ static const struct snd_soc_component_driver ssm4567_component_driver = {
        .num_dapm_routes        = ARRAY_SIZE(ssm4567_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config ssm4567_regmap_config = {
index 8585cbef4c9be7510aba45c40594085f6b764fe2..8c86b578eba8312a59fe5f811ba191b2378dca2c 100644 (file)
@@ -601,8 +601,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        struct sta32x_priv *sta32x = snd_soc_component_get_drvdata(component);
        u8 confb = 0;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -1014,7 +1014,6 @@ static const struct snd_soc_component_driver sta32x_component = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config sta32x_regmap = {
index 9189fb3648f7d8507edcec3a1303f58e9284e354..7b2c5b57d5d4529ad98cd0f595abe4ab4e177ef5 100644 (file)
@@ -630,8 +630,8 @@ static int sta350_set_dai_fmt(struct snd_soc_dai *codec_dai,
        struct sta350_priv *sta350 = snd_soc_component_get_drvdata(component);
        unsigned int confb = 0;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -1057,7 +1057,6 @@ static const struct snd_soc_component_driver sta350_component = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config sta350_regmap = {
index d90e5512a73175135fa8983203f22ef6f0a8ce05..3139570991454573ad55f4adbd807f0e5d78bf85 100644 (file)
@@ -322,7 +322,6 @@ static const struct snd_soc_component_driver sta529_component_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config sta529_regmap = {
index d99f6e466d0a3b43df92268bcdeeb8c36c853164..1824a71fe053d1a2fdfc6c119f327370e434a5f3 100644 (file)
@@ -313,8 +313,6 @@ static const struct snd_soc_component_driver soc_component_dev_stac9766 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
-
 };
 
 static int stac9766_probe(struct platform_device *pdev)
index 3be4940e3c77d3d8b82fc6959b76a0324d243439..f076878908eec5ec1f07e18fce715a8441edd09b 100644 (file)
@@ -199,10 +199,10 @@ static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
 static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
                                 unsigned int fmt)
 {
-       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
                dev_err(dai->component->dev,
-                       "%s: ERROR: Unsupporter master mask 0x%x\n",
-                       __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
+                       "%s: ERROR: Unsupported clocking mask 0x%x\n",
+                       __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
                return -EINVAL;
        }
 
@@ -398,7 +398,6 @@ static struct snd_soc_component_driver sti_sas_driver = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id sti_sas_dev_match[] = {
index b5c9c61ff5a8e4cbb35f12899fe9aeb1689b5dd3..8bd667da876725944fcce9cc74a1d42dc5a2e516 100644 (file)
@@ -347,17 +347,17 @@ static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct tas2552_data *tas2552 = dev_get_drvdata(component->dev);
        u8 serial_format;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                serial_format = 0x00;
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_CBC_CFP:
                serial_format = TAS2552_WCLKDIR;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBP_CFC:
                serial_format = TAS2552_BCLKDIR;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBP_CFP:
                serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
                break;
        default:
@@ -581,7 +581,7 @@ static int tas2552_component_probe(struct snd_soc_component *component)
 
        gpiod_set_value(tas2552->enable_gpio, 1);
 
-       ret = pm_runtime_get_sync(component->dev);
+       ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                dev_err(component->dev, "Enabling device failed: %d\n",
                        ret);
@@ -668,7 +668,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2552 = {
        .num_dapm_routes        = ARRAY_SIZE(tas2552_audio_map),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config tas2552_regmap_config = {
index e62a3da16aed31ae9556f4981f1d6ca550772b35..dc088a1c67213173ffe3f76752f37fe129b129c8 100644 (file)
@@ -589,7 +589,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2110 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = {
@@ -629,7 +628,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas2562 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = {
index 4cb788f3e5f710b6b16d2527293731609c1812f4..846d9d3ecc9de1136ae3f5e25d5e5a041e9bbb4c 100644 (file)
@@ -558,7 +558,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2764 = {
        .num_dapm_routes        = ARRAY_SIZE(tas2764_audio_map),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct reg_default tas2764_reg_defaults[] = {
index c1dbd978d550230d483740d42a6f1270c632e672..3cb634c2826103252ce04a00554be9794e631b82 100644 (file)
@@ -340,11 +340,11 @@ static int tas2770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
        int ret;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
-               dev_err(tas2770->dev, "ASI format master is not found\n");
+               dev_err(tas2770->dev, "ASI invalid DAI clocking\n");
                return -EINVAL;
        }
 
@@ -546,7 +546,6 @@ static const struct snd_soc_component_driver soc_component_driver_tas2770 = {
        .num_dapm_routes        = ARRAY_SIZE(tas2770_audio_map),
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int tas2770_register_codec(struct tas2770_priv *tas2770)
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
new file mode 100644 (file)
index 0000000..a6db6f0
--- /dev/null
@@ -0,0 +1,663 @@
+// SPDX-License-Identifier: GPL-2.0
+// Driver for the Texas Instruments TAS2780 Mono
+//             Audio amplifier
+// Copyright (C) 2022 Texas Instruments Inc.
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include "tas2780.h"
+
+struct tas2780_priv {
+       struct snd_soc_component *component;
+       struct gpio_desc *reset_gpio;
+       struct regmap *regmap;
+       struct device *dev;
+       int v_sense_slot;
+       int i_sense_slot;
+};
+
+static void tas2780_reset(struct tas2780_priv *tas2780)
+{
+       int ret = 0;
+
+       if (tas2780->reset_gpio) {
+               gpiod_set_value_cansleep(tas2780->reset_gpio, 0);
+               usleep_range(2000, 2050);
+               gpiod_set_value_cansleep(tas2780->reset_gpio, 1);
+               usleep_range(2000, 2050);
+       }
+
+       snd_soc_component_write(tas2780->component, TAS2780_SW_RST,
+                               TAS2780_RST);
+       if (ret)
+               dev_err(tas2780->dev, "%s:errCode:0x%x Reset error!\n",
+                       __func__, ret);
+}
+
+#ifdef CONFIG_PM
+static int tas2780_codec_suspend(struct snd_soc_component *component)
+{
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL,
+               TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_SHUTDOWN);
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%0x:power down error\n",
+                       __func__, ret);
+               goto err;
+       }
+       ret = 0;
+       regcache_cache_only(tas2780->regmap, true);
+       regcache_mark_dirty(tas2780->regmap);
+err:
+       return ret;
+}
+
+static int tas2780_codec_resume(struct snd_soc_component *component)
+{
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL,
+               TAS2780_PWR_CTRL_MASK, TAS2780_PWR_CTRL_ACTIVE);
+
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%0x:power down error\n",
+                       __func__, ret);
+               goto err;
+       }
+       ret = 0;
+       regcache_cache_only(tas2780->regmap, false);
+       ret = regcache_sync(tas2780->regmap);
+err:
+       return ret;
+}
+#endif
+
+static const char * const tas2780_ASI1_src[] = {
+       "I2C offset", "Left", "Right", "LeftRightDiv2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       tas2780_ASI1_src_enum, TAS2780_TDM_CFG2, 4, tas2780_ASI1_src);
+
+static const struct snd_kcontrol_new tas2780_asi1_mux =
+       SOC_DAPM_ENUM("ASI1 Source", tas2780_ASI1_src_enum);
+
+static const struct snd_kcontrol_new isense_switch =
+       SOC_DAPM_SINGLE("Switch", TAS2780_PWR_CTRL,
+                       TAS2780_ISENSE_POWER_EN, 1, 1);
+static const struct snd_kcontrol_new vsense_switch =
+       SOC_DAPM_SINGLE("Switch", TAS2780_PWR_CTRL,
+                       TAS2780_VSENSE_POWER_EN, 1, 1);
+
+static const struct snd_soc_dapm_widget tas2780_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2780_asi1_mux),
+       SND_SOC_DAPM_SWITCH("ISENSE", TAS2780_PWR_CTRL,
+               TAS2780_ISENSE_POWER_EN, 1, &isense_switch),
+       SND_SOC_DAPM_SWITCH("VSENSE", TAS2780_PWR_CTRL,
+               TAS2780_VSENSE_POWER_EN, 1, &vsense_switch),
+       SND_SOC_DAPM_OUTPUT("OUT"),
+       SND_SOC_DAPM_SIGGEN("VMON"),
+       SND_SOC_DAPM_SIGGEN("IMON")
+};
+
+static const struct snd_soc_dapm_route tas2780_audio_map[] = {
+       {"ASI1 Sel", "I2C offset", "ASI1"},
+       {"ASI1 Sel", "Left", "ASI1"},
+       {"ASI1 Sel", "Right", "ASI1"},
+       {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
+       {"OUT", NULL, "ASI1 Sel"},
+       {"ISENSE", "Switch", "IMON"},
+       {"VSENSE", "Switch", "VMON"},
+};
+
+static int tas2780_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+       struct snd_soc_component *component = dai->component;
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       ret = snd_soc_component_update_bits(component, TAS2780_PWR_CTRL,
+               TAS2780_PWR_CTRL_MASK,
+               mute ? TAS2780_PWR_CTRL_MUTE : 0);
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s: Failed to set powercontrol\n",
+                       __func__);
+               goto err;
+       }
+       ret = 0;
+err:
+       return ret;
+}
+
+static int tas2780_set_bitwidth(struct tas2780_priv *tas2780, int bitwidth)
+{
+       struct snd_soc_component *component = tas2780->component;
+       int sense_en;
+       int val;
+       int ret;
+       int slot_size;
+
+       switch (bitwidth) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               ret = snd_soc_component_update_bits(component,
+                       TAS2780_TDM_CFG2,
+                       TAS2780_TDM_CFG2_RXW_MASK,
+                       TAS2780_TDM_CFG2_RXW_16BITS);
+               slot_size = TAS2780_TDM_CFG2_RXS_16BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               ret = snd_soc_component_update_bits(component,
+                       TAS2780_TDM_CFG2,
+                       TAS2780_TDM_CFG2_RXW_MASK,
+                       TAS2780_TDM_CFG2_RXW_24BITS);
+               slot_size = TAS2780_TDM_CFG2_RXS_24BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               ret = snd_soc_component_update_bits(component,
+                       TAS2780_TDM_CFG2,
+                       TAS2780_TDM_CFG2_RXW_MASK,
+                       TAS2780_TDM_CFG2_RXW_32BITS);
+               slot_size = TAS2780_TDM_CFG2_RXS_32BITS;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%x set bitwidth error\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2,
+               TAS2780_TDM_CFG2_RXS_MASK, slot_size);
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x set RX slot size error\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       val = snd_soc_component_read(tas2780->component, TAS2780_PWR_CTRL);
+       if (val < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%x read PWR_CTRL error\n",
+                       __func__, val);
+               ret = val;
+               goto err;
+       }
+
+       if (val & (1 << TAS2780_VSENSE_POWER_EN))
+               sense_en = 0;
+       else
+               sense_en = TAS2780_TDM_CFG5_VSNS_ENABLE;
+
+       ret = snd_soc_component_update_bits(tas2780->component,
+               TAS2780_TDM_CFG5, TAS2780_TDM_CFG5_VSNS_ENABLE, sense_en);
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%x enable vSNS error\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       if (val & (1 << TAS2780_ISENSE_POWER_EN))
+               sense_en = 0;
+       else
+               sense_en = TAS2780_TDM_CFG6_ISNS_ENABLE;
+
+       ret = snd_soc_component_update_bits(tas2780->component,
+               TAS2780_TDM_CFG6, TAS2780_TDM_CFG6_ISNS_ENABLE, sense_en);
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%x enable iSNS error\n",
+                       __func__, ret);
+               goto err;
+       }
+       ret = 0;
+err:
+       return ret;
+}
+
+static int tas2780_set_samplerate(
+       struct tas2780_priv *tas2780, int samplerate)
+{
+       struct snd_soc_component *component = tas2780->component;
+       int ramp_rate_val;
+       int ret;
+
+       switch (samplerate) {
+       case 48000:
+               ramp_rate_val = TAS2780_TDM_CFG0_SMP_48KHZ |
+                               TAS2780_TDM_CFG0_44_1_48KHZ;
+               break;
+       case 44100:
+               ramp_rate_val = TAS2780_TDM_CFG0_SMP_44_1KHZ |
+                               TAS2780_TDM_CFG0_44_1_48KHZ;
+               break;
+       case 96000:
+               ramp_rate_val = TAS2780_TDM_CFG0_SMP_48KHZ |
+                               TAS2780_TDM_CFG0_88_2_96KHZ;
+               break;
+       case 88200:
+               ramp_rate_val = TAS2780_TDM_CFG0_SMP_44_1KHZ |
+                               TAS2780_TDM_CFG0_88_2_96KHZ;
+               break;
+       default:
+               return -EINVAL;
+       }
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG0,
+               TAS2780_TDM_CFG0_SMP_MASK | TAS2780_TDM_CFG0_MASK,
+               ramp_rate_val);
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set ramp_rate_val\n",
+                       __func__, ret);
+               goto err;
+       }
+       ret = 0;
+err:
+       return ret;
+}
+
+static int tas2780_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       int ret;
+
+       ret = tas2780_set_bitwidth(tas2780, params_format(params));
+       if (ret < 0)
+               return ret;
+
+       return tas2780_set_samplerate(tas2780, params_rate(params));
+}
+
+static int tas2780_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_component *component = dai->component;
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
+       int iface;
+       int ret = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               asi_cfg_1 = TAS2780_TDM_CFG1_RX_RISING;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               asi_cfg_1 = TAS2780_TDM_CFG1_RX_FALLING;
+               break;
+       default:
+               dev_err(tas2780->dev, "ASI format Inverse is not found\n");
+               return -EINVAL;
+       }
+
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG1,
+               TAS2780_TDM_CFG1_RX_MASK, asi_cfg_1);
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set asi_cfg_1\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
+               || ((fmt & SND_SOC_DAIFMT_FORMAT_MASK)
+               == SND_SOC_DAIFMT_DSP_A)){
+               iface = TAS2780_TDM_CFG2_SCFG_I2S;
+               tdm_rx_start_slot = 1;
+       } else {
+               if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK)
+                       == SND_SOC_DAIFMT_DSP_B)
+                       || ((fmt & SND_SOC_DAIFMT_FORMAT_MASK)
+                       == SND_SOC_DAIFMT_LEFT_J)) {
+                       iface = TAS2780_TDM_CFG2_SCFG_LEFT_J;
+                       tdm_rx_start_slot = 0;
+               } else {
+                       dev_err(tas2780->dev,
+                               "%s:DAI Format is not found, fmt=0x%x\n",
+                               __func__, fmt);
+                       ret = -EINVAL;
+                       goto err;
+               }
+       }
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG1,
+               TAS2780_TDM_CFG1_MASK,
+               (tdm_rx_start_slot << TAS2780_TDM_CFG1_51_SHIFT));
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set tdm_rx_start_slot\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2,
+               TAS2780_TDM_CFG2_SCFG_MASK, iface);
+       if (ret < 0) {
+               dev_err(tas2780->dev, "%s:errCode:0x%x Failed to set iface\n",
+                       __func__, ret);
+               goto err;
+       }
+       ret = 0;
+err:
+       return ret;
+}
+
+static int tas2780_set_dai_tdm_slot(struct snd_soc_dai *dai,
+                               unsigned int tx_mask,
+                               unsigned int rx_mask,
+                               int slots, int slot_width)
+{
+       struct snd_soc_component *component = dai->component;
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       int left_slot, right_slot;
+       int slots_cfg;
+       int slot_size;
+       int ret = 0;
+
+       if (tx_mask == 0 || rx_mask != 0)
+               return -EINVAL;
+
+       if (slots == 1) {
+               if (tx_mask != 1)
+                       return -EINVAL;
+               left_slot = 0;
+               right_slot = 0;
+       } else {
+               left_slot = __ffs(tx_mask);
+               tx_mask &= ~(1 << left_slot);
+               if (tx_mask == 0) {
+                       right_slot = left_slot;
+               } else {
+                       right_slot = __ffs(tx_mask);
+                       tx_mask &= ~(1 << right_slot);
+               }
+       }
+
+       if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
+               return -EINVAL;
+
+       slots_cfg = (right_slot << TAS2780_TDM_CFG3_RXS_SHIFT) | left_slot;
+       ret = snd_soc_component_write(component, TAS2780_TDM_CFG3, slots_cfg);
+       if (ret) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set slots_cfg\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       switch (slot_width) {
+       case 16:
+               slot_size = TAS2780_TDM_CFG2_RXS_16BITS;
+               break;
+       case 24:
+               slot_size = TAS2780_TDM_CFG2_RXS_24BITS;
+               break;
+       case 32:
+               slot_size = TAS2780_TDM_CFG2_RXS_32BITS;
+               break;
+       default:
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG2,
+               TAS2780_TDM_CFG2_RXS_MASK, slot_size);
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set slot_size\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG5,
+               TAS2780_TDM_CFG5_50_MASK, tas2780->v_sense_slot);
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set v_sense_slot\n",
+                       __func__, ret);
+               goto err;
+       }
+
+       ret = snd_soc_component_update_bits(component, TAS2780_TDM_CFG6,
+               TAS2780_TDM_CFG6_50_MASK, tas2780->i_sense_slot);
+       if (ret < 0) {
+               dev_err(tas2780->dev,
+                       "%s:errCode:0x%x Failed to set i_sense_slot\n",
+                       __func__, ret);
+               goto err;
+       }
+       ret = 0;
+err:
+       return ret;
+}
+
+static const struct snd_soc_dai_ops tas2780_dai_ops = {
+       .mute_stream = tas2780_mute,
+       .hw_params  = tas2780_hw_params,
+       .set_fmt    = tas2780_set_fmt,
+       .set_tdm_slot = tas2780_set_dai_tdm_slot,
+       .no_capture_mute = 1,
+};
+
+#define TAS2780_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define TAS2780_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+                      SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
+
+static struct snd_soc_dai_driver tas2780_dai_driver[] = {
+       {
+               .name = "tas2780 ASI1",
+               .id = 0,
+               .playback = {
+                       .stream_name    = "ASI1 Playback",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates      = TAS2780_RATES,
+                       .formats    = TAS2780_FORMATS,
+               },
+               .capture = {
+                       .stream_name    = "ASI1 Capture",
+                       .channels_min   = 1,
+                       .channels_max   = 2,
+                       .rates = TAS2780_RATES,
+                       .formats = TAS2780_FORMATS,
+               },
+               .ops = &tas2780_dai_ops,
+               .symmetric_rate = 1,
+       },
+};
+
+static int tas2780_codec_probe(struct snd_soc_component *component)
+{
+       struct tas2780_priv *tas2780 =
+               snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       tas2780->component = component;
+
+       tas2780_reset(tas2780);
+       ret = snd_soc_component_update_bits(component,
+                       TAS2780_IC_CFG, TAS2780_IC_CFG_MASK,
+                       TAS2780_IC_CFG_ENABLE);
+       if (ret < 0)
+               dev_err(tas2780->dev, "%s:errCode:0x%0x\n",
+                       __func__, ret);
+
+       return ret;
+}
+
+static DECLARE_TLV_DB_SCALE(tas2780_digital_tlv, 1100, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2780_playback_volume, -10000, 50, 0);
+
+static const struct snd_kcontrol_new tas2780_snd_controls[] = {
+       SOC_SINGLE_TLV("Speaker Volume", TAS2780_DVC, 0,
+                      TAS2780_DVC_MAX, 1, tas2780_playback_volume),
+       SOC_SINGLE_TLV("Amp Gain Volume", TAS2780_CHNL_0, 0, 0x14, 0,
+                      tas2780_digital_tlv),
+};
+
+static const struct snd_soc_component_driver soc_component_driver_tas2780 = {
+       .probe                  = tas2780_codec_probe,
+#ifdef CONFIG_PM
+       .suspend                = tas2780_codec_suspend,
+       .resume                 = tas2780_codec_resume,
+#endif
+       .controls               = tas2780_snd_controls,
+       .num_controls           = ARRAY_SIZE(tas2780_snd_controls),
+       .dapm_widgets           = tas2780_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(tas2780_dapm_widgets),
+       .dapm_routes            = tas2780_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(tas2780_audio_map),
+       .idle_bias_on           = 1,
+       .endianness             = 1,
+};
+
+static const struct reg_default tas2780_reg_defaults[] = {
+       { TAS2780_PAGE, 0x00 },
+       { TAS2780_SW_RST, 0x00 },
+       { TAS2780_PWR_CTRL, 0x1a },
+       { TAS2780_DVC, 0x00 },
+       { TAS2780_CHNL_0, 0x00 },
+       { TAS2780_TDM_CFG0, 0x09 },
+       { TAS2780_TDM_CFG1, 0x02 },
+       { TAS2780_TDM_CFG2, 0x0a },
+       { TAS2780_TDM_CFG3, 0x10 },
+       { TAS2780_TDM_CFG5, 0x42 },
+};
+
+static const struct regmap_range_cfg tas2780_regmap_ranges[] = {
+       {
+               .range_min = 0,
+               .range_max = 1 * 128,
+               .selector_reg = TAS2780_PAGE,
+               .selector_mask = 0xff,
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = 128,
+       },
+};
+
+static const struct regmap_config tas2780_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .reg_defaults = tas2780_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(tas2780_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+       .ranges = tas2780_regmap_ranges,
+       .num_ranges = ARRAY_SIZE(tas2780_regmap_ranges),
+       .max_register = 1 * 128,
+};
+
+static int tas2780_parse_dt(struct device *dev, struct tas2780_priv *tas2780)
+{
+       int ret = 0;
+
+       tas2780->reset_gpio = devm_gpiod_get_optional(tas2780->dev, "reset",
+               GPIOD_OUT_HIGH);
+       if (IS_ERR(tas2780->reset_gpio)) {
+               if (PTR_ERR(tas2780->reset_gpio) == -EPROBE_DEFER) {
+                       tas2780->reset_gpio = NULL;
+                       return -EPROBE_DEFER;
+               }
+       }
+
+       ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
+               &tas2780->i_sense_slot);
+       if (ret)
+               tas2780->i_sense_slot = 0;
+
+       ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
+               &tas2780->v_sense_slot);
+       if (ret)
+               tas2780->v_sense_slot = 2;
+
+       return 0;
+}
+
+static int tas2780_i2c_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct tas2780_priv *tas2780;
+       int result;
+
+       tas2780 = devm_kzalloc(&client->dev, sizeof(struct tas2780_priv),
+               GFP_KERNEL);
+       if (!tas2780)
+               return -ENOMEM;
+       tas2780->dev = &client->dev;
+       i2c_set_clientdata(client, tas2780);
+       dev_set_drvdata(&client->dev, tas2780);
+
+       tas2780->regmap = devm_regmap_init_i2c(client, &tas2780_i2c_regmap);
+       if (IS_ERR(tas2780->regmap)) {
+               result = PTR_ERR(tas2780->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       result);
+               return result;
+       }
+
+       if (client->dev.of_node) {
+               result = tas2780_parse_dt(&client->dev, tas2780);
+               if (result) {
+                       dev_err(tas2780->dev,
+                               "%s: Failed to parse devicetree\n", __func__);
+                       return result;
+               }
+       }
+
+       return devm_snd_soc_register_component(tas2780->dev,
+               &soc_component_driver_tas2780, tas2780_dai_driver,
+               ARRAY_SIZE(tas2780_dai_driver));
+}
+
+static const struct i2c_device_id tas2780_i2c_id[] = {
+       { "tas2780", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tas2780_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tas2780_of_match[] = {
+       { .compatible = "ti,tas2780" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tas2780_of_match);
+#endif
+
+static struct i2c_driver tas2780_i2c_driver = {
+       .driver = {
+               .name   = "tas2780",
+               .of_match_table = of_match_ptr(tas2780_of_match),
+       },
+       .probe  = tas2780_i2c_probe,
+       .id_table   = tas2780_i2c_id,
+};
+module_i2c_driver(tas2780_i2c_driver);
+
+MODULE_AUTHOR("Raphael Xu <raphael-xu@ti.com>");
+MODULE_DESCRIPTION("TAS2780 I2C Smart Amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas2780.h b/sound/soc/codecs/tas2780.h
new file mode 100644 (file)
index 0000000..661c25d
--- /dev/null
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * TAS2780.h - ALSA SoC Texas Instruments TAS2780 Mono Audio Amplifier
+ *
+ * Copyright (C) 2020-2022 Texas Instruments Incorporated - https://www.ti.com
+ *
+ * Author: Raphael Xu <raphael-xu@ti.com>
+ */
+
+#ifndef __TAS2780_H__
+#define __TAS2780_H__
+
+/* Book Control Register */
+#define TAS2780_BOOKCTL_PAGE   0
+#define TAS2780_BOOKCTL_REG    127
+#define TAS2780_REG(page, reg) ((page * 128) + reg)
+
+/* Page */
+#define TAS2780_PAGE           TAS2780_REG(0X0, 0x00)
+#define TAS2780_PAGE_PAGE_MASK 255
+
+/* Software Reset */
+#define TAS2780_SW_RST TAS2780_REG(0X0, 0x01)
+#define TAS2780_RST    BIT(0)
+
+/* Power Control */
+#define TAS2780_PWR_CTRL               TAS2780_REG(0X0, 0x02)
+#define TAS2780_PWR_CTRL_MASK          GENMASK(1, 0)
+#define TAS2780_PWR_CTRL_ACTIVE                0x0
+#define TAS2780_PWR_CTRL_MUTE          BIT(0)
+#define TAS2780_PWR_CTRL_SHUTDOWN      BIT(1)
+
+#define TAS2780_VSENSE_POWER_EN                3
+#define TAS2780_ISENSE_POWER_EN                4
+
+/* Digital Volume Control */
+#define TAS2780_DVC    TAS2780_REG(0X0, 0x1a)
+#define TAS2780_DVC_MAX        0xc9
+
+#define TAS2780_CHNL_0  TAS2780_REG(0X0, 0x03)
+
+/* TDM Configuration Reg0 */
+#define TAS2780_TDM_CFG0               TAS2780_REG(0X0, 0x08)
+#define TAS2780_TDM_CFG0_SMP_MASK      BIT(5)
+#define TAS2780_TDM_CFG0_SMP_48KHZ     0x0
+#define TAS2780_TDM_CFG0_SMP_44_1KHZ   BIT(5)
+#define TAS2780_TDM_CFG0_MASK          GENMASK(3, 1)
+#define TAS2780_TDM_CFG0_44_1_48KHZ    BIT(3)
+#define TAS2780_TDM_CFG0_88_2_96KHZ    (BIT(3) | BIT(1))
+
+/* TDM Configuration Reg1 */
+#define TAS2780_TDM_CFG1               TAS2780_REG(0X0, 0x09)
+#define TAS2780_TDM_CFG1_MASK          GENMASK(5, 1)
+#define TAS2780_TDM_CFG1_51_SHIFT      1
+#define TAS2780_TDM_CFG1_RX_MASK       BIT(0)
+#define TAS2780_TDM_CFG1_RX_RISING     0x0
+#define TAS2780_TDM_CFG1_RX_FALLING    BIT(0)
+
+/* TDM Configuration Reg2 */
+#define TAS2780_TDM_CFG2               TAS2780_REG(0X0, 0x0a)
+#define TAS2780_TDM_CFG2_RXW_MASK      GENMASK(3, 2)
+#define TAS2780_TDM_CFG2_RXW_16BITS    0x0
+#define TAS2780_TDM_CFG2_RXW_24BITS    BIT(3)
+#define TAS2780_TDM_CFG2_RXW_32BITS    (BIT(3) | BIT(2))
+#define TAS2780_TDM_CFG2_RXS_MASK      GENMASK(1, 0)
+#define TAS2780_TDM_CFG2_RXS_16BITS    0x0
+#define TAS2780_TDM_CFG2_RXS_24BITS    BIT(0)
+#define TAS2780_TDM_CFG2_RXS_32BITS    BIT(1)
+#define TAS2780_TDM_CFG2_SCFG_MASK     GENMASK(5, 4)
+#define TAS2780_TDM_CFG2_SCFG_I2S      0x0
+#define TAS2780_TDM_CFG2_SCFG_LEFT_J   BIT(4)
+#define TAS2780_TDM_CFG2_SCFG_RIGHT_J  BIT(5)
+
+/* TDM Configuration Reg3 */
+#define TAS2780_TDM_CFG3               TAS2780_REG(0X0, 0x0c)
+#define TAS2780_TDM_CFG3_RXS_MASK      GENMASK(7, 4)
+#define TAS2780_TDM_CFG3_RXS_SHIFT     0x4
+#define TAS2780_TDM_CFG3_MASK          GENMASK(3, 0)
+
+/* TDM Configuration Reg4 */
+#define TAS2780_TDM_CFG4               TAS2780_REG(0X0, 0x0d)
+#define TAS2780_TDM_CFG4_TX_OFFSET_MASK        GENMASK(3, 1)
+
+/* TDM Configuration Reg5 */
+#define TAS2780_TDM_CFG5               TAS2780_REG(0X0, 0x0e)
+#define TAS2780_TDM_CFG5_VSNS_MASK     BIT(6)
+#define TAS2780_TDM_CFG5_VSNS_ENABLE   BIT(6)
+#define TAS2780_TDM_CFG5_50_MASK       GENMASK(5, 0)
+
+/* TDM Configuration Reg6 */
+#define TAS2780_TDM_CFG6               TAS2780_REG(0X0, 0x0f)
+#define TAS2780_TDM_CFG6_ISNS_MASK     BIT(6)
+#define TAS2780_TDM_CFG6_ISNS_ENABLE   BIT(6)
+#define TAS2780_TDM_CFG6_50_MASK       GENMASK(5, 0)
+
+/* IC CFG */
+#define TAS2780_IC_CFG                 TAS2780_REG(0X0, 0x5c)
+#define TAS2780_IC_CFG_MASK            GENMASK(7, 6)
+#define TAS2780_IC_CFG_ENABLE          (BIT(7) | BIT(6))
+
+#endif /* __TAS2780_H__ */
index 5c0df3cd48320deb56a2272fec5aa4e8367af301..a864984225bc46c86914f75d14403939015480c3 100644 (file)
@@ -318,7 +318,7 @@ static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
        struct tas5086_private *priv = snd_soc_component_get_drvdata(component);
 
        /* The TAS5086 can only be slave to all clocks */
-       if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+       if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
                dev_err(component->dev, "Invalid clocking mode\n");
                return -EINVAL;
        }
@@ -888,7 +888,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5086 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct i2c_device_id tas5086_i2c_id[] = {
index 7b599664db205fe5ff83120e26215920dfcd26be..4e7f20db57c4dda92678fa358528cf63a6eef4ab 100644 (file)
@@ -756,7 +756,6 @@ static const struct snd_soc_component_driver tas571x_component = {
        .num_dapm_routes        = ARRAY_SIZE(tas571x_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver tas571x_dai = {
index 17034abef5689f2b338398220e627e9dfc314b84..3885c0bf0b01c1dbfee527f460d3359aade6778f 100644 (file)
@@ -89,8 +89,8 @@ static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        u8 serial_format;
        int ret;
 
-       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
-               dev_vdbg(component->dev, "DAI Format master is not found\n");
+       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
+               dev_vdbg(component->dev, "DAI clocking invalid\n");
                return -EINVAL;
        }
 
@@ -572,7 +572,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
@@ -589,7 +588,6 @@ static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /* PCM rates supported by the TAS5720 driver */
index fa0e81ec875ad3c5b5584860e9b5f7e6aed1a77a..b1bb614534f7437860ecf4b825e6e1b64c4c2ffe 100644 (file)
@@ -367,7 +367,6 @@ static const struct snd_soc_component_driver soc_codec_dev_tas5805m = {
        .num_dapm_routes        = ARRAY_SIZE(tas5805m_audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction)
index 22b53856e6918d9403d5573d064071e97cfb4749..63d2983c3fcf4dd64839f8f07d8caf8a0f46ca00 100644 (file)
@@ -160,11 +160,11 @@ static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        dev_dbg(component->dev, "%s() fmt=0x%0x\n", __func__, fmt);
 
        /* clock masters */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
-               dev_err(component->dev, "Invalid DAI master/slave interface\n");
+               dev_err(component->dev, "Invalid DAI clocking\n");
                return -EINVAL;
        }
 
@@ -375,7 +375,6 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = {
        .num_dapm_routes        = ARRAY_SIZE(tas6424_audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
index 3d8e8c2276f086e9c4f31fc31918c7b0149145a1..9f7902ec40db42794fb73a7af6682798234bd690 100644 (file)
@@ -111,8 +111,8 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        int i2s_set;
        int sck_pol;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
                return -EINVAL;
@@ -235,7 +235,6 @@ static const struct snd_soc_component_driver tfa9879_component = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config tfa9879_regmap = {
index dc86852752c50959370c0e99f368a0f05d000494..1c27429b9af646d61daa4f81f4dcfe3d1a67fae8 100644 (file)
 #define TFA989X_I2S_SEL_REG            0x0a
 #define TFA989X_I2S_SEL_REG_SPKR_MSK   GENMASK(10, 9)  /* speaker impedance */
 #define TFA989X_I2S_SEL_REG_DCFG_MSK   GENMASK(14, 11) /* DCDC compensation */
+#define TFA989X_HIDE_UNHIDE_KEY        0x40
 #define TFA989X_PWM_CONTROL            0x41
 #define TFA989X_CURRENTSENSE1          0x46
 #define TFA989X_CURRENTSENSE2          0x47
 #define TFA989X_CURRENTSENSE3          0x48
 #define TFA989X_CURRENTSENSE4          0x49
 
+#define TFA9890_REVISION               0x80
 #define TFA9895_REVISION               0x12
 #define TFA9897_REVISION               0x97
 
@@ -136,7 +138,6 @@ static const struct snd_soc_component_driver tfa989x_component = {
        .num_dapm_routes        = ARRAY_SIZE(tfa989x_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const unsigned int tfa989x_rates[] = {
@@ -188,6 +189,33 @@ static struct snd_soc_dai_driver tfa989x_dai = {
        .ops = &tfa989x_dai_ops,
 };
 
+static int tfa9890_init(struct regmap *regmap)
+{
+       int ret;
+
+       /* unhide keys to allow updating them */
+       ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x5a6b);
+       if (ret)
+               return ret;
+
+       /* update PLL registers */
+       ret = regmap_set_bits(regmap, 0x59, 0x3);
+       if (ret)
+               return ret;
+
+       /* hide keys again */
+       ret = regmap_write(regmap, TFA989X_HIDE_UNHIDE_KEY, 0x0000);
+       if (ret)
+               return ret;
+
+       return regmap_write(regmap, TFA989X_CURRENTSENSE2, 0x7BE1);
+}
+
+static const struct tfa989x_rev tfa9890_rev = {
+       .rev    = TFA9890_REVISION,
+       .init   = tfa9890_init,
+};
+
 static const struct reg_sequence tfa9895_reg_init[] = {
        /* some other registers must be set for optimal amplifier behaviour */
        { TFA989X_BAT_PROT, 0x13ab },
@@ -376,6 +404,7 @@ static int tfa989x_i2c_probe(struct i2c_client *i2c)
 }
 
 static const struct of_device_id tfa989x_of_match[] = {
+       { .compatible = "nxp,tfa9890", .data = &tfa9890_rev },
        { .compatible = "nxp,tfa9895", .data = &tfa9895_rev },
        { .compatible = "nxp,tfa9897", .data = &tfa9897_rev },
        { }
index 82532ad00c3c82ea7cc0fab5e625d3d5c98638bd..748998e48af97abebb3d417ff8d57b1af64798c7 100644 (file)
@@ -1252,8 +1252,7 @@ static int adc3xxx_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        int master = 0;
        int ret;
 
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
        case SND_SOC_DAIFMT_CBP_CFP:
                master = 1;
                clkdir = ADC3XXX_BCLK_MASTER | ADC3XXX_WCLK_MASTER;
index 0b729658fde80dc795f4d714e4b0656323f51b3f..2844a9d2bc4a03776d687c623a9302f117fd1f03 100644 (file)
@@ -712,16 +712,14 @@ static int adcx140_set_dai_fmt(struct snd_soc_dai *codec_dai,
        bool inverted_bclk = false;
 
        /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                iface_reg2 |= ADCX140_BCLK_FSYNC_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
-       case SND_SOC_DAIFMT_CBM_CFS:
        default:
-               dev_err(component->dev, "Invalid DAI master/slave interface\n");
+               dev_err(component->dev, "Invalid DAI clock provider\n");
                return -EINVAL;
        }
 
@@ -1054,7 +1052,6 @@ static const struct snd_soc_component_driver soc_codec_driver_adcx140 = {
        .idle_bias_on           = 0,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver adcx140_dai_driver[] = {
index 2400093e2c9909cc7cffa5e3d845fae9bbac87ca..c47aa4d4162dd5aaf4bf05d22d78ffde1c909721 100644 (file)
@@ -429,12 +429,11 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
        iface_reg = snd_soc_component_read(component, TLV320AIC23_DIGT_FMT) & (~0x03);
 
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                iface_reg |= TLV320AIC23_MS_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                iface_reg &= ~TLV320AIC23_MS_MASTER;
                break;
        default:
@@ -587,7 +586,6 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320aic23 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
index 077415a572255ec5a96546c384d1b9dfd6987c4b..8bae4b47506880ed66db7753985eb25bc5641ff7 100644 (file)
@@ -32,7 +32,7 @@ struct aic26 {
        struct spi_device *spi;
        struct regmap *regmap;
        struct snd_soc_component *component;
-       int master;
+       int clock_provider;
        int datfm;
        int mclk;
 
@@ -117,8 +117,8 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
        reg = dval << 2;
        snd_soc_component_write(component, AIC26_REG_PLL_PROG2, reg);
 
-       /* Audio Control 3 (master mode, fsref rate) */
-       if (aic26->master)
+       /* Audio Control 3 (clock provider mode, fsref rate) */
+       if (aic26->clock_provider)
                reg = 0x0800;
        if (fsref == 48000)
                reg = 0x2000;
@@ -178,10 +178,9 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
                codec_dai, fmt);
 
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
-       case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP: aic26->clock_provider = 1; break;
+       case SND_SOC_DAIFMT_CBC_CFC: aic26->clock_provider = 0; break;
        default:
                dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
        }
@@ -332,7 +331,6 @@ static const struct snd_soc_component_driver aic26_soc_component_dev = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config aic26_regmap = {
@@ -363,7 +361,7 @@ static int aic26_spi_probe(struct spi_device *spi)
        /* Initialize the driver data */
        aic26->spi = spi;
        dev_set_drvdata(&spi->dev, aic26);
-       aic26->master = 1;
+       aic26->clock_provider = 1;
 
        ret = devm_snd_soc_register_component(&spi->dev,
                        &aic26_soc_component_dev, &aic26_dai, 1);
index b2e59581c17a27b1c50ec88f03d433de520047ad..0847302121f6ec9c2879cfdac031ceb2fb7214c3 100644 (file)
@@ -1033,8 +1033,8 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component,
        struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
        int ret;
 
-       fmt &= SND_SOC_DAIFMT_MASTER_MASK;
-       if (fmt == SND_SOC_DAIFMT_CBS_CFS &&
+       fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
+       if (fmt == SND_SOC_DAIFMT_CBC_CFC &&
            aic31xx->master_dapm_route_applied) {
                /*
                 * Remove the DAPM route(s) for codec clock master modes,
@@ -1051,7 +1051,7 @@ static int aic31xx_clock_master_routes(struct snd_soc_component *component,
                        return ret;
 
                aic31xx->master_dapm_route_applied = false;
-       } else if (fmt != SND_SOC_DAIFMT_CBS_CFS &&
+       } else if (fmt != SND_SOC_DAIFMT_CBC_CFC &&
                   !aic31xx->master_dapm_route_applied) {
                /*
                 * Add the needed DAPM route(s) for codec clock master modes,
@@ -1083,21 +1083,20 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
        dev_dbg(component->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
 
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_CBC_CFP:
                iface_reg1 |= AIC31XX_WCLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBP_CFC:
                iface_reg1 |= AIC31XX_BCLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
-               dev_err(component->dev, "Invalid DAI master/slave interface\n");
+               dev_err(component->dev, "Invalid DAI clock provider\n");
                return -EINVAL;
        }
 
@@ -1418,7 +1417,6 @@ static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops aic31xx_dai_ops = {
index 8f42fd7bc05392e2b777e516a6093b1515680b66..4b74805cdd2e5aae517e8a082d8e8aebab3d8157 100644 (file)
@@ -615,15 +615,14 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        u8 iface_reg_2 = 0;
        u8 iface_reg_3 = 0;
 
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
-               printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
+               printk(KERN_ERR "aic32x4: invalid clock provider\n");
                return -EINVAL;
        }
 
@@ -1078,7 +1077,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
@@ -1200,7 +1198,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 =
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
index d53037b1509d0969dca2b46f3db7b495e29721b1..08938801daec26e4b1adcb1a8147e31e8ef0439d 100644 (file)
@@ -1253,22 +1253,21 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        iface_areg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLA) & 0x3f;
        iface_breg = snd_soc_component_read(component, AIC3X_ASD_INTF_CTRLB) & 0x3f;
 
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                aic3x->master = 1;
                iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_CBC_CFC:
                aic3x->master = 0;
                iface_areg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_CBP_CFC:
                aic3x->master = 1;
                iface_areg |= BIT_CLK_MASTER;
                iface_areg &= ~WORD_CLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_CBC_CFP:
                aic3x->master = 1;
                iface_areg |= WORD_CLK_MASTER;
                iface_areg &= ~BIT_CLK_MASTER;
@@ -1698,7 +1697,6 @@ static const struct snd_soc_component_driver soc_component_dev_aic3x = {
        .num_dapm_routes        = ARRAY_SIZE(intercon),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x)
index 66f1d1cd6cf005ef3b00a73ac07fa1593b271215..17ae3b1d96fb4964542235e06fba5908d4c88f6f 100644 (file)
@@ -1317,16 +1317,14 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
        aictrl_a = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_A);
        aictrl_b = dac33_read_reg_cache(component, DAC33_SER_AUDIOIF_CTRL_B);
-       /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               /* Codec Master */
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBP_CFP:
                aictrl_a |= (DAC33_MSBCLK | DAC33_MSWCLK);
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               /* Codec Slave */
+       case SND_SOC_DAIFMT_CBC_CFC:
                if (dac33->fifo_mode) {
-                       dev_err(component->dev, "FIFO mode requires master mode\n");
+                       dev_err(component->dev, "FIFO mode requires provider mode\n");
                        return -EINVAL;
                } else
                        aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
@@ -1433,7 +1431,6 @@ static const struct snd_soc_component_driver soc_component_dev_tlv320dac33 = {
        .num_dapm_routes        = ARRAY_SIZE(audio_map),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #define DAC33_RATES    (SNDRV_PCM_RATE_44100 | \
index 4fb0bb01bcdc0cbc23a62cf7589472e18a0dc0a4..fa0c525189c203376ef34b969ae3009b74fcdb22 100644 (file)
@@ -1358,7 +1358,6 @@ static const struct snd_soc_component_driver soc_codec_dev_tscs42xx = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static inline void init_coeff_ram_cache(struct tscs42xx *tscs42xx)
index 0ba3546ef8708e0950a1f69c152104a3d5d6c03e..e48768233e208f3430c24893458dce90f3285811 100644 (file)
 
 #define TWL4030_CACHEREGNUM    (TWL4030_REG_MISC_SET_2 + 1)
 
+struct twl4030_board_params {
+       unsigned int digimic_delay; /* in ms */
+       unsigned int ramp_delay_value;
+       unsigned int offset_cncl_path;
+       unsigned int hs_extmute:1;
+       int hs_extmute_gpio;
+};
+
 /* codec private data */
 struct twl4030_priv {
        unsigned int codec_powered;
@@ -58,7 +66,7 @@ struct twl4030_priv {
        u8 carkitl_enabled, carkitr_enabled;
        u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1];
 
-       struct twl4030_codec_data *pdata;
+       struct twl4030_board_params *board_params;
 };
 
 static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030)
@@ -193,73 +201,71 @@ static void twl4030_codec_enable(struct snd_soc_component *component, int enable
        udelay(10);
 }
 
-static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
-                                  struct device_node *node)
+static void
+twl4030_get_board_param_values(struct twl4030_board_params *board_params,
+                              struct device_node *node)
 {
        int value;
 
-       of_property_read_u32(node, "ti,digimic_delay",
-                            &pdata->digimic_delay);
-       of_property_read_u32(node, "ti,ramp_delay_value",
-                            &pdata->ramp_delay_value);
-       of_property_read_u32(node, "ti,offset_cncl_path",
-                            &pdata->offset_cncl_path);
+       of_property_read_u32(node, "ti,digimic_delay", &board_params->digimic_delay);
+       of_property_read_u32(node, "ti,ramp_delay_value", &board_params->ramp_delay_value);
+       of_property_read_u32(node, "ti,offset_cncl_path", &board_params->offset_cncl_path);
        if (!of_property_read_u32(node, "ti,hs_extmute", &value))
-               pdata->hs_extmute = value;
+               board_params->hs_extmute = value;
 
-       pdata->hs_extmute_gpio = of_get_named_gpio(node,
-                                                  "ti,hs_extmute_gpio", 0);
-       if (gpio_is_valid(pdata->hs_extmute_gpio))
-               pdata->hs_extmute = 1;
+       board_params->hs_extmute_gpio = of_get_named_gpio(node, "ti,hs_extmute_gpio", 0);
+       if (gpio_is_valid(board_params->hs_extmute_gpio))
+               board_params->hs_extmute = 1;
 }
 
-static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_component *component)
+static struct twl4030_board_params*
+twl4030_get_board_params(struct snd_soc_component *component)
 {
-       struct twl4030_codec_data *pdata = dev_get_platdata(component->dev);
+       struct twl4030_board_params *board_params = NULL;
        struct device_node *twl4030_codec_node = NULL;
 
        twl4030_codec_node = of_get_child_by_name(component->dev->parent->of_node,
                                                  "codec");
 
-       if (!pdata && twl4030_codec_node) {
-               pdata = devm_kzalloc(component->dev,
-                                    sizeof(struct twl4030_codec_data),
-                                    GFP_KERNEL);
-               if (!pdata) {
+       if (twl4030_codec_node) {
+               board_params = devm_kzalloc(component->dev,
+                                           sizeof(struct twl4030_board_params),
+                                           GFP_KERNEL);
+               if (!board_params) {
                        of_node_put(twl4030_codec_node);
                        return NULL;
                }
-               twl4030_setup_pdata_of(pdata, twl4030_codec_node);
+               twl4030_get_board_param_values(board_params, twl4030_codec_node);
                of_node_put(twl4030_codec_node);
        }
 
-       return pdata;
+       return board_params;
 }
 
 static void twl4030_init_chip(struct snd_soc_component *component)
 {
-       struct twl4030_codec_data *pdata;
+       struct twl4030_board_params *board_params;
        struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
        u8 reg, byte;
        int i = 0;
 
-       pdata = twl4030_get_pdata(component);
+       board_params = twl4030_get_board_params(component);
 
-       if (pdata && pdata->hs_extmute) {
-               if (gpio_is_valid(pdata->hs_extmute_gpio)) {
+       if (board_params && board_params->hs_extmute) {
+               if (gpio_is_valid(board_params->hs_extmute_gpio)) {
                        int ret;
 
-                       if (!pdata->hs_extmute_gpio)
+                       if (!board_params->hs_extmute_gpio)
                                dev_warn(component->dev,
                                        "Extmute GPIO is 0 is this correct?\n");
 
-                       ret = gpio_request_one(pdata->hs_extmute_gpio,
+                       ret = gpio_request_one(board_params->hs_extmute_gpio,
                                               GPIOF_OUT_INIT_LOW,
                                               "hs_extmute");
                        if (ret) {
                                dev_err(component->dev,
                                        "Failed to get hs_extmute GPIO\n");
-                               pdata->hs_extmute_gpio = -1;
+                               board_params->hs_extmute_gpio = -1;
                        }
                } else {
                        u8 pin_mux;
@@ -290,14 +296,14 @@ static void twl4030_init_chip(struct snd_soc_component *component)
        twl4030_write(component, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
 
        /* Machine dependent setup */
-       if (!pdata)
+       if (!board_params)
                return;
 
-       twl4030->pdata = pdata;
+       twl4030->board_params = board_params;
 
        reg = twl4030_read(component, TWL4030_REG_HS_POPN_SET);
        reg &= ~TWL4030_RAMP_DELAY;
-       reg |= (pdata->ramp_delay_value << 2);
+       reg |= (board_params->ramp_delay_value << 2);
        twl4030_write(component, TWL4030_REG_HS_POPN_SET, reg);
 
        /* initiate offset cancellation */
@@ -305,7 +311,7 @@ static void twl4030_init_chip(struct snd_soc_component *component)
 
        reg = twl4030_read(component, TWL4030_REG_ANAMICL);
        reg &= ~TWL4030_OFFSET_CNCL_SEL;
-       reg |= pdata->offset_cncl_path;
+       reg |= board_params->offset_cncl_path;
        twl4030_write(component, TWL4030_REG_ANAMICL,
                      reg | TWL4030_CNCL_OFFSET_START);
 
@@ -692,7 +698,7 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
 {
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
-       struct twl4030_codec_data *pdata = twl4030->pdata;
+       struct twl4030_board_params *board_params = twl4030->board_params;
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
        unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
                                    8388608, 16777216, 33554432, 67108864};
@@ -705,9 +711,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
 
        /* Enable external mute control, this dramatically reduces
         * the pop-noise */
-       if (pdata && pdata->hs_extmute) {
-               if (gpio_is_valid(pdata->hs_extmute_gpio)) {
-                       gpio_set_value(pdata->hs_extmute_gpio, 1);
+       if (board_params && board_params->hs_extmute) {
+               if (gpio_is_valid(board_params->hs_extmute_gpio)) {
+                       gpio_set_value(board_params->hs_extmute_gpio, 1);
                } else {
                        hs_pop |= TWL4030_EXTMUTE;
                        twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -741,9 +747,9 @@ static void headset_ramp(struct snd_soc_component *component, int ramp)
        }
 
        /* Disable external mute */
-       if (pdata && pdata->hs_extmute) {
-               if (gpio_is_valid(pdata->hs_extmute_gpio)) {
-                       gpio_set_value(pdata->hs_extmute_gpio, 0);
+       if (board_params && board_params->hs_extmute) {
+               if (gpio_is_valid(board_params->hs_extmute_gpio)) {
+                       gpio_set_value(board_params->hs_extmute_gpio, 0);
                } else {
                        hs_pop &= ~TWL4030_EXTMUTE;
                        twl4030_write(component, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -806,10 +812,10 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
-       struct twl4030_codec_data *pdata = twl4030->pdata;
+       struct twl4030_board_params *board_params = twl4030->board_params;
 
-       if (pdata && pdata->digimic_delay)
-               twl4030_wait_ms(pdata->digimic_delay);
+       if (board_params && board_params->digimic_delay)
+               twl4030_wait_ms(board_params->digimic_delay);
        return 0;
 }
 
@@ -2168,10 +2174,11 @@ static int twl4030_soc_probe(struct snd_soc_component *component)
 static void twl4030_soc_remove(struct snd_soc_component *component)
 {
        struct twl4030_priv *twl4030 = snd_soc_component_get_drvdata(component);
-       struct twl4030_codec_data *pdata = twl4030->pdata;
+       struct twl4030_board_params *board_params = twl4030->board_params;
 
-       if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
-               gpio_free(pdata->hs_extmute_gpio);
+       if (board_params && board_params->hs_extmute &&
+           gpio_is_valid(board_params->hs_extmute_gpio))
+               gpio_free(board_params->hs_extmute_gpio);
 }
 
 static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
@@ -2188,7 +2195,6 @@ static const struct snd_soc_component_driver soc_component_dev_twl4030 = {
        .num_dapm_routes        = ARRAY_SIZE(intercon),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int twl4030_codec_probe(struct platform_device *pdev)
index b37203336c4e0a92dd7bf656d4440dae89e179da..dd5ee5dc0cd75833af8a4076522fdc728a61baa3 100644 (file)
@@ -1153,7 +1153,6 @@ static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
        .suspend_bias_off       = 1,
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int twl6040_codec_probe(struct platform_device *pdev)
index 8670a2a05a560c5b5454a02a77a57106d90cbbf1..eace965336003469117d50e3f21e3d4addd68f44 100644 (file)
@@ -169,7 +169,7 @@ static int uda1334_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int uda1334_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
-               SND_SOC_DAIFMT_MASTER_MASK);
+               SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
 
        if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                    SND_SOC_DAIFMT_CBC_CFC)) {
@@ -236,7 +236,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda1334 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id uda1334_of_match[] = {
index 037833c509f70073ea334d00d089fec93d0c56ad..2db3d8a60c7a0cc23827262248812a8d79731321 100644 (file)
@@ -527,7 +527,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda134x = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config uda134x_regmap_config = {
index b5004842520bffdc8abc922bf39032a56ec057ce..fdaaee845176e72395f9ce3c74becbd865eed8d8 100644 (file)
@@ -736,7 +736,6 @@ static const struct snd_soc_component_driver soc_component_dev_uda1380 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int uda1380_i2c_probe(struct i2c_client *i2c)
index c53c2ef33e1a2ba29a2248ce816928613f99d08a..98baef594bf31688e7855c2276f78e6a11609d82 100644 (file)
@@ -714,12 +714,11 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
        struct snd_soc_component *component = mbhc->component;
        int ret;
 
-       ret = pm_runtime_get_sync(component->dev);
+       ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0 && ret != -EACCES) {
                dev_err_ratelimited(component->dev,
-                                   "pm_runtime_get_sync failed in %s, ret %d\n",
+                                   "pm_runtime_resume_and_get failed in %s, ret %d\n",
                                    __func__, ret);
-               pm_runtime_put_noidle(component->dev);
                return ret;
        }
 
@@ -1097,12 +1096,11 @@ static void wcd_correct_swch_plug(struct work_struct *work)
        mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
        component = mbhc->component;
 
-       ret = pm_runtime_get_sync(component->dev);
+       ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0 && ret != -EACCES) {
                dev_err_ratelimited(component->dev,
-                                   "pm_runtime_get_sync failed in %s, ret %d\n",
+                                   "pm_runtime_resume_and_get failed in %s, ret %d\n",
                                    __func__, ret);
-               pm_runtime_put_noidle(component->dev);
                return;
        }
        micbias_mv = wcd_mbhc_get_micbias(mbhc);
@@ -1306,7 +1304,7 @@ exit:
 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
 {
        struct wcd_mbhc *mbhc = data;
-       u8 clamp_state = 0;
+       u8 clamp_state;
        u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
 
        /*
index 3cb7a3eab8c74be63e1cd49d08c985c2011dec58..beeeb35e803215517cb90a1112325b3819a242b0 100644 (file)
@@ -24,6 +24,8 @@
 #include "wcd9335.h"
 #include "wcd-clsh-v2.h"
 
+#include <dt-bindings/sound/qcom,wcd9335.h>
+
 #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
                            SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
                            SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
@@ -203,17 +205,6 @@ enum wcd9335_sido_voltage {
        SIDO_VOLTAGE_NOMINAL_MV = 1100,
 };
 
-enum {
-       AIF1_PB = 0,
-       AIF1_CAP,
-       AIF2_PB,
-       AIF2_CAP,
-       AIF3_PB,
-       AIF3_CAP,
-       AIF4_PB,
-       NUM_CODEC_DAIS,
-};
-
 enum {
        COMPANDER_1, /* HPH_L */
        COMPANDER_2, /* HPH_R */
@@ -1818,11 +1809,11 @@ static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai,
                        tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0;
                        shift = (tx_port << 1);
                        shift_val = 0x03;
-               } else if ((tx_port >= 4) && (tx_port < 8)) {
+               } else if (tx_port < 8) {
                        tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1;
                        shift = ((tx_port - 4) << 1);
                        shift_val = 0x03;
-               } else if ((tx_port >= 8) && (tx_port < 11)) {
+               } else if (tx_port < 11) {
                        tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2;
                        shift = ((tx_port - 8) << 1);
                        shift_val = 0x03;
@@ -2264,51 +2255,42 @@ static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc,
 
 static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
        /* -84dB min - 40dB max */
-       SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
-               0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
-                         WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
-                         WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
-                         WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
-                         WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
-                         WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume",
-                         WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume",
-                         WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
-                         WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
-                         WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
-                         0, -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX0 Mix Digital Volume", WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX1 Mix Digital Volume", WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX2 Mix Digital Volume", WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX3 Mix Digital Volume", WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX4 Mix Digital Volume", WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX5 Mix Digital Volume", WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX6 Mix Digital Volume", WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX7 Mix Digital Volume", WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
+       SOC_SINGLE_S8_TLV("RX8 Mix Digital Volume", WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
+                       -84, 40, digital_gain),
        SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
        SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
        SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
index 02232f64110e0581f7dad3e9bc6b2615ea8e7427..626278e4c92380600f62837cb0930b217bd15307 100644 (file)
@@ -475,7 +475,6 @@ static const struct snd_soc_component_driver soc_component_dev_wl1273 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wl1273_platform_probe(struct platform_device *pdev)
index 1bef1c500c8e32a114b18a6345a5b28a954d6632..034a4e858c7e6d2e962782fbb94a539b366d7692 100644 (file)
@@ -789,7 +789,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm0010 = {
        .num_dapm_routes        = ARRAY_SIZE(wm0010_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
index b6366dea15a6724ddec32611ac6f7d0418c3bf03..98343626078b6e3c48f881f9d2f4789861adafd1 100644 (file)
@@ -144,7 +144,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm1250_ev1 = {
        .set_bias_level         = wm1250_ev1_set_bias_level,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm1250_ev1_pdata(struct i2c_client *i2c)
index ede5f2a982a63cbabf410dfe6394aa5ada23862c..14b4fd97488c8358568bea9fea965714db4520b8 100644 (file)
@@ -803,7 +803,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm2000 = {
        .num_dapm_routes        = ARRAY_SIZE(wm2000_audio_map),
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm2000_i2c_probe(struct i2c_client *i2c)
index 1cd544580c83272d5a32e3478164e9d31d839d67..7b4e162a298c0dd03e5e6be9b137c2c274127481 100644 (file)
@@ -2104,7 +2104,6 @@ static const struct snd_soc_component_driver soc_component_wm2200 = {
        .dapm_routes            = wm2200_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(wm2200_dapm_routes),
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static irqreturn_t wm2200_irq(int irq, void *data)
index a89870918174b57ca9f6991b32fc563e9b200f84..35a85ce6b4648f9c5bb9d00cf72fcdb9ae6ff1b8 100644 (file)
@@ -2389,7 +2389,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5100 = {
        .num_dapm_routes        = ARRAY_SIZE(wm5100_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm5100_regmap = {
index b034df47a5ef1cff7b0d6181a8207256497e2451..af7d324e335258909354e15918d4531876bb7c78 100644 (file)
@@ -2028,7 +2028,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = {
        .num_dapm_routes        = ARRAY_SIZE(wm5102_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm5102_probe(struct platform_device *pdev)
index 4ab7a672f8de8b336ddbd9f302298771523c4f34..f3f4a10bf0f7c82c3a3f28103f07b20f6c54871e 100644 (file)
@@ -2385,7 +2385,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = {
        .num_dapm_routes        = ARRAY_SIZE(wm5110_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm5110_probe(struct platform_device *pdev)
index 41504ce2a682f630cdedf2199966585402d58a69..66bd281095e1c92facc5a7cbf45b30d4de2f9946 100644 (file)
@@ -1613,7 +1613,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8350_probe(struct platform_device *pdev)
index bf5e77c86aed659b202ce8faac7af7f65faafb74..19ce839f6ef7cedcada122025c72347b39b2d74e 100644 (file)
@@ -1322,7 +1322,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8400 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8400_probe(struct platform_device *pdev)
index c6439d25006bf58cf1509c291ed044b67ec296d8..e13f9780a111bdac0386e390144c249cb5cdeb83 100644 (file)
@@ -592,7 +592,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8510 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8510_of_match[] = {
index ba35a0221dc847359c78b2caac158c0d1b116f0c..66f6371d8acfa7348ab7a7915a42a5649defaf77 100644 (file)
@@ -422,7 +422,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8523 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8523_of_match[] = {
index 81f858f6bd6768ecacaea3f506090df65dd60f96..b56dcac602448bb8a9aa6935554af461af7d0747 100644 (file)
@@ -203,7 +203,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8524 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8524_of_match[] = {
index 84020195314d94212e0f405ff6fdd8952f6e66a4..ca796aa0aeb79187a8cc91721f4ccf32a9be2ab1 100644 (file)
@@ -966,7 +966,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8580 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8580_regmap = {
index b68a1ebcd0617d9effa40939a8b1eb6613cb4a25..383c6796e8a39d4b871c5584b5ca180fe10d06de 100644 (file)
@@ -378,7 +378,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8711 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8711_of_match[] = {
index 1a118b75b5398b6f6cf7bb7e91bd11fad5387a4c..d6b0a570dd87ca50384a4b18e2975d8e1edc12cc 100644 (file)
@@ -55,7 +55,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8727 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8727_probe(struct platform_device *pdev)
index 119ff0a1bb35c34364bf7aa7484d32535987b7e0..a3dbdbf40723eb1903c1b967141d42aecf5fc37f 100644 (file)
@@ -221,7 +221,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8728 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8728_of_match[] = {
index 2408c4a591d550f6160d4dd810fe16eaadaa70d9..d5ab3ba126a6b5a1519064ed841f09aefc0fbc23 100644 (file)
@@ -561,7 +561,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8731 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 int wm8731_init(struct device *dev, struct wm8731_priv *wm8731)
index 5778091d1c09f51d900b90e3f16f219b479fcf6c..90b54343370c46e85a7cb5fb39b477cc4d37d6e2 100644 (file)
@@ -583,7 +583,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8737 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8737_of_match[] = {
index 871e2c5421b86b5d35564926529329c92eb7c92e..c7afa4f2795d852efa8f4f009b1a64717d8116f2 100644 (file)
@@ -528,7 +528,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8741 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8741_of_match[] = {
index 1426fc1f7c5ac13fb12637694603cbc9feda701d..2f6ee8d6639f80ff2849b43408521fa821f54a25 100644 (file)
@@ -719,7 +719,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8750 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8750_of_match[] = {
index 931134d334ecacb6c14fb65dd46d7c85e3f87807..bb18f58dc670fa6bba770bb83a2a4ae57f225d6b 100644 (file)
@@ -1492,7 +1492,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8753 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8753_of_match[] = {
index 5f394065030d27ceaeed4efb0d0e3eeafc6e600f..e03fee8869c371995a6bfe67a6b4ab94315eb202 100644 (file)
@@ -617,7 +617,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8770 = {
        .num_dapm_routes        = ARRAY_SIZE(wm8770_intercon),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8770_of_match[] = {
index f164cb6744c49339f8ff2edccb8f3ff6749cd384..936ea24621b0d080f59d7338cd8c897f58b62cdc 100644 (file)
@@ -436,7 +436,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8776 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct of_device_id wm8776_of_match[] = {
index f89855c616ebe6e62efdb421af1361da6b24217d..95ff4339d103b5044f38a5e544050c591e649cf3 100644 (file)
@@ -99,7 +99,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8782 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8782_probe(struct platform_device *pdev)
index 21bf0cfa1e7e7ca625394d084d34a287a795b6e8..0b234bae480e117b515721fa71005c9cc8883083 100644 (file)
@@ -546,7 +546,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8804 = {
        .num_dapm_routes        = ARRAY_SIZE(wm8804_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 const struct regmap_config wm8804_regmap_config = {
index 84a3daf0c11e3c62d0add24214abfea73642f470..d6420df3505d524ffc8b7a655f69662d3b8a97c0 100644 (file)
@@ -1214,7 +1214,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8900 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8900_regmap = {
index 3c95c2aea5152c8a8f9546eb08c97c3fad71e378..54e0a7628cd57b1cff1e967058a2212c723d298a 100644 (file)
@@ -1893,7 +1893,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8903 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8903_regmap = {
index 04bb8e3924977f61c43120db53e3b981ba866c73..ca6a01a230af4a6ca056a033cd682b8547b61578 100644 (file)
@@ -2131,7 +2131,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8904 = {
        .set_bias_level         = wm8904_set_bias_level,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8904_regmap = {
index 589394d420ced9fb985eee698e6f993aeadec1b8..8dac9fd88547059d40524d166ebf0a92c80d323c 100644 (file)
@@ -734,7 +734,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8940 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8940_regmap = {
index 80e3cbd704ee0386c20efd6a177e3a97c4178d13..05ef45672ebc70368dc9274490a79fc6538abe7d 100644 (file)
@@ -952,7 +952,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8955 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8955_regmap = {
index 8c8f32b230838ffb62fa52983bb4ae0a630ab17e..37956516d9976a13cac0f6a71914d42dfa79c4ea 100644 (file)
@@ -1378,7 +1378,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8960 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8960_regmap = {
index 69eb731dbf4bb60818c1d7f05ca5f08329d4f197..7dc6aaf65576792df5990e9f2bd12f9547a3ea6e 100644 (file)
@@ -895,7 +895,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8961 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8961_regmap = {
index 5cca89364280ade53577b4e1a4942b522893b0fa..398c448ea8540de5f8a5911414f42dd657312bb6 100644 (file)
@@ -3502,7 +3502,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8962 = {
        .set_pll                = wm8962_set_fll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /* Improve power consumption for IN4 DC measurement mode */
index 8a289b048e66d3c839b4d0664ae07a19a810f6ea..4db9248de54ba6004e68a9f12c2c29d70c1185fe 100644 (file)
@@ -659,7 +659,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8971 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8971_regmap = {
index a8d7809f3f64b93ecd3e2bc03f494dd32d7a17f0..010a394c705c1cf5dc02c7190167f1868f18ead4 100644 (file)
@@ -682,7 +682,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8974 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8974_i2c_probe(struct i2c_client *i2c)
index 141f50bfec68a1ffb37a87ec3cce965cd5eb0862..a682f8020eb6d3d10e296b5987b6816a6ff7a694 100644 (file)
@@ -1005,7 +1005,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8978 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8978_regmap_config = {
index ae89554d47bc9f9e9a2622593f1d04162fe9196a..50e6ac6ccbe03a0cd2bec0494bc9b77004e13732 100644 (file)
@@ -987,7 +987,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8983 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8983_regmap = {
index cf2c32eac773a70e90baedc03c558256b0531505..751aa67308337e01d019f0dbc864b5a7edf1134e 100644 (file)
@@ -1116,7 +1116,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8985 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8985_regmap = {
index 27538d6598cf14438788e79c784f1a02fd019da6..5dbdf647cd9788160001596a5c6a8b45ee1cb4c0 100644 (file)
@@ -823,7 +823,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8988 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8988_regmap = {
index c9448a59c872fdfd0e1c2b9765dd49ff955a6e30..589af286f133fd1a5ecc9c45ef834988bc3e1336 100644 (file)
@@ -1217,7 +1217,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8990 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8990_i2c_probe(struct i2c_client *i2c)
index 998bc89bb7e1268adb1d0ec4c799abe6547c537c..30121993b7b4ff1bd3dd5b545557a6529501e9db 100644 (file)
@@ -1243,7 +1243,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8991 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8991_regmap = {
index f4da77ec9d6c24f94508993036705023ea564484..8db98b5a06bf4c6214802a17358cbd229fe6a6bb 100644 (file)
@@ -1621,7 +1621,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8993 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8993_i2c_probe(struct i2c_client *i2c)
index f117ec0c489f03af6f5d20bee93f8ff7a68cad09..d3cfd3788f2ab019e65463ce8febaccd287c6d9c 100644 (file)
@@ -4614,7 +4614,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8994 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8994_probe(struct platform_device *pdev)
index ea9727446707d645d940a40e6f77a4293077759a..eed48bf339f249c0ce1a754b8940815fc5ccaa2b 100644 (file)
@@ -2182,7 +2182,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8995 = {
        .num_dapm_routes        = ARRAY_SIZE(wm8995_intercon),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm8995_regmap = {
index f7bb27d1c76d0f3c1437e28a1003caa8c60b1c36..17f307a3104670164fb9959e26cecfa1b7c85356 100644 (file)
@@ -2695,8 +2695,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8996 = {
        .set_pll                = wm8996_set_fll,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
-
 };
 
 #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
index 38ef631d1a1ff825a60064e822464d389e32aaa9..210ad662fc26d6d554b2b16462ab6a6353790f7e 100644 (file)
@@ -1105,7 +1105,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = {
        .num_dapm_routes        = ARRAY_SIZE(wm8997_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8997_probe(struct platform_device *pdev)
index ab5481187c7105c54956a4464b299300a1839107..79fc6bbaa3aa3cd7b52ae2e8c9b56feaa5357520 100644 (file)
@@ -1332,7 +1332,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = {
        .num_dapm_routes        = ARRAY_SIZE(wm8998_dapm_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm8998_probe(struct platform_device *pdev)
index 87b58448cea7cc3cf5d63259be08ac30d22ee7d1..d5151877d0fa218b68512e2473ae9bc09eba7e31 100644 (file)
@@ -1284,7 +1284,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9081 = {
        .num_dapm_routes        = ARRAY_SIZE(wm9081_audio_paths),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm9081_regmap = {
index f7d80f1e37a809082cce4c9a4278cb826cc3a1c5..ef3524c3f07fd2fbcf23e3f9516e59668f0ed541 100644 (file)
@@ -543,7 +543,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9090 = {
        .suspend_bias_off       = 1,
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config wm9090_regmap = {
index 99fe8f3166248e27b646be8dae2d5e93bec96fd9..d04902ef1d5f30c84d96359b7853120d3d75a512 100644 (file)
@@ -368,7 +368,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9705 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm9705_probe(struct platform_device *pdev)
index 7515c9d4006e7062f0aed63a498b7d786d702017..df9b7980706b255cac155b0ce3daf7963100d191 100644 (file)
@@ -692,7 +692,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9712 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm9712_probe(struct platform_device *pdev)
index e0ce32dd4a811517828278f5b803ecb20169981a..5d2e54e06e30ae490f81f6cfd998d7827438d3bc 100644 (file)
@@ -1257,7 +1257,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm9713 = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int wm9713_probe(struct platform_device *pdev)
index a7784ac15dde694565d9f0a7c71e48e82ad0d238..cfaa45ede916ae42bef79e54203ff66a50bd1e40 100644 (file)
@@ -675,21 +675,12 @@ static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
 int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
                      unsigned int alg, void *buf, size_t len)
 {
-       struct cs_dsp_coeff_ctl *cs_ctl;
+       struct cs_dsp_coeff_ctl *cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
        struct wm_coeff_ctl *ctl;
        struct snd_kcontrol *kcontrol;
        char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int ret;
 
-       cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
-       if (!cs_ctl)
-               return -EINVAL;
-
-       ctl = cs_ctl->priv;
-
-       if (len > cs_ctl->len)
-               return -EINVAL;
-
        ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
        if (ret)
                return ret;
@@ -697,6 +688,8 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
        if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
                return 0;
 
+       ctl = cs_ctl->priv;
+
        if (dsp->component->name_prefix)
                snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
                         dsp->component->name_prefix, ctl->name);
@@ -720,16 +713,8 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
 int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
                     unsigned int alg, void *buf, size_t len)
 {
-       struct cs_dsp_coeff_ctl *cs_ctl;
-
-       cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
-       if (!cs_ctl)
-               return -EINVAL;
-
-       if (len > cs_ctl->len)
-               return -EINVAL;
-
-       return cs_dsp_coeff_read_ctrl(cs_ctl, 0, buf, len);
+       return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
+                                     0, buf, len);
 }
 EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
 
index f3a56f3ce4871ac2de386141c363d3f2b413ff1a..6c8b1db649b8988b28e1c7ebcdc11cec7d2ee122 100644 (file)
@@ -749,11 +749,9 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
        unsigned int mask = (1 << fls(max)) - 1;
        int val, ret, min_gain, max_gain;
 
-       ret = pm_runtime_get_sync(comp->dev);
-       if (ret < 0 && ret != -EACCES) {
-               pm_runtime_put_noidle(comp->dev);
+       ret = pm_runtime_resume_and_get(comp->dev);
+       if (ret < 0 && ret != -EACCES)
                return ret;
-       }
 
        max_gain = (max - ucontrol->value.integer.value[0]) & mask;
        /*
@@ -1175,11 +1173,17 @@ static int __maybe_unused wsa881x_runtime_resume(struct device *dev)
        struct sdw_slave *slave = dev_to_sdw_dev(dev);
        struct regmap *regmap = dev_get_regmap(dev, NULL);
        struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
+       unsigned long time;
 
        gpiod_direction_output(wsa881x->sd_n, 1);
 
-       wait_for_completion_timeout(&slave->initialization_complete,
-                                   msecs_to_jiffies(WSA881X_PROBE_TIMEOUT));
+       time = wait_for_completion_timeout(&slave->initialization_complete,
+                                          msecs_to_jiffies(WSA881X_PROBE_TIMEOUT));
+       if (!time) {
+               dev_err(dev, "Initialization not complete, timed out\n");
+               gpiod_direction_output(wsa881x->sd_n, 0);
+               return -ETIMEDOUT;
+       }
 
        regcache_cache_only(regmap, false);
        regcache_sync(regmap);
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
new file mode 100644 (file)
index 0000000..63e1d7a
--- /dev/null
@@ -0,0 +1,1511 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define WSA883X_BASE                    0x3000
+#define WSA883X_ANA_BG_TSADC_BASE       (WSA883X_BASE + 0x00000001)
+#define WSA883X_REF_CTRL                (WSA883X_ANA_BG_TSADC_BASE + 0x0000)
+#define WSA883X_TEST_CTL_0              (WSA883X_ANA_BG_TSADC_BASE + 0x0001)
+#define WSA883X_BIAS_0                  (WSA883X_ANA_BG_TSADC_BASE + 0x0002)
+#define WSA883X_OP_CTL                  (WSA883X_ANA_BG_TSADC_BASE + 0x0003)
+#define WSA883X_IREF_CTL                (WSA883X_ANA_BG_TSADC_BASE + 0x0004)
+#define WSA883X_ISENS_CTL               (WSA883X_ANA_BG_TSADC_BASE + 0x0005)
+#define WSA883X_CLK_CTL                 (WSA883X_ANA_BG_TSADC_BASE + 0x0006)
+#define WSA883X_TEST_CTL_1              (WSA883X_ANA_BG_TSADC_BASE + 0x0007)
+#define WSA883X_BIAS_1                  (WSA883X_ANA_BG_TSADC_BASE + 0x0008)
+#define WSA883X_ADC_CTL                 (WSA883X_ANA_BG_TSADC_BASE + 0x0009)
+#define WSA883X_DOUT_MSB                (WSA883X_ANA_BG_TSADC_BASE + 0x000A)
+#define WSA883X_DOUT_LSB                (WSA883X_ANA_BG_TSADC_BASE + 0x000B)
+#define WSA883X_VBAT_SNS                (WSA883X_ANA_BG_TSADC_BASE + 0x000C)
+#define WSA883X_ITRIM_CODE              (WSA883X_ANA_BG_TSADC_BASE + 0x000D)
+
+#define WSA883X_ANA_IVSENSE_BASE        (WSA883X_BASE + 0x0000000F)
+#define WSA883X_EN                      (WSA883X_ANA_IVSENSE_BASE + 0x0000)
+#define WSA883X_OVERRIDE1               (WSA883X_ANA_IVSENSE_BASE + 0x0001)
+#define WSA883X_OVERRIDE2               (WSA883X_ANA_IVSENSE_BASE + 0x0002)
+#define WSA883X_VSENSE1                 (WSA883X_ANA_IVSENSE_BASE + 0x0003)
+#define WSA883X_ISENSE1                 (WSA883X_ANA_IVSENSE_BASE + 0x0004)
+#define WSA883X_ISENSE2                 (WSA883X_ANA_IVSENSE_BASE + 0x0005)
+#define WSA883X_ISENSE_CAL              (WSA883X_ANA_IVSENSE_BASE + 0x0006)
+#define WSA883X_MISC                    (WSA883X_ANA_IVSENSE_BASE + 0x0007)
+#define WSA883X_ADC_0                   (WSA883X_ANA_IVSENSE_BASE + 0x0008)
+#define WSA883X_ADC_1                   (WSA883X_ANA_IVSENSE_BASE + 0x0009)
+#define WSA883X_ADC_2                   (WSA883X_ANA_IVSENSE_BASE + 0x000A)
+#define WSA883X_ADC_3                   (WSA883X_ANA_IVSENSE_BASE + 0x000B)
+#define WSA883X_ADC_4                   (WSA883X_ANA_IVSENSE_BASE + 0x000C)
+#define WSA883X_ADC_5                   (WSA883X_ANA_IVSENSE_BASE + 0x000D)
+#define WSA883X_ADC_6                   (WSA883X_ANA_IVSENSE_BASE + 0x000E)
+#define WSA883X_ADC_7                   (WSA883X_ANA_IVSENSE_BASE + 0x000F)
+#define WSA883X_STATUS                  (WSA883X_ANA_IVSENSE_BASE + 0x0010)
+
+#define WSA883X_ANA_SPK_TOP_BASE        (WSA883X_BASE + 0x00000025)
+#define WSA883X_DAC_CTRL_REG            (WSA883X_ANA_SPK_TOP_BASE + 0x0000)
+#define WSA883X_DAC_EN_DEBUG_REG        (WSA883X_ANA_SPK_TOP_BASE + 0x0001)
+#define WSA883X_DAC_OPAMP_BIAS1_REG     (WSA883X_ANA_SPK_TOP_BASE + 0x0002)
+#define WSA883X_DAC_OPAMP_BIAS2_REG     (WSA883X_ANA_SPK_TOP_BASE + 0x0003)
+#define WSA883X_DAC_VCM_CTRL_REG        (WSA883X_ANA_SPK_TOP_BASE + 0x0004)
+#define WSA883X_DAC_VOLTAGE_CTRL_REG    (WSA883X_ANA_SPK_TOP_BASE + 0x0005)
+#define WSA883X_ATEST1_REG              (WSA883X_ANA_SPK_TOP_BASE + 0x0006)
+#define WSA883X_ATEST2_REG              (WSA883X_ANA_SPK_TOP_BASE + 0x0007)
+#define WSA883X_SPKR_TOP_BIAS_REG1      (WSA883X_ANA_SPK_TOP_BASE + 0x0008)
+#define WSA883X_SPKR_TOP_BIAS_REG2      (WSA883X_ANA_SPK_TOP_BASE + 0x0009)
+#define WSA883X_SPKR_TOP_BIAS_REG3      (WSA883X_ANA_SPK_TOP_BASE + 0x000A)
+#define WSA883X_SPKR_TOP_BIAS_REG4      (WSA883X_ANA_SPK_TOP_BASE + 0x000B)
+#define WSA883X_SPKR_CLIP_DET_REG       (WSA883X_ANA_SPK_TOP_BASE + 0x000C)
+#define WSA883X_SPKR_DRV_LF_BLK_EN      (WSA883X_ANA_SPK_TOP_BASE + 0x000D)
+#define WSA883X_SPKR_DRV_LF_EN          (WSA883X_ANA_SPK_TOP_BASE + 0x000E)
+#define WSA883X_SPKR_DRV_LF_MASK_DCC_CTL (WSA883X_ANA_SPK_TOP_BASE + 0x000F)
+#define WSA883X_SPKR_DRV_LF_MISC_CTL    (WSA883X_ANA_SPK_TOP_BASE + 0x0010)
+#define WSA883X_SPKR_DRV_LF_REG_GAIN    (WSA883X_ANA_SPK_TOP_BASE + 0x0011)
+#define WSA883X_SPKR_DRV_OS_CAL_CTL     (WSA883X_ANA_SPK_TOP_BASE + 0x0012)
+#define WSA883X_SPKR_DRV_OS_CAL_CTL1     (WSA883X_ANA_SPK_TOP_BASE + 0x0013)
+#define WSA883X_SPKR_PWM_CLK_CTL        (WSA883X_ANA_SPK_TOP_BASE + 0x0014)
+#define WSA883X_SPKR_PWM_FREQ_SEL_MASK BIT(3)
+#define WSA883X_SPKR_PWM_FREQ_F300KHZ  0
+#define WSA883X_SPKR_PWM_FREQ_F600KHZ  1
+#define WSA883X_SPKR_PDRV_HS_CTL        (WSA883X_ANA_SPK_TOP_BASE + 0x0015)
+#define WSA883X_SPKR_PDRV_LS_CTL        (WSA883X_ANA_SPK_TOP_BASE + 0x0016)
+#define WSA883X_SPKR_PWRSTG_DBG         (WSA883X_ANA_SPK_TOP_BASE + 0x0017)
+#define WSA883X_SPKR_OCP_CTL            (WSA883X_ANA_SPK_TOP_BASE + 0x0018)
+#define WSA883X_SPKR_BBM_CTL            (WSA883X_ANA_SPK_TOP_BASE + 0x0019)
+#define WSA883X_PA_STATUS0              (WSA883X_ANA_SPK_TOP_BASE + 0x001A)
+#define WSA883X_PA_STATUS1              (WSA883X_ANA_SPK_TOP_BASE + 0x001B)
+#define WSA883X_PA_STATUS2              (WSA883X_ANA_SPK_TOP_BASE + 0x001C)
+
+#define WSA883X_ANA_BOOST_BASE          (WSA883X_BASE + 0x00000043)
+#define WSA883X_EN_CTRL                 (WSA883X_ANA_BOOST_BASE + 0x0000)
+#define WSA883X_CURRENT_LIMIT           (WSA883X_ANA_BOOST_BASE + 0x0001)
+#define WSA883X_IBIAS1                  (WSA883X_ANA_BOOST_BASE + 0x0002)
+#define WSA883X_IBIAS2                  (WSA883X_ANA_BOOST_BASE + 0x0003)
+#define WSA883X_IBIAS3                  (WSA883X_ANA_BOOST_BASE + 0x0004)
+#define WSA883X_LDO_PROG                (WSA883X_ANA_BOOST_BASE + 0x0005)
+#define WSA883X_STABILITY_CTRL1         (WSA883X_ANA_BOOST_BASE + 0x0006)
+#define WSA883X_STABILITY_CTRL2         (WSA883X_ANA_BOOST_BASE + 0x0007)
+#define WSA883X_PWRSTAGE_CTRL1          (WSA883X_ANA_BOOST_BASE + 0x0008)
+#define WSA883X_PWRSTAGE_CTRL2          (WSA883X_ANA_BOOST_BASE + 0x0009)
+#define WSA883X_BYPASS_1                (WSA883X_ANA_BOOST_BASE + 0x000A)
+#define WSA883X_BYPASS_2                (WSA883X_ANA_BOOST_BASE + 0x000B)
+#define WSA883X_ZX_CTRL_1               (WSA883X_ANA_BOOST_BASE + 0x000C)
+#define WSA883X_ZX_CTRL_2               (WSA883X_ANA_BOOST_BASE + 0x000D)
+#define WSA883X_MISC1                   (WSA883X_ANA_BOOST_BASE + 0x000E)
+#define WSA883X_MISC2                   (WSA883X_ANA_BOOST_BASE + 0x000F)
+#define WSA883X_GMAMP_SUP1              (WSA883X_ANA_BOOST_BASE + 0x0010)
+#define WSA883X_PWRSTAGE_CTRL3          (WSA883X_ANA_BOOST_BASE + 0x0011)
+#define WSA883X_PWRSTAGE_CTRL4          (WSA883X_ANA_BOOST_BASE + 0x0012)
+#define WSA883X_TEST1                   (WSA883X_ANA_BOOST_BASE + 0x0013)
+#define WSA883X_SPARE1                  (WSA883X_ANA_BOOST_BASE + 0x0014)
+#define WSA883X_SPARE2                  (WSA883X_ANA_BOOST_BASE + 0x0015)
+
+#define WSA883X_ANA_PON_LDOL_BASE       (WSA883X_BASE + 0x00000059)
+#define WSA883X_PON_CTL_0               (WSA883X_ANA_PON_LDOL_BASE + 0x0000)
+#define WSA883X_PON_CLT_1               (WSA883X_ANA_PON_LDOL_BASE + 0x0001)
+#define WSA883X_PON_CTL_2               (WSA883X_ANA_PON_LDOL_BASE + 0x0002)
+#define WSA883X_PON_CTL_3               (WSA883X_ANA_PON_LDOL_BASE + 0x0003)
+#define WSA883X_CKWD_CTL_0              (WSA883X_ANA_PON_LDOL_BASE + 0x0004)
+#define WSA883X_CKWD_CTL_1              (WSA883X_ANA_PON_LDOL_BASE + 0x0005)
+#define WSA883X_CKWD_CTL_2              (WSA883X_ANA_PON_LDOL_BASE + 0x0006)
+#define WSA883X_CKSK_CTL_0              (WSA883X_ANA_PON_LDOL_BASE + 0x0007)
+#define WSA883X_PADSW_CTL_0             (WSA883X_ANA_PON_LDOL_BASE + 0x0008)
+#define WSA883X_TEST_0                  (WSA883X_ANA_PON_LDOL_BASE + 0x0009)
+#define WSA883X_TEST_1                  (WSA883X_ANA_PON_LDOL_BASE + 0x000A)
+#define WSA883X_STATUS_0                (WSA883X_ANA_PON_LDOL_BASE + 0x000B)
+#define WSA883X_STATUS_1                (WSA883X_ANA_PON_LDOL_BASE + 0x000C)
+
+#define WSA883X_DIG_CTRL_BASE           (WSA883X_BASE + 0x00000400)
+#define WSA883X_CHIP_ID0                (WSA883X_DIG_CTRL_BASE + 0x0001)
+#define WSA883X_CHIP_ID1                (WSA883X_DIG_CTRL_BASE + 0x0002)
+#define WSA883X_CHIP_ID2                (WSA883X_DIG_CTRL_BASE + 0x0003)
+#define WSA883X_CHIP_ID3                (WSA883X_DIG_CTRL_BASE + 0x0004)
+#define WSA883X_BUS_ID                  (WSA883X_DIG_CTRL_BASE + 0x0005)
+#define WSA883X_CDC_RST_CTL             (WSA883X_DIG_CTRL_BASE + 0x0006)
+#define WSA883X_TOP_CLK_CFG             (WSA883X_DIG_CTRL_BASE + 0x0007)
+#define WSA883X_CDC_PATH_MODE           (WSA883X_DIG_CTRL_BASE + 0x0008)
+#define WSA883X_RXD_MODE_MASK          BIT(1)
+#define WSA883X_RXD_MODE_NORMAL                0
+#define WSA883X_RXD_MODE_HIFI          1
+#define WSA883X_CDC_CLK_CTL             (WSA883X_DIG_CTRL_BASE + 0x0009)
+#define WSA883X_SWR_RESET_EN            (WSA883X_DIG_CTRL_BASE + 0x000A)
+#define WSA883X_RESET_CTL               (WSA883X_DIG_CTRL_BASE + 0x000B)
+#define WSA883X_PA_FSM_CTL              (WSA883X_DIG_CTRL_BASE + 0x0010)
+#define WSA883X_GLOBAL_PA_EN_MASK      BIT(0)
+#define WSA883X_GLOBAL_PA_ENABLE       1
+#define WSA883X_PA_FSM_TIMER0           (WSA883X_DIG_CTRL_BASE + 0x0011)
+#define WSA883X_PA_FSM_TIMER1           (WSA883X_DIG_CTRL_BASE + 0x0012)
+#define WSA883X_PA_FSM_STA              (WSA883X_DIG_CTRL_BASE + 0x0013)
+#define WSA883X_PA_FSM_ERR_COND         (WSA883X_DIG_CTRL_BASE + 0x0014)
+#define WSA883X_PA_FSM_MSK              (WSA883X_DIG_CTRL_BASE + 0x0015)
+#define WSA883X_PA_FSM_BYP              (WSA883X_DIG_CTRL_BASE + 0x0016)
+#define WSA883X_PA_FSM_DBG              (WSA883X_DIG_CTRL_BASE + 0x0017)
+#define WSA883X_TADC_VALUE_CTL          (WSA883X_DIG_CTRL_BASE + 0x0020)
+#define WSA883X_TEMP_DETECT_CTL         (WSA883X_DIG_CTRL_BASE + 0x0021)
+#define WSA883X_TEMP_MSB                (WSA883X_DIG_CTRL_BASE + 0x0022)
+#define WSA883X_TEMP_LSB                (WSA883X_DIG_CTRL_BASE + 0x0023)
+#define WSA883X_TEMP_CONFIG0            (WSA883X_DIG_CTRL_BASE + 0x0024)
+#define WSA883X_TEMP_CONFIG1            (WSA883X_DIG_CTRL_BASE + 0x0025)
+#define WSA883X_VBAT_ADC_FLT_CTL        (WSA883X_DIG_CTRL_BASE + 0x0026)
+#define WSA883X_VBAT_ADC_FLT_EN_MASK   BIT(0)
+#define WSA883X_VBAT_ADC_COEF_SEL_MASK GENMASK(3, 1)
+#define WSA883X_VBAT_ADC_COEF_F_1DIV2  0x0
+#define WSA883X_VBAT_ADC_COEF_F_1DIV16 0x3
+#define WSA883X_VBAT_DIN_MSB            (WSA883X_DIG_CTRL_BASE + 0x0027)
+#define WSA883X_VBAT_DIN_LSB            (WSA883X_DIG_CTRL_BASE + 0x0028)
+#define WSA883X_VBAT_DOUT               (WSA883X_DIG_CTRL_BASE + 0x0029)
+#define WSA883X_SDM_PDM9_LSB            (WSA883X_DIG_CTRL_BASE + 0x002A)
+#define WSA883X_SDM_PDM9_MSB            (WSA883X_DIG_CTRL_BASE + 0x002B)
+#define WSA883X_CDC_RX_CTL              (WSA883X_DIG_CTRL_BASE + 0x0030)
+#define WSA883X_CDC_SPK_DSM_A1_0        (WSA883X_DIG_CTRL_BASE + 0x0031)
+#define WSA883X_CDC_SPK_DSM_A1_1        (WSA883X_DIG_CTRL_BASE + 0x0032)
+#define WSA883X_CDC_SPK_DSM_A2_0        (WSA883X_DIG_CTRL_BASE + 0x0033)
+#define WSA883X_CDC_SPK_DSM_A2_1        (WSA883X_DIG_CTRL_BASE + 0x0034)
+#define WSA883X_CDC_SPK_DSM_A3_0        (WSA883X_DIG_CTRL_BASE + 0x0035)
+#define WSA883X_CDC_SPK_DSM_A3_1        (WSA883X_DIG_CTRL_BASE + 0x0036)
+#define WSA883X_CDC_SPK_DSM_A4_0        (WSA883X_DIG_CTRL_BASE + 0x0037)
+#define WSA883X_CDC_SPK_DSM_A4_1        (WSA883X_DIG_CTRL_BASE + 0x0038)
+#define WSA883X_CDC_SPK_DSM_A5_0        (WSA883X_DIG_CTRL_BASE + 0x0039)
+#define WSA883X_CDC_SPK_DSM_A5_1        (WSA883X_DIG_CTRL_BASE + 0x003A)
+#define WSA883X_CDC_SPK_DSM_A6_0        (WSA883X_DIG_CTRL_BASE + 0x003B)
+#define WSA883X_CDC_SPK_DSM_A7_0        (WSA883X_DIG_CTRL_BASE + 0x003C)
+#define WSA883X_CDC_SPK_DSM_C_0         (WSA883X_DIG_CTRL_BASE + 0x003D)
+#define WSA883X_CDC_SPK_DSM_C_1         (WSA883X_DIG_CTRL_BASE + 0x003E)
+#define WSA883X_CDC_SPK_DSM_C_2         (WSA883X_DIG_CTRL_BASE + 0x003F)
+#define WSA883X_CDC_SPK_DSM_C_3         (WSA883X_DIG_CTRL_BASE + 0x0040)
+#define WSA883X_CDC_SPK_DSM_R1          (WSA883X_DIG_CTRL_BASE + 0x0041)
+#define WSA883X_CDC_SPK_DSM_R2          (WSA883X_DIG_CTRL_BASE + 0x0042)
+#define WSA883X_CDC_SPK_DSM_R3          (WSA883X_DIG_CTRL_BASE + 0x0043)
+#define WSA883X_CDC_SPK_DSM_R4          (WSA883X_DIG_CTRL_BASE + 0x0044)
+#define WSA883X_CDC_SPK_DSM_R5          (WSA883X_DIG_CTRL_BASE + 0x0045)
+#define WSA883X_CDC_SPK_DSM_R6          (WSA883X_DIG_CTRL_BASE + 0x0046)
+#define WSA883X_CDC_SPK_DSM_R7          (WSA883X_DIG_CTRL_BASE + 0x0047)
+#define WSA883X_CDC_SPK_GAIN_PDM_0      (WSA883X_DIG_CTRL_BASE + 0x0048)
+#define WSA883X_CDC_SPK_GAIN_PDM_1      (WSA883X_DIG_CTRL_BASE + 0x0049)
+#define WSA883X_CDC_SPK_GAIN_PDM_2      (WSA883X_DIG_CTRL_BASE + 0x004A)
+#define WSA883X_PDM_WD_CTL              (WSA883X_DIG_CTRL_BASE + 0x004B)
+#define WSA883X_PDM_EN_MASK            BIT(0)
+#define WSA883X_PDM_ENABLE             BIT(0)
+#define WSA883X_DEM_BYPASS_DATA0        (WSA883X_DIG_CTRL_BASE + 0x004C)
+#define WSA883X_DEM_BYPASS_DATA1        (WSA883X_DIG_CTRL_BASE + 0x004D)
+#define WSA883X_DEM_BYPASS_DATA2        (WSA883X_DIG_CTRL_BASE + 0x004E)
+#define WSA883X_DEM_BYPASS_DATA3        (WSA883X_DIG_CTRL_BASE + 0x004F)
+#define WSA883X_WAVG_CTL                (WSA883X_DIG_CTRL_BASE + 0x0050)
+#define WSA883X_WAVG_LRA_PER_0          (WSA883X_DIG_CTRL_BASE + 0x0051)
+#define WSA883X_WAVG_LRA_PER_1          (WSA883X_DIG_CTRL_BASE + 0x0052)
+#define WSA883X_WAVG_DELTA_THETA_0      (WSA883X_DIG_CTRL_BASE + 0x0053)
+#define WSA883X_WAVG_DELTA_THETA_1      (WSA883X_DIG_CTRL_BASE + 0x0054)
+#define WSA883X_WAVG_DIRECT_AMP_0       (WSA883X_DIG_CTRL_BASE + 0x0055)
+#define WSA883X_WAVG_DIRECT_AMP_1       (WSA883X_DIG_CTRL_BASE + 0x0056)
+#define WSA883X_WAVG_PTRN_AMP0_0        (WSA883X_DIG_CTRL_BASE + 0x0057)
+#define WSA883X_WAVG_PTRN_AMP0_1        (WSA883X_DIG_CTRL_BASE + 0x0058)
+#define WSA883X_WAVG_PTRN_AMP1_0        (WSA883X_DIG_CTRL_BASE + 0x0059)
+#define WSA883X_WAVG_PTRN_AMP1_1        (WSA883X_DIG_CTRL_BASE + 0x005A)
+#define WSA883X_WAVG_PTRN_AMP2_0        (WSA883X_DIG_CTRL_BASE + 0x005B)
+#define WSA883X_WAVG_PTRN_AMP2_1        (WSA883X_DIG_CTRL_BASE + 0x005C)
+#define WSA883X_WAVG_PTRN_AMP3_0        (WSA883X_DIG_CTRL_BASE + 0x005D)
+#define WSA883X_WAVG_PTRN_AMP3_1        (WSA883X_DIG_CTRL_BASE + 0x005E)
+#define WSA883X_WAVG_PTRN_AMP4_0        (WSA883X_DIG_CTRL_BASE + 0x005F)
+#define WSA883X_WAVG_PTRN_AMP4_1        (WSA883X_DIG_CTRL_BASE + 0x0060)
+#define WSA883X_WAVG_PTRN_AMP5_0        (WSA883X_DIG_CTRL_BASE + 0x0061)
+#define WSA883X_WAVG_PTRN_AMP5_1        (WSA883X_DIG_CTRL_BASE + 0x0062)
+#define WSA883X_WAVG_PTRN_AMP6_0        (WSA883X_DIG_CTRL_BASE + 0x0063)
+#define WSA883X_WAVG_PTRN_AMP6_1        (WSA883X_DIG_CTRL_BASE + 0x0064)
+#define WSA883X_WAVG_PTRN_AMP7_0        (WSA883X_DIG_CTRL_BASE + 0x0065)
+#define WSA883X_WAVG_PTRN_AMP7_1        (WSA883X_DIG_CTRL_BASE + 0x0066)
+#define WSA883X_WAVG_PER_0_1            (WSA883X_DIG_CTRL_BASE + 0x0067)
+#define WSA883X_WAVG_PER_2_3            (WSA883X_DIG_CTRL_BASE + 0x0068)
+#define WSA883X_WAVG_PER_4_5            (WSA883X_DIG_CTRL_BASE + 0x0069)
+#define WSA883X_WAVG_PER_6_7            (WSA883X_DIG_CTRL_BASE + 0x006A)
+#define WSA883X_WAVG_STA                (WSA883X_DIG_CTRL_BASE + 0x006B)
+#define WSA883X_DRE_CTL_0               (WSA883X_DIG_CTRL_BASE + 0x006C)
+#define WSA883X_DRE_OFFSET_MASK                GENMASK(2, 0)
+#define WSA883X_DRE_PROG_DELAY_MASK    GENMASK(7, 4)
+#define WSA883X_DRE_CTL_1               (WSA883X_DIG_CTRL_BASE + 0x006D)
+#define WSA883X_DRE_GAIN_EN_MASK       BIT(0)
+#define WSA883X_DRE_GAIN_FROM_CSR      1
+#define WSA883X_DRE_IDLE_DET_CTL        (WSA883X_DIG_CTRL_BASE + 0x006E)
+#define WSA883X_CLSH_CTL_0              (WSA883X_DIG_CTRL_BASE + 0x0070)
+#define WSA883X_CLSH_CTL_1              (WSA883X_DIG_CTRL_BASE + 0x0071)
+#define WSA883X_CLSH_V_HD_PA            (WSA883X_DIG_CTRL_BASE + 0x0072)
+#define WSA883X_CLSH_V_PA_MIN           (WSA883X_DIG_CTRL_BASE + 0x0073)
+#define WSA883X_CLSH_OVRD_VAL           (WSA883X_DIG_CTRL_BASE + 0x0074)
+#define WSA883X_CLSH_HARD_MAX           (WSA883X_DIG_CTRL_BASE + 0x0075)
+#define WSA883X_CLSH_SOFT_MAX           (WSA883X_DIG_CTRL_BASE + 0x0076)
+#define WSA883X_CLSH_SIG_DP             (WSA883X_DIG_CTRL_BASE + 0x0077)
+#define WSA883X_TAGC_CTL                (WSA883X_DIG_CTRL_BASE + 0x0078)
+#define WSA883X_TAGC_TIME               (WSA883X_DIG_CTRL_BASE + 0x0079)
+#define WSA883X_TAGC_E2E_GAIN           (WSA883X_DIG_CTRL_BASE + 0x007A)
+#define WSA883X_TAGC_FORCE_VAL          (WSA883X_DIG_CTRL_BASE + 0x007B)
+#define WSA883X_VAGC_CTL                (WSA883X_DIG_CTRL_BASE + 0x007C)
+#define WSA883X_VAGC_TIME               (WSA883X_DIG_CTRL_BASE + 0x007D)
+#define WSA883X_VAGC_ATTN_LVL_1_2       (WSA883X_DIG_CTRL_BASE + 0x007E)
+#define WSA883X_VAGC_ATTN_LVL_3         (WSA883X_DIG_CTRL_BASE + 0x007F)
+#define WSA883X_INTR_MODE               (WSA883X_DIG_CTRL_BASE + 0x0080)
+#define WSA883X_INTR_MASK0              (WSA883X_DIG_CTRL_BASE + 0x0081)
+#define WSA883X_INTR_MASK1              (WSA883X_DIG_CTRL_BASE + 0x0082)
+#define WSA883X_INTR_STATUS0            (WSA883X_DIG_CTRL_BASE + 0x0083)
+#define WSA883X_INTR_STATUS1            (WSA883X_DIG_CTRL_BASE + 0x0084)
+#define WSA883X_INTR_CLEAR0             (WSA883X_DIG_CTRL_BASE + 0x0085)
+#define WSA883X_INTR_CLEAR1             (WSA883X_DIG_CTRL_BASE + 0x0086)
+#define WSA883X_INTR_LEVEL0             (WSA883X_DIG_CTRL_BASE + 0x0087)
+#define WSA883X_INTR_LEVEL1             (WSA883X_DIG_CTRL_BASE + 0x0088)
+#define WSA883X_INTR_SET0               (WSA883X_DIG_CTRL_BASE + 0x0089)
+#define WSA883X_INTR_SET1               (WSA883X_DIG_CTRL_BASE + 0x008A)
+#define WSA883X_INTR_TEST0              (WSA883X_DIG_CTRL_BASE + 0x008B)
+#define WSA883X_INTR_TEST1              (WSA883X_DIG_CTRL_BASE + 0x008C)
+#define WSA883X_OTP_CTRL0               (WSA883X_DIG_CTRL_BASE + 0x0090)
+#define WSA883X_OTP_CTRL1               (WSA883X_DIG_CTRL_BASE + 0x0091)
+#define WSA883X_HDRIVE_CTL_GROUP1       (WSA883X_DIG_CTRL_BASE + 0x0092)
+#define WSA883X_PIN_CTL                 (WSA883X_DIG_CTRL_BASE + 0x0093)
+#define WSA883X_PIN_CTL_OE              (WSA883X_DIG_CTRL_BASE + 0x0094)
+#define WSA883X_PIN_WDATA_IOPAD         (WSA883X_DIG_CTRL_BASE + 0x0095)
+#define WSA883X_PIN_STATUS              (WSA883X_DIG_CTRL_BASE + 0x0096)
+#define WSA883X_I2C_SLAVE_CTL           (WSA883X_DIG_CTRL_BASE + 0x0097)
+#define WSA883X_PDM_TEST_MODE           (WSA883X_DIG_CTRL_BASE + 0x00A0)
+#define WSA883X_ATE_TEST_MODE           (WSA883X_DIG_CTRL_BASE + 0x00A1)
+#define WSA883X_DIG_DEBUG_MODE          (WSA883X_DIG_CTRL_BASE + 0x00A3)
+#define WSA883X_DIG_DEBUG_SEL           (WSA883X_DIG_CTRL_BASE + 0x00A4)
+#define WSA883X_DIG_DEBUG_EN            (WSA883X_DIG_CTRL_BASE + 0x00A5)
+#define WSA883X_SWR_HM_TEST0            (WSA883X_DIG_CTRL_BASE + 0x00A6)
+#define WSA883X_SWR_HM_TEST1            (WSA883X_DIG_CTRL_BASE + 0x00A7)
+#define WSA883X_SWR_PAD_CTL             (WSA883X_DIG_CTRL_BASE + 0x00A8)
+#define WSA883X_TADC_DETECT_DBG_CTL     (WSA883X_DIG_CTRL_BASE + 0x00A9)
+#define WSA883X_TADC_DEBUG_MSB          (WSA883X_DIG_CTRL_BASE + 0x00AA)
+#define WSA883X_TADC_DEBUG_LSB          (WSA883X_DIG_CTRL_BASE + 0x00AB)
+#define WSA883X_SAMPLE_EDGE_SEL         (WSA883X_DIG_CTRL_BASE + 0x00AC)
+#define WSA883X_SWR_EDGE_SEL            (WSA883X_DIG_CTRL_BASE + 0x00AD)
+#define WSA883X_TEST_MODE_CTL           (WSA883X_DIG_CTRL_BASE + 0x00AE)
+#define WSA883X_IOPAD_CTL               (WSA883X_DIG_CTRL_BASE + 0x00AF)
+#define WSA883X_ANA_CSR_DBG_ADD         (WSA883X_DIG_CTRL_BASE + 0x00B0)
+#define WSA883X_ANA_CSR_DBG_CTL         (WSA883X_DIG_CTRL_BASE + 0x00B1)
+#define WSA883X_SPARE_R                 (WSA883X_DIG_CTRL_BASE + 0x00BC)
+#define WSA883X_SPARE_0                 (WSA883X_DIG_CTRL_BASE + 0x00BD)
+#define WSA883X_SPARE_1                 (WSA883X_DIG_CTRL_BASE + 0x00BE)
+#define WSA883X_SPARE_2                 (WSA883X_DIG_CTRL_BASE + 0x00BF)
+#define WSA883X_SCODE                   (WSA883X_DIG_CTRL_BASE + 0x00C0)
+
+#define WSA883X_DIG_TRIM_BASE           (WSA883X_BASE + 0x00000500)
+#define WSA883X_OTP_REG_0               (WSA883X_DIG_TRIM_BASE + 0x0080)
+#define WSA883X_ID_MASK                        GENMASK(3, 0)
+#define WSA883X_OTP_REG_1               (WSA883X_DIG_TRIM_BASE + 0x0081)
+#define WSA883X_OTP_REG_2               (WSA883X_DIG_TRIM_BASE + 0x0082)
+#define WSA883X_OTP_REG_3               (WSA883X_DIG_TRIM_BASE + 0x0083)
+#define WSA883X_OTP_REG_4               (WSA883X_DIG_TRIM_BASE + 0x0084)
+#define WSA883X_OTP_REG_5               (WSA883X_DIG_TRIM_BASE + 0x0085)
+#define WSA883X_OTP_REG_6               (WSA883X_DIG_TRIM_BASE + 0x0086)
+#define WSA883X_OTP_REG_7               (WSA883X_DIG_TRIM_BASE + 0x0087)
+#define WSA883X_OTP_REG_8               (WSA883X_DIG_TRIM_BASE + 0x0088)
+#define WSA883X_OTP_REG_9               (WSA883X_DIG_TRIM_BASE + 0x0089)
+#define WSA883X_OTP_REG_10              (WSA883X_DIG_TRIM_BASE + 0x008A)
+#define WSA883X_OTP_REG_11              (WSA883X_DIG_TRIM_BASE + 0x008B)
+#define WSA883X_OTP_REG_12              (WSA883X_DIG_TRIM_BASE + 0x008C)
+#define WSA883X_OTP_REG_13              (WSA883X_DIG_TRIM_BASE + 0x008D)
+#define WSA883X_OTP_REG_14              (WSA883X_DIG_TRIM_BASE + 0x008E)
+#define WSA883X_OTP_REG_15              (WSA883X_DIG_TRIM_BASE + 0x008F)
+#define WSA883X_OTP_REG_16              (WSA883X_DIG_TRIM_BASE + 0x0090)
+#define WSA883X_OTP_REG_17              (WSA883X_DIG_TRIM_BASE + 0x0091)
+#define WSA883X_OTP_REG_18              (WSA883X_DIG_TRIM_BASE + 0x0092)
+#define WSA883X_OTP_REG_19              (WSA883X_DIG_TRIM_BASE + 0x0093)
+#define WSA883X_OTP_REG_20              (WSA883X_DIG_TRIM_BASE + 0x0094)
+#define WSA883X_OTP_REG_21              (WSA883X_DIG_TRIM_BASE + 0x0095)
+#define WSA883X_OTP_REG_22              (WSA883X_DIG_TRIM_BASE + 0x0096)
+#define WSA883X_OTP_REG_23              (WSA883X_DIG_TRIM_BASE + 0x0097)
+#define WSA883X_OTP_REG_24              (WSA883X_DIG_TRIM_BASE + 0x0098)
+#define WSA883X_OTP_REG_25              (WSA883X_DIG_TRIM_BASE + 0x0099)
+#define WSA883X_OTP_REG_26              (WSA883X_DIG_TRIM_BASE + 0x009A)
+#define WSA883X_OTP_REG_27              (WSA883X_DIG_TRIM_BASE + 0x009B)
+#define WSA883X_OTP_REG_28              (WSA883X_DIG_TRIM_BASE + 0x009C)
+#define WSA883X_OTP_REG_29              (WSA883X_DIG_TRIM_BASE + 0x009D)
+#define WSA883X_OTP_REG_30              (WSA883X_DIG_TRIM_BASE + 0x009E)
+#define WSA883X_OTP_REG_31              (WSA883X_DIG_TRIM_BASE + 0x009F)
+#define WSA883X_OTP_REG_32              (WSA883X_DIG_TRIM_BASE + 0x00A0)
+#define WSA883X_OTP_REG_33              (WSA883X_DIG_TRIM_BASE + 0x00A1)
+#define WSA883X_OTP_REG_34              (WSA883X_DIG_TRIM_BASE + 0x00A2)
+#define WSA883X_OTP_REG_35              (WSA883X_DIG_TRIM_BASE + 0x00A3)
+#define WSA883X_OTP_REG_63              (WSA883X_DIG_TRIM_BASE + 0x00BF)
+
+#define WSA883X_DIG_EMEM_BASE           (WSA883X_BASE + 0x000005C0)
+#define WSA883X_EMEM_0                  (WSA883X_DIG_EMEM_BASE + 0x0000)
+#define WSA883X_EMEM_1                  (WSA883X_DIG_EMEM_BASE + 0x0001)
+#define WSA883X_EMEM_2                  (WSA883X_DIG_EMEM_BASE + 0x0002)
+#define WSA883X_EMEM_3                  (WSA883X_DIG_EMEM_BASE + 0x0003)
+#define WSA883X_EMEM_4                  (WSA883X_DIG_EMEM_BASE + 0x0004)
+#define WSA883X_EMEM_5                  (WSA883X_DIG_EMEM_BASE + 0x0005)
+#define WSA883X_EMEM_6                  (WSA883X_DIG_EMEM_BASE + 0x0006)
+#define WSA883X_EMEM_7                  (WSA883X_DIG_EMEM_BASE + 0x0007)
+#define WSA883X_EMEM_8                  (WSA883X_DIG_EMEM_BASE + 0x0008)
+#define WSA883X_EMEM_9                  (WSA883X_DIG_EMEM_BASE + 0x0009)
+#define WSA883X_EMEM_10                 (WSA883X_DIG_EMEM_BASE + 0x000A)
+#define WSA883X_EMEM_11                 (WSA883X_DIG_EMEM_BASE + 0x000B)
+#define WSA883X_EMEM_12                 (WSA883X_DIG_EMEM_BASE + 0x000C)
+#define WSA883X_EMEM_13                 (WSA883X_DIG_EMEM_BASE + 0x000D)
+#define WSA883X_EMEM_14                 (WSA883X_DIG_EMEM_BASE + 0x000E)
+#define WSA883X_EMEM_15                 (WSA883X_DIG_EMEM_BASE + 0x000F)
+#define WSA883X_EMEM_16                 (WSA883X_DIG_EMEM_BASE + 0x0010)
+#define WSA883X_EMEM_17                 (WSA883X_DIG_EMEM_BASE + 0x0011)
+#define WSA883X_EMEM_18                 (WSA883X_DIG_EMEM_BASE + 0x0012)
+#define WSA883X_EMEM_19                 (WSA883X_DIG_EMEM_BASE + 0x0013)
+#define WSA883X_EMEM_20                 (WSA883X_DIG_EMEM_BASE + 0x0014)
+#define WSA883X_EMEM_21                 (WSA883X_DIG_EMEM_BASE + 0x0015)
+#define WSA883X_EMEM_22                 (WSA883X_DIG_EMEM_BASE + 0x0016)
+#define WSA883X_EMEM_23                 (WSA883X_DIG_EMEM_BASE + 0x0017)
+#define WSA883X_EMEM_24                 (WSA883X_DIG_EMEM_BASE + 0x0018)
+#define WSA883X_EMEM_25                 (WSA883X_DIG_EMEM_BASE + 0x0019)
+#define WSA883X_EMEM_26                 (WSA883X_DIG_EMEM_BASE + 0x001A)
+#define WSA883X_EMEM_27                 (WSA883X_DIG_EMEM_BASE + 0x001B)
+#define WSA883X_EMEM_28                 (WSA883X_DIG_EMEM_BASE + 0x001C)
+#define WSA883X_EMEM_29                 (WSA883X_DIG_EMEM_BASE + 0x001D)
+#define WSA883X_EMEM_30                 (WSA883X_DIG_EMEM_BASE + 0x001E)
+#define WSA883X_EMEM_31                 (WSA883X_DIG_EMEM_BASE + 0x001F)
+#define WSA883X_EMEM_32                 (WSA883X_DIG_EMEM_BASE + 0x0020)
+#define WSA883X_EMEM_33                 (WSA883X_DIG_EMEM_BASE + 0x0021)
+#define WSA883X_EMEM_34                 (WSA883X_DIG_EMEM_BASE + 0x0022)
+#define WSA883X_EMEM_35                 (WSA883X_DIG_EMEM_BASE + 0x0023)
+#define WSA883X_EMEM_36                 (WSA883X_DIG_EMEM_BASE + 0x0024)
+#define WSA883X_EMEM_37                 (WSA883X_DIG_EMEM_BASE + 0x0025)
+#define WSA883X_EMEM_38                 (WSA883X_DIG_EMEM_BASE + 0x0026)
+#define WSA883X_EMEM_39                 (WSA883X_DIG_EMEM_BASE + 0x0027)
+#define WSA883X_EMEM_40                 (WSA883X_DIG_EMEM_BASE + 0x0028)
+#define WSA883X_EMEM_41                 (WSA883X_DIG_EMEM_BASE + 0x0029)
+#define WSA883X_EMEM_42                 (WSA883X_DIG_EMEM_BASE + 0x002A)
+#define WSA883X_EMEM_43                 (WSA883X_DIG_EMEM_BASE + 0x002B)
+#define WSA883X_EMEM_44                 (WSA883X_DIG_EMEM_BASE + 0x002C)
+#define WSA883X_EMEM_45                 (WSA883X_DIG_EMEM_BASE + 0x002D)
+#define WSA883X_EMEM_46                 (WSA883X_DIG_EMEM_BASE + 0x002E)
+#define WSA883X_EMEM_47                 (WSA883X_DIG_EMEM_BASE + 0x002F)
+#define WSA883X_EMEM_48                 (WSA883X_DIG_EMEM_BASE + 0x0030)
+#define WSA883X_EMEM_49                 (WSA883X_DIG_EMEM_BASE + 0x0031)
+#define WSA883X_EMEM_50                 (WSA883X_DIG_EMEM_BASE + 0x0032)
+#define WSA883X_EMEM_51                 (WSA883X_DIG_EMEM_BASE + 0x0033)
+#define WSA883X_EMEM_52                 (WSA883X_DIG_EMEM_BASE + 0x0034)
+#define WSA883X_EMEM_53                 (WSA883X_DIG_EMEM_BASE + 0x0035)
+#define WSA883X_EMEM_54                 (WSA883X_DIG_EMEM_BASE + 0x0036)
+#define WSA883X_EMEM_55                 (WSA883X_DIG_EMEM_BASE + 0x0037)
+#define WSA883X_EMEM_56                 (WSA883X_DIG_EMEM_BASE + 0x0038)
+#define WSA883X_EMEM_57                 (WSA883X_DIG_EMEM_BASE + 0x0039)
+#define WSA883X_EMEM_58                 (WSA883X_DIG_EMEM_BASE + 0x003A)
+#define WSA883X_EMEM_59                 (WSA883X_DIG_EMEM_BASE + 0x003B)
+#define WSA883X_EMEM_60                 (WSA883X_DIG_EMEM_BASE + 0x003C)
+#define WSA883X_EMEM_61                 (WSA883X_DIG_EMEM_BASE + 0x003D)
+#define WSA883X_EMEM_62                 (WSA883X_DIG_EMEM_BASE + 0x003E)
+#define WSA883X_EMEM_63                 (WSA883X_DIG_EMEM_BASE + 0x003F)
+
+#define WSA883X_NUM_REGISTERS           (WSA883X_EMEM_63 + 1)
+#define WSA883X_MAX_REGISTER            (WSA883X_NUM_REGISTERS - 1)
+#define WSA883X_PROBE_TIMEOUT 1000
+
+#define WSA883X_VERSION_1_0 0
+#define WSA883X_VERSION_1_1 1
+
+#define WSA883X_MAX_SWR_PORTS   4
+#define WSA883X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+                       SNDRV_PCM_RATE_384000)
+/* Fractional Rates */
+#define WSA883X_FRAC_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+                               SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800)
+
+#define WSA883X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE |\
+               SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct wsa883x_priv {
+       struct regmap *regmap;
+       struct device *dev;
+       struct regulator *vdd;
+       struct sdw_slave *slave;
+       struct sdw_stream_config sconfig;
+       struct sdw_stream_runtime *sruntime;
+       struct sdw_port_config port_config[WSA883X_MAX_SWR_PORTS];
+       struct gpio_desc *sd_n;
+       bool port_prepared[WSA883X_MAX_SWR_PORTS];
+       bool port_enable[WSA883X_MAX_SWR_PORTS];
+       int version;
+       int variant;
+       int active_ports;
+       int dev_mode;
+       int comp_offset;
+};
+
+enum {
+       WSA8830 = 0,
+       WSA8835,
+       WSA8832,
+       WSA8835_V2 = 5,
+};
+
+enum {
+       COMP_OFFSET0,
+       COMP_OFFSET1,
+       COMP_OFFSET2,
+       COMP_OFFSET3,
+       COMP_OFFSET4,
+};
+
+enum wsa_port_ids {
+       WSA883X_PORT_DAC,
+       WSA883X_PORT_COMP,
+       WSA883X_PORT_BOOST,
+       WSA883X_PORT_VISENSE,
+};
+
+static const char * const wsa_dev_mode_text[] = {
+       "Speaker", "Receiver", "Ultrasound"
+};
+
+enum {
+       SPEAKER,
+       RECEIVER,
+       ULTRASOUND,
+};
+
+static const struct soc_enum wsa_dev_mode_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_dev_mode_text), wsa_dev_mode_text);
+
+/* 4 ports */
+static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
+       {
+               /* DAC */
+               .num = 1,
+               .type = SDW_DPN_SIMPLE,
+               .min_ch = 1,
+               .max_ch = 1,
+               .simple_ch_prep_sm = true,
+               .read_only_wordlength = true,
+       }, {
+               /* COMP */
+               .num = 2,
+               .type = SDW_DPN_SIMPLE,
+               .min_ch = 1,
+               .max_ch = 1,
+               .simple_ch_prep_sm = true,
+               .read_only_wordlength = true,
+       }, {
+               /* BOOST */
+               .num = 3,
+               .type = SDW_DPN_SIMPLE,
+               .min_ch = 1,
+               .max_ch = 1,
+               .simple_ch_prep_sm = true,
+               .read_only_wordlength = true,
+       }, {
+               /* VISENSE */
+               .num = 4,
+               .type = SDW_DPN_SIMPLE,
+               .min_ch = 1,
+               .max_ch = 1,
+               .simple_ch_prep_sm = true,
+               .read_only_wordlength = true,
+       }
+};
+
+static struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
+       {
+               .num = 1,
+               .ch_mask = 0x1,
+       }, {
+               .num = 2,
+               .ch_mask = 0xf,
+       }, {
+               .num = 3,
+               .ch_mask = 0x3,
+       }, {    /* IV feedback */
+               .num = 4,
+               .ch_mask = 0x3,
+       },
+};
+
+static struct reg_default wsa883x_defaults[] = {
+       { WSA883X_REF_CTRL, 0xD5 },
+       { WSA883X_TEST_CTL_0, 0x06 },
+       { WSA883X_BIAS_0, 0xD2 },
+       { WSA883X_OP_CTL, 0xE0 },
+       { WSA883X_IREF_CTL, 0x57 },
+       { WSA883X_ISENS_CTL, 0x47 },
+       { WSA883X_CLK_CTL, 0x87 },
+       { WSA883X_TEST_CTL_1, 0x00 },
+       { WSA883X_BIAS_1, 0x51 },
+       { WSA883X_ADC_CTL, 0x01 },
+       { WSA883X_DOUT_MSB, 0x00 },
+       { WSA883X_DOUT_LSB, 0x00 },
+       { WSA883X_VBAT_SNS, 0x40 },
+       { WSA883X_ITRIM_CODE, 0x9F },
+       { WSA883X_EN, 0x20 },
+       { WSA883X_OVERRIDE1, 0x00 },
+       { WSA883X_OVERRIDE2, 0x08 },
+       { WSA883X_VSENSE1, 0xD3 },
+       { WSA883X_ISENSE1, 0xD4 },
+       { WSA883X_ISENSE2, 0x20 },
+       { WSA883X_ISENSE_CAL, 0x00 },
+       { WSA883X_MISC, 0x08 },
+       { WSA883X_ADC_0, 0x00 },
+       { WSA883X_ADC_1, 0x00 },
+       { WSA883X_ADC_2, 0x40 },
+       { WSA883X_ADC_3, 0x80 },
+       { WSA883X_ADC_4, 0x25 },
+       { WSA883X_ADC_5, 0x25 },
+       { WSA883X_ADC_6, 0x08 },
+       { WSA883X_ADC_7, 0x81 },
+       { WSA883X_STATUS, 0x00 },
+       { WSA883X_DAC_CTRL_REG, 0x53 },
+       { WSA883X_DAC_EN_DEBUG_REG, 0x00 },
+       { WSA883X_DAC_OPAMP_BIAS1_REG, 0x48 },
+       { WSA883X_DAC_OPAMP_BIAS2_REG, 0x48 },
+       { WSA883X_DAC_VCM_CTRL_REG, 0x88 },
+       { WSA883X_DAC_VOLTAGE_CTRL_REG, 0xA5 },
+       { WSA883X_ATEST1_REG, 0x00 },
+       { WSA883X_ATEST2_REG, 0x00 },
+       { WSA883X_SPKR_TOP_BIAS_REG1, 0x6A },
+       { WSA883X_SPKR_TOP_BIAS_REG2, 0x65 },
+       { WSA883X_SPKR_TOP_BIAS_REG3, 0x55 },
+       { WSA883X_SPKR_TOP_BIAS_REG4, 0xA9 },
+       { WSA883X_SPKR_CLIP_DET_REG, 0x9C },
+       { WSA883X_SPKR_DRV_LF_BLK_EN, 0x0F },
+       { WSA883X_SPKR_DRV_LF_EN, 0x0A },
+       { WSA883X_SPKR_DRV_LF_MASK_DCC_CTL, 0x00 },
+       { WSA883X_SPKR_DRV_LF_MISC_CTL, 0x3A },
+       { WSA883X_SPKR_DRV_LF_REG_GAIN, 0x00 },
+       { WSA883X_SPKR_DRV_OS_CAL_CTL, 0x00 },
+       { WSA883X_SPKR_DRV_OS_CAL_CTL1, 0x90 },
+       { WSA883X_SPKR_PWM_CLK_CTL, 0x00 },
+       { WSA883X_SPKR_PDRV_HS_CTL, 0x52 },
+       { WSA883X_SPKR_PDRV_LS_CTL, 0x48 },
+       { WSA883X_SPKR_PWRSTG_DBG, 0x08 },
+       { WSA883X_SPKR_OCP_CTL, 0xE2 },
+       { WSA883X_SPKR_BBM_CTL, 0x92 },
+       { WSA883X_PA_STATUS0, 0x00 },
+       { WSA883X_PA_STATUS1, 0x00 },
+       { WSA883X_PA_STATUS2, 0x80 },
+       { WSA883X_EN_CTRL, 0x44 },
+       { WSA883X_CURRENT_LIMIT, 0xCC },
+       { WSA883X_IBIAS1, 0x00 },
+       { WSA883X_IBIAS2, 0x00 },
+       { WSA883X_IBIAS3, 0x00 },
+       { WSA883X_LDO_PROG, 0x02 },
+       { WSA883X_STABILITY_CTRL1, 0x8E },
+       { WSA883X_STABILITY_CTRL2, 0x10 },
+       { WSA883X_PWRSTAGE_CTRL1, 0x06 },
+       { WSA883X_PWRSTAGE_CTRL2, 0x00 },
+       { WSA883X_BYPASS_1, 0x19 },
+       { WSA883X_BYPASS_2, 0x13 },
+       { WSA883X_ZX_CTRL_1, 0xF0 },
+       { WSA883X_ZX_CTRL_2, 0x04 },
+       { WSA883X_MISC1, 0x06 },
+       { WSA883X_MISC2, 0xA0 },
+       { WSA883X_GMAMP_SUP1, 0x82 },
+       { WSA883X_PWRSTAGE_CTRL3, 0x39 },
+       { WSA883X_PWRSTAGE_CTRL4, 0x5F },
+       { WSA883X_TEST1, 0x00 },
+       { WSA883X_SPARE1, 0x00 },
+       { WSA883X_SPARE2, 0x00 },
+       { WSA883X_PON_CTL_0, 0x10 },
+       { WSA883X_PON_CLT_1, 0xE0 },
+       { WSA883X_PON_CTL_2, 0x90 },
+       { WSA883X_PON_CTL_3, 0x70 },
+       { WSA883X_CKWD_CTL_0, 0x34 },
+       { WSA883X_CKWD_CTL_1, 0x0F },
+       { WSA883X_CKWD_CTL_2, 0x00 },
+       { WSA883X_CKSK_CTL_0, 0x00 },
+       { WSA883X_PADSW_CTL_0, 0x00 },
+       { WSA883X_TEST_0, 0x00 },
+       { WSA883X_TEST_1, 0x00 },
+       { WSA883X_STATUS_0, 0x00 },
+       { WSA883X_STATUS_1, 0x00 },
+       { WSA883X_CHIP_ID0, 0x00 },
+       { WSA883X_CHIP_ID1, 0x00 },
+       { WSA883X_CHIP_ID2, 0x02 },
+       { WSA883X_CHIP_ID3, 0x02 },
+       { WSA883X_BUS_ID, 0x00 },
+       { WSA883X_CDC_RST_CTL, 0x01 },
+       { WSA883X_TOP_CLK_CFG, 0x00 },
+       { WSA883X_CDC_PATH_MODE, 0x00 },
+       { WSA883X_CDC_CLK_CTL, 0xFF },
+       { WSA883X_SWR_RESET_EN, 0x00 },
+       { WSA883X_RESET_CTL, 0x00 },
+       { WSA883X_PA_FSM_CTL, 0x00 },
+       { WSA883X_PA_FSM_TIMER0, 0x80 },
+       { WSA883X_PA_FSM_TIMER1, 0x80 },
+       { WSA883X_PA_FSM_STA, 0x00 },
+       { WSA883X_PA_FSM_ERR_COND, 0x00 },
+       { WSA883X_PA_FSM_MSK, 0x00 },
+       { WSA883X_PA_FSM_BYP, 0x01 },
+       { WSA883X_PA_FSM_DBG, 0x00 },
+       { WSA883X_TADC_VALUE_CTL, 0x03 },
+       { WSA883X_TEMP_DETECT_CTL, 0x01 },
+       { WSA883X_TEMP_MSB, 0x00 },
+       { WSA883X_TEMP_LSB, 0x00 },
+       { WSA883X_TEMP_CONFIG0, 0x00 },
+       { WSA883X_TEMP_CONFIG1, 0x00 },
+       { WSA883X_VBAT_ADC_FLT_CTL, 0x00 },
+       { WSA883X_VBAT_DIN_MSB, 0x00 },
+       { WSA883X_VBAT_DIN_LSB, 0x00 },
+       { WSA883X_VBAT_DOUT, 0x00 },
+       { WSA883X_SDM_PDM9_LSB, 0x00 },
+       { WSA883X_SDM_PDM9_MSB, 0x00 },
+       { WSA883X_CDC_RX_CTL, 0xFE },
+       { WSA883X_CDC_SPK_DSM_A1_0, 0x00 },
+       { WSA883X_CDC_SPK_DSM_A1_1, 0x01 },
+       { WSA883X_CDC_SPK_DSM_A2_0, 0x96 },
+       { WSA883X_CDC_SPK_DSM_A2_1, 0x09 },
+       { WSA883X_CDC_SPK_DSM_A3_0, 0xAB },
+       { WSA883X_CDC_SPK_DSM_A3_1, 0x05 },
+       { WSA883X_CDC_SPK_DSM_A4_0, 0x1C },
+       { WSA883X_CDC_SPK_DSM_A4_1, 0x02 },
+       { WSA883X_CDC_SPK_DSM_A5_0, 0x17 },
+       { WSA883X_CDC_SPK_DSM_A5_1, 0x02 },
+       { WSA883X_CDC_SPK_DSM_A6_0, 0xAA },
+       { WSA883X_CDC_SPK_DSM_A7_0, 0xE3 },
+       { WSA883X_CDC_SPK_DSM_C_0, 0x69 },
+       { WSA883X_CDC_SPK_DSM_C_1, 0x54 },
+       { WSA883X_CDC_SPK_DSM_C_2, 0x02 },
+       { WSA883X_CDC_SPK_DSM_C_3, 0x15 },
+       { WSA883X_CDC_SPK_DSM_R1, 0xA4 },
+       { WSA883X_CDC_SPK_DSM_R2, 0xB5 },
+       { WSA883X_CDC_SPK_DSM_R3, 0x86 },
+       { WSA883X_CDC_SPK_DSM_R4, 0x85 },
+       { WSA883X_CDC_SPK_DSM_R5, 0xAA },
+       { WSA883X_CDC_SPK_DSM_R6, 0xE2 },
+       { WSA883X_CDC_SPK_DSM_R7, 0x62 },
+       { WSA883X_CDC_SPK_GAIN_PDM_0, 0x00 },
+       { WSA883X_CDC_SPK_GAIN_PDM_1, 0xFC },
+       { WSA883X_CDC_SPK_GAIN_PDM_2, 0x05 },
+       { WSA883X_PDM_WD_CTL, 0x00 },
+       { WSA883X_DEM_BYPASS_DATA0, 0x00 },
+       { WSA883X_DEM_BYPASS_DATA1, 0x00 },
+       { WSA883X_DEM_BYPASS_DATA2, 0x00 },
+       { WSA883X_DEM_BYPASS_DATA3, 0x00 },
+       { WSA883X_WAVG_CTL, 0x06 },
+       { WSA883X_WAVG_LRA_PER_0, 0xD1 },
+       { WSA883X_WAVG_LRA_PER_1, 0x00 },
+       { WSA883X_WAVG_DELTA_THETA_0, 0xE6 },
+       { WSA883X_WAVG_DELTA_THETA_1, 0x04 },
+       { WSA883X_WAVG_DIRECT_AMP_0, 0x50 },
+       { WSA883X_WAVG_DIRECT_AMP_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP0_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP0_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP1_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP1_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP2_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP2_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP3_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP3_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP4_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP4_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP5_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP5_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP6_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP6_1, 0x00 },
+       { WSA883X_WAVG_PTRN_AMP7_0, 0x50 },
+       { WSA883X_WAVG_PTRN_AMP7_1, 0x00 },
+       { WSA883X_WAVG_PER_0_1, 0x88 },
+       { WSA883X_WAVG_PER_2_3, 0x88 },
+       { WSA883X_WAVG_PER_4_5, 0x88 },
+       { WSA883X_WAVG_PER_6_7, 0x88 },
+       { WSA883X_WAVG_STA, 0x00 },
+       { WSA883X_DRE_CTL_0, 0x70 },
+       { WSA883X_DRE_CTL_1, 0x08 },
+       { WSA883X_DRE_IDLE_DET_CTL, 0x1F },
+       { WSA883X_CLSH_CTL_0, 0x37 },
+       { WSA883X_CLSH_CTL_1, 0x81 },
+       { WSA883X_CLSH_V_HD_PA, 0x0F },
+       { WSA883X_CLSH_V_PA_MIN, 0x00 },
+       { WSA883X_CLSH_OVRD_VAL, 0x00 },
+       { WSA883X_CLSH_HARD_MAX, 0xFF },
+       { WSA883X_CLSH_SOFT_MAX, 0xF5 },
+       { WSA883X_CLSH_SIG_DP, 0x00 },
+       { WSA883X_TAGC_CTL, 0x10 },
+       { WSA883X_TAGC_TIME, 0x20 },
+       { WSA883X_TAGC_E2E_GAIN, 0x02 },
+       { WSA883X_TAGC_FORCE_VAL, 0x00 },
+       { WSA883X_VAGC_CTL, 0x00 },
+       { WSA883X_VAGC_TIME, 0x08 },
+       { WSA883X_VAGC_ATTN_LVL_1_2, 0x21 },
+       { WSA883X_VAGC_ATTN_LVL_3, 0x03 },
+       { WSA883X_INTR_MODE, 0x00 },
+       { WSA883X_INTR_MASK0, 0x90 },
+       { WSA883X_INTR_MASK1, 0x00 },
+       { WSA883X_INTR_STATUS0, 0x00 },
+       { WSA883X_INTR_STATUS1, 0x00 },
+       { WSA883X_INTR_CLEAR0, 0x00 },
+       { WSA883X_INTR_CLEAR1, 0x00 },
+       { WSA883X_INTR_LEVEL0, 0x00 },
+       { WSA883X_INTR_LEVEL1, 0x00 },
+       { WSA883X_INTR_SET0, 0x00 },
+       { WSA883X_INTR_SET1, 0x00 },
+       { WSA883X_INTR_TEST0, 0x00 },
+       { WSA883X_INTR_TEST1, 0x00 },
+       { WSA883X_OTP_CTRL0, 0x00 },
+       { WSA883X_OTP_CTRL1, 0x00 },
+       { WSA883X_HDRIVE_CTL_GROUP1, 0x00 },
+       { WSA883X_PIN_CTL, 0x04 },
+       { WSA883X_PIN_CTL_OE, 0x00 },
+       { WSA883X_PIN_WDATA_IOPAD, 0x00 },
+       { WSA883X_PIN_STATUS, 0x00 },
+       { WSA883X_I2C_SLAVE_CTL, 0x00 },
+       { WSA883X_PDM_TEST_MODE, 0x00 },
+       { WSA883X_ATE_TEST_MODE, 0x00 },
+       { WSA883X_DIG_DEBUG_MODE, 0x00 },
+       { WSA883X_DIG_DEBUG_SEL, 0x00 },
+       { WSA883X_DIG_DEBUG_EN, 0x00 },
+       { WSA883X_SWR_HM_TEST0, 0x08 },
+       { WSA883X_SWR_HM_TEST1, 0x00 },
+       { WSA883X_SWR_PAD_CTL, 0x37 },
+       { WSA883X_TADC_DETECT_DBG_CTL, 0x00 },
+       { WSA883X_TADC_DEBUG_MSB, 0x00 },
+       { WSA883X_TADC_DEBUG_LSB, 0x00 },
+       { WSA883X_SAMPLE_EDGE_SEL, 0x7F },
+       { WSA883X_SWR_EDGE_SEL, 0x00 },
+       { WSA883X_TEST_MODE_CTL, 0x04 },
+       { WSA883X_IOPAD_CTL, 0x00 },
+       { WSA883X_ANA_CSR_DBG_ADD, 0x00 },
+       { WSA883X_ANA_CSR_DBG_CTL, 0x12 },
+       { WSA883X_SPARE_R, 0x00 },
+       { WSA883X_SPARE_0, 0x00 },
+       { WSA883X_SPARE_1, 0x00 },
+       { WSA883X_SPARE_2, 0x00 },
+       { WSA883X_SCODE, 0x00 },
+       { WSA883X_OTP_REG_0, 0x05 },
+       { WSA883X_OTP_REG_1, 0xFF },
+       { WSA883X_OTP_REG_2, 0xC0 },
+       { WSA883X_OTP_REG_3, 0xFF },
+       { WSA883X_OTP_REG_4, 0xC0 },
+       { WSA883X_OTP_REG_5, 0xFF },
+       { WSA883X_OTP_REG_6, 0xFF },
+       { WSA883X_OTP_REG_7, 0xFF },
+       { WSA883X_OTP_REG_8, 0xFF },
+       { WSA883X_OTP_REG_9, 0xFF },
+       { WSA883X_OTP_REG_10, 0xFF },
+       { WSA883X_OTP_REG_11, 0xFF },
+       { WSA883X_OTP_REG_12, 0xFF },
+       { WSA883X_OTP_REG_13, 0xFF },
+       { WSA883X_OTP_REG_14, 0xFF },
+       { WSA883X_OTP_REG_15, 0xFF },
+       { WSA883X_OTP_REG_16, 0xFF },
+       { WSA883X_OTP_REG_17, 0xFF },
+       { WSA883X_OTP_REG_18, 0xFF },
+       { WSA883X_OTP_REG_19, 0xFF },
+       { WSA883X_OTP_REG_20, 0xFF },
+       { WSA883X_OTP_REG_21, 0xFF },
+       { WSA883X_OTP_REG_22, 0xFF },
+       { WSA883X_OTP_REG_23, 0xFF },
+       { WSA883X_OTP_REG_24, 0x37 },
+       { WSA883X_OTP_REG_25, 0x3F },
+       { WSA883X_OTP_REG_26, 0x03 },
+       { WSA883X_OTP_REG_27, 0x00 },
+       { WSA883X_OTP_REG_28, 0x00 },
+       { WSA883X_OTP_REG_29, 0x00 },
+       { WSA883X_OTP_REG_30, 0x00 },
+       { WSA883X_OTP_REG_31, 0x03 },
+       { WSA883X_OTP_REG_32, 0x00 },
+       { WSA883X_OTP_REG_33, 0xFF },
+       { WSA883X_OTP_REG_34, 0x00 },
+       { WSA883X_OTP_REG_35, 0x00 },
+       { WSA883X_OTP_REG_63, 0x40 },
+       { WSA883X_EMEM_0, 0x00 },
+       { WSA883X_EMEM_1, 0x00 },
+       { WSA883X_EMEM_2, 0x00 },
+       { WSA883X_EMEM_3, 0x00 },
+       { WSA883X_EMEM_4, 0x00 },
+       { WSA883X_EMEM_5, 0x00 },
+       { WSA883X_EMEM_6, 0x00 },
+       { WSA883X_EMEM_7, 0x00 },
+       { WSA883X_EMEM_8, 0x00 },
+       { WSA883X_EMEM_9, 0x00 },
+       { WSA883X_EMEM_10, 0x00 },
+       { WSA883X_EMEM_11, 0x00 },
+       { WSA883X_EMEM_12, 0x00 },
+       { WSA883X_EMEM_13, 0x00 },
+       { WSA883X_EMEM_14, 0x00 },
+       { WSA883X_EMEM_15, 0x00 },
+       { WSA883X_EMEM_16, 0x00 },
+       { WSA883X_EMEM_17, 0x00 },
+       { WSA883X_EMEM_18, 0x00 },
+       { WSA883X_EMEM_19, 0x00 },
+       { WSA883X_EMEM_20, 0x00 },
+       { WSA883X_EMEM_21, 0x00 },
+       { WSA883X_EMEM_22, 0x00 },
+       { WSA883X_EMEM_23, 0x00 },
+       { WSA883X_EMEM_24, 0x00 },
+       { WSA883X_EMEM_25, 0x00 },
+       { WSA883X_EMEM_26, 0x00 },
+       { WSA883X_EMEM_27, 0x00 },
+       { WSA883X_EMEM_28, 0x00 },
+       { WSA883X_EMEM_29, 0x00 },
+       { WSA883X_EMEM_30, 0x00 },
+       { WSA883X_EMEM_31, 0x00 },
+       { WSA883X_EMEM_32, 0x00 },
+       { WSA883X_EMEM_33, 0x00 },
+       { WSA883X_EMEM_34, 0x00 },
+       { WSA883X_EMEM_35, 0x00 },
+       { WSA883X_EMEM_36, 0x00 },
+       { WSA883X_EMEM_37, 0x00 },
+       { WSA883X_EMEM_38, 0x00 },
+       { WSA883X_EMEM_39, 0x00 },
+       { WSA883X_EMEM_40, 0x00 },
+       { WSA883X_EMEM_41, 0x00 },
+       { WSA883X_EMEM_42, 0x00 },
+       { WSA883X_EMEM_43, 0x00 },
+       { WSA883X_EMEM_44, 0x00 },
+       { WSA883X_EMEM_45, 0x00 },
+       { WSA883X_EMEM_46, 0x00 },
+       { WSA883X_EMEM_47, 0x00 },
+       { WSA883X_EMEM_48, 0x00 },
+       { WSA883X_EMEM_49, 0x00 },
+       { WSA883X_EMEM_50, 0x00 },
+       { WSA883X_EMEM_51, 0x00 },
+       { WSA883X_EMEM_52, 0x00 },
+       { WSA883X_EMEM_53, 0x00 },
+       { WSA883X_EMEM_54, 0x00 },
+       { WSA883X_EMEM_55, 0x00 },
+       { WSA883X_EMEM_56, 0x00 },
+       { WSA883X_EMEM_57, 0x00 },
+       { WSA883X_EMEM_58, 0x00 },
+       { WSA883X_EMEM_59, 0x00 },
+       { WSA883X_EMEM_60, 0x00 },
+       { WSA883X_EMEM_61, 0x00 },
+       { WSA883X_EMEM_62, 0x00 },
+       { WSA883X_EMEM_63, 0x00 },
+};
+
+static bool wsa883x_readonly_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WSA883X_DOUT_MSB:
+       case WSA883X_DOUT_LSB:
+       case WSA883X_STATUS:
+       case WSA883X_PA_STATUS0:
+       case WSA883X_PA_STATUS1:
+       case WSA883X_PA_STATUS2:
+       case WSA883X_STATUS_0:
+       case WSA883X_STATUS_1:
+       case WSA883X_CHIP_ID0:
+       case WSA883X_CHIP_ID1:
+       case WSA883X_CHIP_ID2:
+       case WSA883X_CHIP_ID3:
+       case WSA883X_BUS_ID:
+       case WSA883X_PA_FSM_STA:
+       case WSA883X_PA_FSM_ERR_COND:
+       case WSA883X_TEMP_MSB:
+       case WSA883X_TEMP_LSB:
+       case WSA883X_VBAT_DIN_MSB:
+       case WSA883X_VBAT_DIN_LSB:
+       case WSA883X_VBAT_DOUT:
+       case WSA883X_SDM_PDM9_LSB:
+       case WSA883X_SDM_PDM9_MSB:
+       case WSA883X_WAVG_STA:
+       case WSA883X_INTR_STATUS0:
+       case WSA883X_INTR_STATUS1:
+       case WSA883X_OTP_CTRL1:
+       case WSA883X_PIN_STATUS:
+       case WSA883X_ATE_TEST_MODE:
+       case WSA883X_SWR_HM_TEST1:
+       case WSA883X_SPARE_R:
+       case WSA883X_OTP_REG_0:
+               return true;
+       }
+       return false;
+}
+
+static bool wsa883x_writeable_register(struct device *dev, unsigned int reg)
+{
+       return !wsa883x_readonly_register(dev, reg);
+}
+
+static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
+{
+       return wsa883x_readonly_register(dev, reg);
+}
+
+static struct regmap_config wsa883x_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wsa883x_defaults,
+       .max_register = WSA883X_MAX_REGISTER,
+       .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults),
+       .volatile_reg = wsa883x_volatile_register,
+       .writeable_reg = wsa883x_writeable_register,
+       .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+       .val_format_endian = REGMAP_ENDIAN_NATIVE,
+       .can_multi_write = true,
+       .use_single_read = true,
+};
+
+static const struct reg_sequence reg_init[] = {
+       {WSA883X_PA_FSM_BYP, 0x00},
+       {WSA883X_ADC_6, 0x02},
+       {WSA883X_CDC_SPK_DSM_A2_0, 0x0A},
+       {WSA883X_CDC_SPK_DSM_A2_1, 0x08},
+       {WSA883X_CDC_SPK_DSM_A3_0, 0xF3},
+       {WSA883X_CDC_SPK_DSM_A3_1, 0x07},
+       {WSA883X_CDC_SPK_DSM_A4_0, 0x79},
+       {WSA883X_CDC_SPK_DSM_A4_1, 0x02},
+       {WSA883X_CDC_SPK_DSM_A5_0, 0x0B},
+       {WSA883X_CDC_SPK_DSM_A5_1, 0x02},
+       {WSA883X_CDC_SPK_DSM_A6_0, 0x8A},
+       {WSA883X_CDC_SPK_DSM_A7_0, 0x9B},
+       {WSA883X_CDC_SPK_DSM_C_0, 0x68},
+       {WSA883X_CDC_SPK_DSM_C_1, 0x54},
+       {WSA883X_CDC_SPK_DSM_C_2, 0xF2},
+       {WSA883X_CDC_SPK_DSM_C_3, 0x20},
+       {WSA883X_CDC_SPK_DSM_R1, 0x83},
+       {WSA883X_CDC_SPK_DSM_R2, 0x7F},
+       {WSA883X_CDC_SPK_DSM_R3, 0x9D},
+       {WSA883X_CDC_SPK_DSM_R4, 0x82},
+       {WSA883X_CDC_SPK_DSM_R5, 0x8B},
+       {WSA883X_CDC_SPK_DSM_R6, 0x9B},
+       {WSA883X_CDC_SPK_DSM_R7, 0x3F},
+       {WSA883X_VBAT_SNS, 0x20},
+       {WSA883X_DRE_CTL_0, 0x92},
+       {WSA883X_DRE_IDLE_DET_CTL, 0x0F},
+       {WSA883X_CURRENT_LIMIT, 0xC4},
+       {WSA883X_VAGC_TIME, 0x0F},
+       {WSA883X_VAGC_ATTN_LVL_1_2, 0x00},
+       {WSA883X_VAGC_ATTN_LVL_3, 0x01},
+       {WSA883X_VAGC_CTL, 0x01},
+       {WSA883X_TAGC_CTL, 0x1A},
+       {WSA883X_TAGC_TIME, 0x2C},
+       {WSA883X_TEMP_CONFIG0, 0x02},
+       {WSA883X_TEMP_CONFIG1, 0x02},
+       {WSA883X_OTP_REG_1, 0x49},
+       {WSA883X_OTP_REG_2, 0x80},
+       {WSA883X_OTP_REG_3, 0xC9},
+       {WSA883X_OTP_REG_4, 0x40},
+       {WSA883X_TAGC_CTL, 0x1B},
+       {WSA883X_ADC_2, 0x00},
+       {WSA883X_ADC_7, 0x85},
+       {WSA883X_ADC_7, 0x87},
+       {WSA883X_CKWD_CTL_0, 0x14},
+       {WSA883X_CKWD_CTL_1, 0x1B},
+       {WSA883X_GMAMP_SUP1, 0xE2},
+};
+
+static void wsa883x_init(struct wsa883x_priv *wsa883x)
+{
+       struct regmap *regmap = wsa883x->regmap;
+       int variant, version;
+
+       regmap_read(regmap, WSA883X_OTP_REG_0, &variant);
+       wsa883x->variant = variant & WSA883X_ID_MASK;
+
+       regmap_read(regmap, WSA883X_CHIP_ID0, &version);
+       wsa883x->version = version;
+
+       switch (wsa883x->variant) {
+       case WSA8830:
+               dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n",
+                        wsa883x->version);
+               break;
+       case WSA8835:
+               dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n",
+                        wsa883x->version);
+               break;
+       case WSA8832:
+               dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n",
+                        wsa883x->version);
+               break;
+       case WSA8835_V2:
+               dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n",
+                        wsa883x->version);
+               break;
+       default:
+               break;
+       }
+
+       wsa883x->comp_offset = COMP_OFFSET2;
+
+       /* Initial settings */
+       regmap_multi_reg_write(regmap, reg_init, ARRAY_SIZE(reg_init));
+
+       if (wsa883x->variant == WSA8830 || wsa883x->variant == WSA8832) {
+               wsa883x->comp_offset = COMP_OFFSET3;
+               regmap_update_bits(regmap, WSA883X_DRE_CTL_0,
+                                  WSA883X_DRE_OFFSET_MASK,
+                                  wsa883x->comp_offset);
+       }
+}
+
+static int wsa883x_update_status(struct sdw_slave *slave,
+                                enum sdw_slave_status status)
+{
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
+
+       if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0)
+               wsa883x_init(wsa883x);
+
+       return 0;
+}
+
+static int wsa883x_port_prep(struct sdw_slave *slave,
+                            struct sdw_prepare_ch *prepare_ch,
+                            enum sdw_port_prep_ops state)
+{
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev);
+
+       if (state == SDW_OPS_PORT_POST_PREP)
+               wsa883x->port_prepared[prepare_ch->num - 1] = true;
+       else
+               wsa883x->port_prepared[prepare_ch->num - 1] = false;
+
+       return 0;
+}
+
+static struct sdw_slave_ops wsa883x_slave_ops = {
+       .update_status = wsa883x_update_status,
+       .port_prep = wsa883x_port_prep,
+};
+
+static int wsa_dev_mode_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.enumerated.item[0] = wsa883x->dev_mode;
+
+       return 0;
+}
+
+static int wsa_dev_mode_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+       if (wsa883x->dev_mode == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       wsa883x->dev_mode = ucontrol->value.enumerated.item[0];
+
+       return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(pa_gain, -300, 150, -300);
+
+static int wsa883x_get_swr_port(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp);
+       struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+       int portidx = mixer->reg;
+
+       ucontrol->value.integer.value[0] = data->port_enable[portidx];
+
+       return 0;
+}
+
+static int wsa883x_set_swr_port(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct wsa883x_priv *data = snd_soc_component_get_drvdata(comp);
+       struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
+       int portidx = mixer->reg;
+
+       if (ucontrol->value.integer.value[0]) {
+               if (data->port_enable[portidx])
+                       return 0;
+
+               data->port_enable[portidx] = true;
+       } else {
+               if (!data->port_enable[portidx])
+                       return 0;
+
+               data->port_enable[portidx] = false;
+       }
+
+       return 1;
+}
+
+static int wsa883x_get_comp_offset(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.integer.value[0] = wsa883x->comp_offset;
+
+       return 0;
+}
+
+static int wsa883x_set_comp_offset(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+       if (wsa883x->comp_offset == ucontrol->value.integer.value[0])
+               return 0;
+
+       wsa883x->comp_offset = ucontrol->value.integer.value[0];
+
+       return 1;
+}
+
+static int wsa883x_codec_probe(struct snd_soc_component *comp)
+{
+       struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(comp);
+
+       snd_soc_component_init_regmap(comp, wsa883x->regmap);
+
+       return 0;
+}
+
+static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               switch (wsa883x->dev_mode) {
+               case RECEIVER:
+                       snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE,
+                                                     WSA883X_RXD_MODE_MASK,
+                                                     WSA883X_RXD_MODE_HIFI);
+                       snd_soc_component_write_field(component, WSA883X_SPKR_PWM_CLK_CTL,
+                                                     WSA883X_SPKR_PWM_FREQ_SEL_MASK,
+                                                     WSA883X_SPKR_PWM_FREQ_F600KHZ);
+                       snd_soc_component_write_field(component, WSA883X_DRE_CTL_0,
+                                                      WSA883X_DRE_PROG_DELAY_MASK, 0x0);
+                       break;
+               case SPEAKER:
+                       snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE,
+                                                     WSA883X_RXD_MODE_MASK,
+                                                     WSA883X_RXD_MODE_NORMAL);
+                       snd_soc_component_write_field(component, WSA883X_SPKR_PWM_CLK_CTL,
+                                                     WSA883X_SPKR_PWM_FREQ_SEL_MASK,
+                                                     WSA883X_SPKR_PWM_FREQ_F300KHZ);
+                       snd_soc_component_write_field(component, WSA883X_DRE_CTL_0,
+                                                      WSA883X_DRE_PROG_DELAY_MASK, 0x9);
+                       break;
+               default:
+                       break;
+               }
+
+               snd_soc_component_write_field(component, WSA883X_DRE_CTL_1,
+                                             WSA883X_DRE_GAIN_EN_MASK,
+                                             WSA883X_DRE_GAIN_FROM_CSR);
+               if (wsa883x->port_enable[WSA883X_PORT_COMP])
+                       snd_soc_component_write_field(component, WSA883X_DRE_CTL_0,
+                                                     WSA883X_DRE_OFFSET_MASK,
+                                                     wsa883x->comp_offset);
+               snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL,
+                                             WSA883X_VBAT_ADC_COEF_SEL_MASK,
+                                             WSA883X_VBAT_ADC_COEF_F_1DIV16);
+               snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL,
+                                             WSA883X_VBAT_ADC_FLT_EN_MASK, 0x1);
+               snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL,
+                                             WSA883X_PDM_EN_MASK,
+                                             WSA883X_PDM_ENABLE);
+               snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
+                                             WSA883X_GLOBAL_PA_EN_MASK,
+                                             WSA883X_GLOBAL_PA_ENABLE);
+
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL,
+                                             WSA883X_VBAT_ADC_FLT_EN_MASK, 0x0);
+               snd_soc_component_write_field(component, WSA883X_VBAT_ADC_FLT_CTL,
+                                             WSA883X_VBAT_ADC_COEF_SEL_MASK,
+                                             WSA883X_VBAT_ADC_COEF_F_1DIV2);
+               snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
+                                             WSA883X_GLOBAL_PA_EN_MASK, 0);
+               snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL,
+                                             WSA883X_PDM_EN_MASK, 0);
+               break;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget wsa883x_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("IN"),
+       SND_SOC_DAPM_SPK("SPKR", wsa883x_spkr_event),
+};
+
+static const struct snd_kcontrol_new wsa883x_snd_controls[] = {
+       SOC_SINGLE_RANGE_TLV("PA Volume", WSA883X_DRE_CTL_1, 1,
+                            0x0, 0x1f, 1, pa_gain),
+       SOC_ENUM_EXT("WSA MODE", wsa_dev_mode_enum,
+                    wsa_dev_mode_get, wsa_dev_mode_put),
+       SOC_SINGLE_EXT("COMP Offset", SND_SOC_NOPM, 0, 4, 0,
+                      wsa883x_get_comp_offset, wsa883x_set_comp_offset),
+       SOC_SINGLE_EXT("DAC Switch", WSA883X_PORT_DAC, 0, 1, 0,
+                      wsa883x_get_swr_port, wsa883x_set_swr_port),
+       SOC_SINGLE_EXT("COMP Switch", WSA883X_PORT_COMP, 0, 1, 0,
+                      wsa883x_get_swr_port, wsa883x_set_swr_port),
+       SOC_SINGLE_EXT("BOOST Switch", WSA883X_PORT_BOOST, 0, 1, 0,
+                      wsa883x_get_swr_port, wsa883x_set_swr_port),
+       SOC_SINGLE_EXT("VISENSE Switch", WSA883X_PORT_VISENSE, 0, 1, 0,
+                      wsa883x_get_swr_port, wsa883x_set_swr_port),
+};
+
+static const struct snd_soc_dapm_route wsa883x_audio_map[] = {
+       {"SPKR", NULL, "IN"},
+};
+
+static const struct snd_soc_component_driver wsa883x_component_drv = {
+       .name = "WSA883x",
+       .probe = wsa883x_codec_probe,
+       .controls = wsa883x_snd_controls,
+       .num_controls = ARRAY_SIZE(wsa883x_snd_controls),
+       .dapm_widgets = wsa883x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets),
+       .dapm_routes = wsa883x_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map),
+};
+
+static int wsa883x_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev);
+       int i;
+
+       wsa883x->active_ports = 0;
+       for (i = 0; i < WSA883X_MAX_SWR_PORTS; i++) {
+               if (!wsa883x->port_enable[i])
+                       continue;
+
+               wsa883x->port_config[wsa883x->active_ports] = wsa883x_pconfig[i];
+               wsa883x->active_ports++;
+       }
+
+       wsa883x->sconfig.frame_rate = params_rate(params);
+
+       return sdw_stream_add_slave(wsa883x->slave, &wsa883x->sconfig,
+                                   wsa883x->port_config, wsa883x->active_ports,
+                                   wsa883x->sruntime);
+}
+
+static int wsa883x_hw_free(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
+{
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev);
+
+       sdw_stream_remove_slave(wsa883x->slave, wsa883x->sruntime);
+
+       return 0;
+}
+
+static int wsa883x_set_sdw_stream(struct snd_soc_dai *dai,
+                                 void *stream, int direction)
+{
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(dai->dev);
+
+       wsa883x->sruntime = stream;
+
+       return 0;
+}
+
+static int wsa883x_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct snd_soc_component *component = dai->component;
+
+       if (mute) {
+               snd_soc_component_write_field(component, WSA883X_DRE_CTL_1,
+                                             WSA883X_DRE_GAIN_EN_MASK, 0);
+               snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
+                                             WSA883X_GLOBAL_PA_EN_MASK, 0);
+
+       } else {
+               snd_soc_component_write_field(component, WSA883X_DRE_CTL_1,
+                                             WSA883X_DRE_GAIN_EN_MASK,
+                                             WSA883X_DRE_GAIN_FROM_CSR);
+               snd_soc_component_write_field(component, WSA883X_PA_FSM_CTL,
+                                             WSA883X_GLOBAL_PA_EN_MASK, 1);
+
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops wsa883x_dai_ops = {
+       .hw_params = wsa883x_hw_params,
+       .hw_free = wsa883x_hw_free,
+       .mute_stream = wsa883x_digital_mute,
+       .set_stream = wsa883x_set_sdw_stream,
+};
+
+static struct snd_soc_dai_driver wsa883x_dais[] = {
+       {
+               .name = "SPKR",
+               .playback = {
+                       .stream_name = "SPKR Playback",
+                       .rates = WSA883X_RATES | WSA883X_FRAC_RATES,
+                       .formats = WSA883X_FORMATS,
+                       .rate_max = 8000,
+                       .rate_min = 352800,
+                       .channels_min = 1,
+                       .channels_max = 1,
+               },
+               .ops = &wsa883x_dai_ops,
+       },
+};
+
+static int wsa883x_probe(struct sdw_slave *pdev,
+                        const struct sdw_device_id *id)
+{
+       struct wsa883x_priv *wsa883x;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       wsa883x = devm_kzalloc(&pdev->dev, sizeof(*wsa883x), GFP_KERNEL);
+       if (!wsa883x)
+               return -ENOMEM;
+
+       wsa883x->vdd = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(wsa883x->vdd)) {
+               dev_err(dev, "No vdd regulator found\n");
+               return PTR_ERR(wsa883x->vdd);
+       }
+
+       ret = regulator_enable(wsa883x->vdd);
+       if (ret) {
+               dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
+               return ret;
+       }
+
+       wsa883x->sd_n = devm_gpiod_get_optional(&pdev->dev, "powerdown",
+                                               GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+       if (IS_ERR(wsa883x->sd_n)) {
+               dev_err(&pdev->dev, "Shutdown Control GPIO not found\n");
+               ret = PTR_ERR(wsa883x->sd_n);
+               goto err;
+       }
+
+       dev_set_drvdata(&pdev->dev, wsa883x);
+       wsa883x->slave = pdev;
+       wsa883x->dev = &pdev->dev;
+       wsa883x->sconfig.ch_count = 1;
+       wsa883x->sconfig.bps = 1;
+       wsa883x->sconfig.direction = SDW_DATA_DIR_RX;
+       wsa883x->sconfig.type = SDW_STREAM_PDM;
+
+       pdev->prop.sink_ports = GENMASK(WSA883X_MAX_SWR_PORTS, 0);
+       pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
+       pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+       gpiod_direction_output(wsa883x->sd_n, 1);
+
+       wsa883x->regmap = devm_regmap_init_sdw(pdev, &wsa883x_regmap_config);
+       if (IS_ERR(wsa883x->regmap)) {
+               dev_err(&pdev->dev, "regmap_init failed\n");
+               ret = PTR_ERR(wsa883x->regmap);
+               goto err;
+       }
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &wsa883x_component_drv,
+                                              wsa883x_dais,
+                                              ARRAY_SIZE(wsa883x_dais));
+err:
+       if (ret)
+               regulator_disable(wsa883x->vdd);
+
+       return ret;
+
+}
+
+static int __maybe_unused wsa883x_runtime_suspend(struct device *dev)
+{
+       struct regmap *regmap = dev_get_regmap(dev, NULL);
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(dev);
+
+       gpiod_direction_output(wsa883x->sd_n, 0);
+
+       regcache_cache_only(regmap, true);
+       regcache_mark_dirty(regmap);
+
+       regulator_disable(wsa883x->vdd);
+       return 0;
+}
+
+static int __maybe_unused wsa883x_runtime_resume(struct device *dev)
+{
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       struct regmap *regmap = dev_get_regmap(dev, NULL);
+       struct wsa883x_priv *wsa883x = dev_get_drvdata(dev);
+       unsigned long time;
+       int ret;
+
+       ret = regulator_enable(wsa883x->vdd);
+       if (ret) {
+               dev_err(dev, "Failed to enable vdd regulator (%d)\n", ret);
+               return ret;
+       }
+
+       gpiod_direction_output(wsa883x->sd_n, 1);
+
+       time = wait_for_completion_timeout(&slave->initialization_complete,
+                                          msecs_to_jiffies(WSA883X_PROBE_TIMEOUT));
+       if (!time) {
+               dev_err(dev, "Initialization not complete, timed out\n");
+               gpiod_direction_output(wsa883x->sd_n, 0);
+               regulator_disable(wsa883x->vdd);
+               return -ETIMEDOUT;
+       }
+
+       usleep_range(20000, 20010);
+       regcache_cache_only(regmap, false);
+       regcache_sync(regmap);
+
+       return 0;
+}
+
+static const struct dev_pm_ops wsa883x_pm_ops = {
+       SET_RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL)
+};
+
+static const struct sdw_device_id wsa883x_swr_id[] = {
+       SDW_SLAVE_ENTRY(0x0217, 0x0202, 0),
+       {},
+};
+
+MODULE_DEVICE_TABLE(sdw, wsa883x_swr_id);
+
+static struct sdw_driver wsa883x_codec_driver = {
+       .driver = {
+               .name = "wsa883x-codec",
+               .pm = &wsa883x_pm_ops,
+               .suppress_bind_attrs = true,
+       },
+       .probe = wsa883x_probe,
+       .ops = &wsa883x_slave_ops,
+       .id_table = wsa883x_swr_id,
+};
+
+module_sdw_driver(wsa883x_codec_driver);
+
+MODULE_DESCRIPTION("WSA883x codec driver");
+MODULE_LICENSE("GPL");
index 6cae0fb08093b01d110c65a227c2087d7e85edc7..c3d0a2a7c36f2a362f174858ba892d1e5db3e5c2 100644 (file)
@@ -385,7 +385,6 @@ static const struct snd_soc_component_driver zl38_component_dev = {
        .dapm_routes            = zl38_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(zl38_dapm_routes),
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val)
index 1edac3e10f345746338ec98adb437705134e5616..7f7dd07c63b2f1fdcfb710e30f0250c850fa14ce 100644 (file)
@@ -357,20 +357,20 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        int ret = 0;
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                if (dev->capability & DW_I2S_SLAVE)
                        ret = 0;
                else
                        ret = -EINVAL;
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                if (dev->capability & DW_I2S_MASTER)
                        ret = 0;
                else
                        ret = -EINVAL;
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BC_FP:
+       case SND_SOC_DAIFMT_BP_FC:
                ret = -EINVAL;
                break;
        default:
@@ -449,9 +449,10 @@ static int dw_i2s_resume(struct snd_soc_component *component)
 #endif
 
 static const struct snd_soc_component_driver dw_i2s_component = {
-       .name           = "dw-i2s",
-       .suspend        = dw_i2s_suspend,
-       .resume         = dw_i2s_resume,
+       .name                   = "dw-i2s",
+       .suspend                = dw_i2s_suspend,
+       .resume                 = dw_i2s_resume,
+       .legacy_dai_naming      = 1,
 };
 
 /*
index 10fa3875345338a39a5911011f24fe42146a4d52..614eceda6b9e3181b184beb16eb3c0c5612f787f 100644 (file)
@@ -19,6 +19,7 @@ config SND_SOC_FSL_SAI
        select REGMAP_MMIO
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_GENERIC_DMAENGINE_PCM
+       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add Synchronous Audio Interface (SAI)
          support for the Freescale CPUs.
@@ -59,6 +60,7 @@ config SND_SOC_FSL_SPDIF
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC)
        select BITREVERSE
+       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add Sony/Philips Digital Interface (SPDIF)
          support for the Freescale CPUs.
@@ -80,6 +82,7 @@ config SND_SOC_FSL_MICFIL
        select REGMAP_MMIO
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_GENERIC_DMAENGINE_PCM
+       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add Pulse Density Modulation microphone
          interface (MICFIL) support for NXP.
index d9a0d4768c4d5627358a987544d405aae7940434..c836848ef0a65ecce8e6bf970fa48f6bcf91d33c 100644 (file)
@@ -537,6 +537,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        struct device *codec_dev = NULL;
        const char *codec_dai_name;
        const char *codec_dev_name;
+       u32 asrc_fmt = 0;
        u32 width;
        int ret;
 
@@ -829,8 +830,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
                        goto asrc_fail;
                }
 
-               ret = of_property_read_u32(asrc_np, "fsl,asrc-format",
-                                          &priv->asrc_format);
+               ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt);
+               priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
                if (ret) {
                        /* Fallback to old binding; translate to asrc_format */
                        ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
index 20a9f8e924b339c302706187cafdd77d0040e88a..aa5edf32d988955ba08178e1d96518b2e5406213 100644 (file)
@@ -1066,6 +1066,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
        struct resource *res;
        void __iomem *regs;
        int irq, ret, i;
+       u32 asrc_fmt = 0;
        u32 map_idx;
        char tmp[16];
        u32 width;
@@ -1174,7 +1175,8 @@ static int fsl_asrc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format);
+       ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
+       asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
        if (ret) {
                ret = of_property_read_u32(np, "fsl,asrc-width", &width);
                if (ret) {
@@ -1197,7 +1199,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
                }
        }
 
-       if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) {
+       if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) {
                dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n");
                asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
        }
index 5038faf035cbaff6d613b41ba3d656a69016ea03..12ddf2320f2db6de1fd4edfd0ada335d3445dcc3 100644 (file)
@@ -114,8 +114,8 @@ static int fsl_asrc_dma_trigger(struct snd_soc_component *component,
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               dmaengine_terminate_all(pair->dma_chan[OUT]);
-               dmaengine_terminate_all(pair->dma_chan[IN]);
+               dmaengine_terminate_async(pair->dma_chan[OUT]);
+               dmaengine_terminate_async(pair->dma_chan[IN]);
                break;
        default:
                return -EINVAL;
@@ -129,6 +129,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
                                  struct snd_pcm_hw_params *params)
 {
        enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+       enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL;
@@ -139,6 +140,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
        struct snd_soc_component *component_be = NULL;
        struct fsl_asrc *asrc = pair->asrc;
        struct dma_slave_config config_fe, config_be;
+       struct sdma_peripheral_config audio_config;
        enum asrc_pair_index index = pair->index;
        struct device *dev = component->dev;
        struct device_node *of_dma_node;
@@ -221,6 +223,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
                /* Get DMA request of Back-End */
                tmp_data = tmp_chan->private;
                pair->dma_data.dma_request = tmp_data->dma_request;
+               be_peripheral_type = tmp_data->peripheral_type;
                if (!be_chan)
                        dma_release_channel(tmp_chan);
 
@@ -268,6 +271,17 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
        config_be.dst_addr_width = buswidth;
        config_be.dst_maxburst = dma_params_be->maxburst;
 
+       memset(&audio_config, 0, sizeof(audio_config));
+       config_be.peripheral_config = &audio_config;
+       config_be.peripheral_size  = sizeof(audio_config);
+
+       if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
+                  be_peripheral_type == IMX_DMATYPE_SPDIF))
+               audio_config.n_fifos_dst = 2;
+       if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
+                   be_peripheral_type == IMX_DMATYPE_SPDIF))
+               audio_config.n_fifos_src = 2;
+
        if (tx) {
                config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
                config_be.dst_addr = dma_params_be->addr;
@@ -441,5 +455,6 @@ struct snd_soc_component_driver fsl_asrc_component = {
        .close          = fsl_asrc_dma_shutdown,
        .pointer        = fsl_asrc_dma_pcm_pointer,
        .pcm_construct  = fsl_asrc_dma_pcm_new,
+       .legacy_dai_naming = 1,
 };
 EXPORT_SYMBOL_GPL(fsl_asrc_component);
index 422922146f2a53b10128f6bd81313c35f6190b1a..873295f59ad7b9dde877ce1f990bb098f77385ca 100644 (file)
@@ -103,7 +103,8 @@ static struct snd_soc_dai_driver fsl_aud2htx_dai = {
 };
 
 static const struct snd_soc_component_driver fsl_aud2htx_component = {
-       .name   = "fsl-aud2htx",
+       .name                   = "fsl-aud2htx",
+       .legacy_dai_naming      = 1,
 };
 
 static const struct reg_default fsl_aud2htx_reg_defaults[] = {
index 6dbb8c99f62688af4719421dde405c797fa9d670..43857b7a81c94b68e77658710abb4ac7f6b70a7a 100644 (file)
@@ -259,8 +259,8 @@ static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        /* For playback the AUDMIX is consumer, and for record is provider */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_BP_FP:
                break;
        default:
                return -EINVAL;
@@ -317,7 +317,7 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static const struct snd_soc_dai_ops fsl_audmix_dai_ops = {
-       .set_fmt      = fsl_audmix_dai_set_fmt,
+       .set_fmt  = fsl_audmix_dai_set_fmt,
        .trigger      = fsl_audmix_dai_trigger,
 };
 
index be14f84796cb437b073597957b142893ad723bee..3153d19136b29957df92d37eb8fdaed75b55fd5d 100644 (file)
@@ -476,7 +476,8 @@ static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc,
        struct fsl_asrc_pair *ctx;
        struct device *dev;
        u32 inrate, outrate, offset = 0;
-       u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt;
+       u32 in_s_rate, out_s_rate;
+       snd_pcm_format_t in_s_fmt, out_s_fmt;
        int ret, i;
 
        if (!easrc)
@@ -1572,9 +1573,10 @@ static struct snd_soc_dai_driver fsl_easrc_dai = {
 };
 
 static const struct snd_soc_component_driver fsl_easrc_component = {
-       .name           = "fsl-easrc-dai",
-       .controls       = fsl_easrc_snd_controls,
-       .num_controls   = ARRAY_SIZE(fsl_easrc_snd_controls),
+       .name                   = "fsl-easrc-dai",
+       .controls               = fsl_easrc_snd_controls,
+       .num_controls           = ARRAY_SIZE(fsl_easrc_snd_controls),
+       .legacy_dai_naming      = 1,
 };
 
 static const struct reg_default fsl_easrc_reg_defaults[] = {
@@ -1873,6 +1875,7 @@ static int fsl_easrc_probe(struct platform_device *pdev)
        struct resource *res;
        struct device_node *np;
        void __iomem *regs;
+       u32 asrc_fmt = 0;
        int ret, irq;
 
        easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL);
@@ -1933,13 +1936,14 @@ static int fsl_easrc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format);
+       ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
+       easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
        if (ret) {
                dev_err(dev, "failed to asrc format\n");
                return ret;
        }
 
-       if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) {
+       if (!(FSL_EASRC_FORMATS & (pcm_format_to_bits(easrc->asrc_format)))) {
                dev_warn(dev, "unsupported format, switching to S24_LE\n");
                easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
        }
index 86d5c360d4f53de17b7ca596465991d6f7988715..7c70dac52713772eb82db13b6ce6c568362ebd45 100644 (file)
@@ -569,7 +569,7 @@ struct fsl_easrc_io_params {
        unsigned int access_len;
        unsigned int fifo_wtmk;
        unsigned int sample_rate;
-       unsigned int sample_format;
+       snd_pcm_format_t sample_format;
        unsigned int norm_rate;
 };
 
index 1a2bdf8e76f00bae0025f8182a8b510eb922c304..5c21fc490fce1ac1161ac1ce6b1ddaf799a00036 100644 (file)
@@ -480,16 +480,16 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        /* DAI clock provider masks */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                esai_priv->consumer_mode = true;
                break;
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BP_FC:
                xccr |= ESAI_xCCR_xCKD;
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BC_FP:
                xccr |= ESAI_xCCR_xFSD;
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
                break;
        default:
@@ -824,7 +824,8 @@ static struct snd_soc_dai_driver fsl_esai_dai = {
 };
 
 static const struct snd_soc_component_driver fsl_esai_component = {
-       .name           = "fsl-esai",
+       .name                   = "fsl-esai",
+       .legacy_dai_naming      = 1,
 };
 
 static const struct reg_default fsl_esai_reg_defaults[] = {
index 7b88d52f27de20aade907304000d9d0e6a8d2e06..79ef4e269bc95a3ef248f9da4af8503b9ef70dd6 100644 (file)
@@ -24,6 +24,7 @@
 #include <sound/core.h>
 
 #include "fsl_micfil.h"
+#include "fsl_utils.h"
 
 #define MICFIL_OSR_DEFAULT     16
 
@@ -42,12 +43,15 @@ struct fsl_micfil {
        const struct fsl_micfil_soc_data *soc;
        struct clk *busclk;
        struct clk *mclk;
+       struct clk *pll8k_clk;
+       struct clk *pll11k_clk;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct sdma_peripheral_config sdmacfg;
        unsigned int dataline;
        char name[32];
        int irq[MICFIL_IRQ_LINES];
        enum quality quality;
+       int dc_remover;
 };
 
 struct fsl_micfil_soc_data {
@@ -263,6 +267,27 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
+static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int sample_rate)
+{
+       struct device *dev = &micfil->pdev->dev;
+       u64 ratio = sample_rate;
+       struct clk *clk;
+       int ret;
+
+       /* Get root clock */
+       clk = micfil->mclk;
+
+       /* Disable clock first, for it was enabled by pm_runtime */
+       clk_disable_unprepare(clk);
+       fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk,
+                                    micfil->pll11k_clk, ratio);
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
@@ -286,6 +311,10 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return ret;
 
+       ret = fsl_micfil_reparent_rootclk(micfil, rate);
+       if (ret)
+               return ret;
+
        ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8);
        if (ret)
                return ret;
@@ -317,12 +346,25 @@ static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
 static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev);
-       int ret;
+       struct device *dev = cpu_dai->dev;
+       unsigned int val = 0;
+       int ret, i;
 
-       micfil->quality = QUALITY_MEDIUM;
+       micfil->quality = QUALITY_VLOW0;
 
-       /* set default gain to max_gain */
-       regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x77777777);
+       /* set default gain to 2 */
+       regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
+
+       /* set DC Remover in bypass mode*/
+       for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++)
+               val |= MICFIL_DC_BYPASS << MICFIL_DC_CHX_SHIFT(i);
+       ret = regmap_update_bits(micfil->regmap, REG_MICFIL_DC_CTRL,
+                                MICFIL_DC_CTRL_CONFIG, val);
+       if (ret) {
+               dev_err(dev, "failed to set DC Remover mode bits\n");
+               return ret;
+       }
+       micfil->dc_remover = MICFIL_DC_BYPASS;
 
        snd_soc_dai_init_dma_data(cpu_dai, NULL,
                                  &micfil->dma_params_rx);
@@ -353,7 +395,7 @@ static const struct snd_soc_component_driver fsl_micfil_component = {
        .name           = "fsl-micfil-dai",
        .controls       = fsl_micfil_snd_controls,
        .num_controls   = ARRAY_SIZE(fsl_micfil_snd_controls),
-
+       .legacy_dai_naming      = 1,
 };
 
 /* REGMAP */
@@ -577,6 +619,9 @@ static int fsl_micfil_probe(struct platform_device *pdev)
                return PTR_ERR(micfil->busclk);
        }
 
+       fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk,
+                               &micfil->pll11k_clk);
+
        /* init regmap */
        regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(regs))
index 053caba3caf375958c7f80c30fe89905c1e32661..d60285dd07bc5c57588bee1b8c4a0d47da6fd9ff 100644 (file)
 #define MICFIL_FIFO_STAT_FIFOX_OVER(ch)        BIT(ch)
 #define MICFIL_FIFO_STAT_FIFOX_UNDER(ch)       BIT((ch) + 8)
 
+/* MICFIL DC Remover Control Register -- REG_MICFIL_DC_CTRL */
+#define MICFIL_DC_CTRL_CONFIG          GENMASK(15, 0)
+#define MICFIL_DC_CHX_SHIFT(ch)        ((ch) << 1)
+#define MICFIL_DC_CHX(ch)              GENMASK((((ch) << 1) + 1), ((ch) << 1))
+#define MICFIL_DC_CUTOFF_21HZ          0
+#define MICFIL_DC_CUTOFF_83HZ          1
+#define MICFIL_DC_CUTOFF_152Hz         2
+#define MICFIL_DC_BYPASS               3
+
 /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/
 #define MICFIL_VAD0_CTRL1_CHSEL                GENMASK(26, 24)
 #define MICFIL_VAD0_CTRL1_CICOSR       GENMASK(19, 16)
index ceaecbe3a25e4abf727c9bd2349611d2d9045e44..c1e2f671191b5fb0a60e3b7ec425c3cbf56035a0 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/moduleparam.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/pm.h>
 #define MQS_CLK_DIV_MASK               (0xFF << 0)
 #define MQS_CLK_DIV_SHIFT              (0)
 
+/**
+ * struct fsl_mqs_soc_data - soc specific data
+ *
+ * @use_gpr: control register is in General Purpose Register group
+ * @ctrl_off: control register offset
+ * @en_mask: enable bit mask
+ * @en_shift: enable bit shift
+ * @rst_mask: reset bit mask
+ * @rst_shift: reset bit shift
+ * @osr_mask: oversample bit mask
+ * @osr_shift: oversample bit shift
+ * @div_mask: clock divider mask
+ * @div_shift: clock divider bit shift
+ */
+struct fsl_mqs_soc_data {
+       bool use_gpr;
+       int  ctrl_off;
+       int  en_mask;
+       int  en_shift;
+       int  rst_mask;
+       int  rst_shift;
+       int  osr_mask;
+       int  osr_shift;
+       int  div_mask;
+       int  div_shift;
+};
+
 /* codec private data */
 struct fsl_mqs {
        struct regmap *regmap;
        struct clk *mclk;
        struct clk *ipg;
+       const struct fsl_mqs_soc_data *soc;
 
-       unsigned int reg_iomuxc_gpr2;
        unsigned int reg_mqs_ctrl;
-       bool use_gpr;
 };
 
 #define FSL_MQS_RATES  (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
@@ -65,19 +92,11 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream,
        res = mclk_rate % (32 * lrclk * 2 * 8);
 
        if (res == 0 && div > 0 && div <= 256) {
-               if (mqs_priv->use_gpr) {
-                       regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
-                                          IMX6SX_GPR2_MQS_CLK_DIV_MASK,
-                                          (div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT);
-                       regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
-                                          IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0);
-               } else {
-                       regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
-                                          MQS_CLK_DIV_MASK,
-                                          (div - 1) << MQS_CLK_DIV_SHIFT);
-                       regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
-                                          MQS_OVERSAMPLE_MASK, 0);
-               }
+               regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+                                  mqs_priv->soc->div_mask,
+                                  (div - 1) << mqs_priv->soc->div_shift);
+               regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+                                  mqs_priv->soc->osr_mask, 0);
        } else {
                dev_err(component->dev, "can't get proper divider\n");
        }
@@ -103,7 +122,7 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        }
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                break;
        default:
                return -EINVAL;
@@ -118,14 +137,9 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream,
        struct snd_soc_component *component = dai->component;
        struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
 
-       if (mqs_priv->use_gpr)
-               regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
-                                  IMX6SX_GPR2_MQS_EN_MASK,
-                                  1 << IMX6SX_GPR2_MQS_EN_SHIFT);
-       else
-               regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
-                                  MQS_EN_MASK,
-                                  1 << MQS_EN_SHIFT);
+       regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+                          mqs_priv->soc->en_mask,
+                          1 << mqs_priv->soc->en_shift);
        return 0;
 }
 
@@ -135,17 +149,12 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_component *component = dai->component;
        struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component);
 
-       if (mqs_priv->use_gpr)
-               regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2,
-                                  IMX6SX_GPR2_MQS_EN_MASK, 0);
-       else
-               regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL,
-                                  MQS_EN_MASK, 0);
+       regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off,
+                          mqs_priv->soc->en_mask, 0);
 }
 
 static const struct snd_soc_component_driver soc_codec_fsl_mqs = {
        .idle_bias_on = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_dai_ops fsl_mqs_dai_ops = {
@@ -191,12 +200,9 @@ static int fsl_mqs_probe(struct platform_device *pdev)
         * But in i.MX8QM/i.MX8QXP the control register is moved
         * to its own domain.
         */
-       if (of_device_is_compatible(np, "fsl,imx8qm-mqs"))
-               mqs_priv->use_gpr = false;
-       else
-               mqs_priv->use_gpr = true;
+       mqs_priv->soc = of_device_get_match_data(&pdev->dev);
 
-       if (mqs_priv->use_gpr) {
+       if (mqs_priv->soc->use_gpr) {
                gpr_np = of_parse_phandle(np, "gpr", 0);
                if (!gpr_np) {
                        dev_err(&pdev->dev, "failed to get gpr node by phandle\n");
@@ -280,12 +286,7 @@ static int fsl_mqs_runtime_resume(struct device *dev)
                return ret;
        }
 
-       if (mqs_priv->use_gpr)
-               regmap_write(mqs_priv->regmap, IOMUXC_GPR2,
-                            mqs_priv->reg_iomuxc_gpr2);
-       else
-               regmap_write(mqs_priv->regmap, REG_MQS_CTRL,
-                            mqs_priv->reg_mqs_ctrl);
+       regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl);
        return 0;
 }
 
@@ -293,12 +294,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev)
 {
        struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
 
-       if (mqs_priv->use_gpr)
-               regmap_read(mqs_priv->regmap, IOMUXC_GPR2,
-                           &mqs_priv->reg_iomuxc_gpr2);
-       else
-               regmap_read(mqs_priv->regmap, REG_MQS_CTRL,
-                           &mqs_priv->reg_mqs_ctrl);
+       regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl);
 
        clk_disable_unprepare(mqs_priv->mclk);
        clk_disable_unprepare(mqs_priv->ipg);
@@ -315,9 +311,49 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = {
                                pm_runtime_force_resume)
 };
 
+static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = {
+       .use_gpr = false,
+       .ctrl_off = REG_MQS_CTRL,
+       .en_mask  = MQS_EN_MASK,
+       .en_shift = MQS_EN_SHIFT,
+       .rst_mask = MQS_SW_RST_MASK,
+       .rst_shift = MQS_SW_RST_SHIFT,
+       .osr_mask = MQS_OVERSAMPLE_MASK,
+       .osr_shift = MQS_OVERSAMPLE_SHIFT,
+       .div_mask = MQS_CLK_DIV_MASK,
+       .div_shift = MQS_CLK_DIV_SHIFT,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = {
+       .use_gpr = true,
+       .ctrl_off = IOMUXC_GPR2,
+       .en_mask  = IMX6SX_GPR2_MQS_EN_MASK,
+       .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT,
+       .rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK,
+       .rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT,
+       .osr_mask  = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK,
+       .osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT,
+       .div_mask  = IMX6SX_GPR2_MQS_CLK_DIV_MASK,
+       .div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = {
+       .use_gpr = true,
+       .ctrl_off = 0x20,
+       .en_mask  = BIT(1),
+       .en_shift = 1,
+       .rst_mask = BIT(2),
+       .rst_shift = 2,
+       .osr_mask = BIT(3),
+       .osr_shift = 3,
+       .div_mask = GENMASK(15, 8),
+       .div_shift = 8,
+};
+
 static const struct of_device_id fsl_mqs_dt_ids[] = {
-       { .compatible = "fsl,imx8qm-mqs", },
-       { .compatible = "fsl,imx6sx-mqs", },
+       { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data },
+       { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data },
+       { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
index 19fd312508839aed26bf409649406825607b3335..bf94838bdbefe47ec9a614867f9e4b84663caaba 100644 (file)
@@ -135,7 +135,8 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = {
 };
 
 static const struct snd_soc_component_driver fsl_component = {
-       .name           = "fsl-rpmsg",
+       .name                   = "fsl-rpmsg",
+       .legacy_dai_naming      = 1,
 };
 
 static const struct fsl_rpmsg_soc_data imx7ulp_data = {
index e765da9a19e7e13846751eb7685eed9f09ac5de8..7523bb944b216da4c601e8c5332683fa669fa8cd 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
@@ -22,6 +23,7 @@
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 
 #include "fsl_sai.h"
+#include "fsl_utils.h"
 #include "imx-pcm.h"
 
 #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
@@ -30,7 +32,8 @@
 static const unsigned int fsl_sai_rates[] = {
        8000, 11025, 12000, 16000, 22050,
        24000, 32000, 44100, 48000, 64000,
-       88200, 96000, 176400, 192000
+       88200, 96000, 176400, 192000, 352800,
+       384000, 705600, 768000, 1411200, 2822400,
 };
 
 static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
@@ -56,6 +59,31 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
        return !sai->synchronous[dir] && sai->synchronous[adir];
 }
 
+static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk)
+{
+       struct pinctrl_state *state = NULL;
+
+       if (sai->is_pdm_mode) {
+               /* DSD512@44.1kHz, DSD512@48kHz */
+               if (bclk >= 22579200)
+                       state = pinctrl_lookup_state(sai->pinctrl, "dsd512");
+
+               /* Get default DSD state */
+               if (IS_ERR_OR_NULL(state))
+                       state = pinctrl_lookup_state(sai->pinctrl, "dsd");
+       } else {
+               /* 706k32b2c, 768k32b2c, etc */
+               if (bclk >= 45158400)
+                       state = pinctrl_lookup_state(sai->pinctrl, "pcm_b2m");
+       }
+
+       /* Get default state */
+       if (IS_ERR_OR_NULL(state))
+               state = pinctrl_lookup_state(sai->pinctrl, "default");
+
+       return state;
+}
+
 static irqreturn_t fsl_sai_isr(int irq, void *devid)
 {
        struct fsl_sai *sai = (struct fsl_sai *)devid;
@@ -193,14 +221,48 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
+static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id, unsigned int freq)
+{
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       fsl_asoc_reparent_pll_clocks(dai->dev, sai->mclk_clk[clk_id],
+                                    sai->pll8k_clk, sai->pll11k_clk, freq);
+
+       ret = clk_set_rate(sai->mclk_clk[clk_id], freq);
+       if (ret < 0)
+               dev_err(dai->dev, "failed to set clock rate (%u): %d\n", freq, ret);
+
+       return ret;
+}
+
 static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int dir)
 {
+       struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        int ret;
 
        if (dir == SND_SOC_CLOCK_IN)
                return 0;
 
+       if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) {
+               if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) {
+                       dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id);
+                       return -EINVAL;
+               }
+
+               if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) {
+                       dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id);
+                       return -EINVAL;
+               }
+
+               if (sai->mclk_streams == 0) {
+                       ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, true);
        if (ret) {
                dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
@@ -224,6 +286,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
        if (!sai->is_lsb_first)
                val_cr4 |= FSL_SAI_CR4_MF;
 
+       sai->is_pdm_mode = false;
        /* DAI mode */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
@@ -262,6 +325,11 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                val_cr2 |= FSL_SAI_CR2_BCP;
                sai->is_dsp_mode = true;
                break;
+       case SND_SOC_DAIFMT_PDM:
+               val_cr2 |= FSL_SAI_CR2_BCP;
+               val_cr4 &= ~FSL_SAI_CR4_MF;
+               sai->is_pdm_mode = true;
+               break;
        case SND_SOC_DAIFMT_RIGHT_J:
                /* To be done */
        default:
@@ -292,19 +360,19 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
 
        /* DAI clock provider masks */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                sai->is_consumer_mode = false;
                break;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                sai->is_consumer_mode = true;
                break;
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BP_FC:
                val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
                sai->is_consumer_mode = false;
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BC_FP:
                val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
                sai->is_consumer_mode = true;
                break;
@@ -437,6 +505,12 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
                                   FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
                                   savediv / 2 - 1);
 
+       if (sai->soc_data->max_register >= FSL_SAI_MCTL) {
+               /* SAI is in master mode at this point, so enable MCLK */
+               regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
+                                  FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
+       }
+
        return 0;
 }
 
@@ -448,13 +522,18 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        unsigned int ofs = sai->soc_data->reg_offset;
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
        unsigned int channels = params_channels(params);
+       struct snd_dmaengine_dai_dma_data *dma_params;
+       struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg;
        u32 word_width = params_width(params);
+       int trce_mask = 0, dl_cfg_idx = 0;
+       int dl_cfg_cnt = sai->dl_cfg_cnt;
+       u32 dl_type = FSL_SAI_DL_I2S;
        u32 val_cr4 = 0, val_cr5 = 0;
        u32 slots = (channels == 1) ? 2 : channels;
        u32 slot_width = word_width;
        int adir = tx ? RX : TX;
-       u32 pins;
-       int ret;
+       u32 pins, bclk;
+       int ret, i;
 
        if (sai->slots)
                slots = sai->slots;
@@ -464,15 +543,42 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
 
        pins = DIV_ROUND_UP(channels, slots);
 
+       /*
+        * PDM mode, channels are independent
+        * each channels are on one dataline/FIFO.
+        */
+       if (sai->is_pdm_mode) {
+               pins = channels;
+               dl_type = FSL_SAI_DL_PDM;
+       }
+
+       for (i = 0; i < dl_cfg_cnt; i++) {
+               if (dl_cfg[i].type == dl_type && dl_cfg[i].pins[tx] == pins) {
+                       dl_cfg_idx = i;
+                       break;
+               }
+       }
+
+       if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) < pins) {
+               dev_err(cpu_dai->dev, "channel not supported\n");
+               return -EINVAL;
+       }
+
+       bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width);
+
+       if (!IS_ERR_OR_NULL(sai->pinctrl)) {
+               sai->pins_state = fsl_sai_get_pins_state(sai, bclk);
+               if (!IS_ERR_OR_NULL(sai->pins_state)) {
+                       ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+                       if (ret) {
+                               dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n", ret);
+                               return ret;
+                       }
+               }
+       }
+
        if (!sai->is_consumer_mode) {
-               if (sai->bclk_ratio)
-                       ret = fsl_sai_set_bclk(cpu_dai, tx,
-                                              sai->bclk_ratio *
-                                              params_rate(params));
-               else
-                       ret = fsl_sai_set_bclk(cpu_dai, tx,
-                                              slots * slot_width *
-                                              params_rate(params));
+               ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
                if (ret)
                        return ret;
 
@@ -486,13 +592,13 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (!sai->is_dsp_mode)
+       if (!sai->is_dsp_mode && !sai->is_pdm_mode)
                val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);
 
        val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
        val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
 
-       if (sai->is_lsb_first)
+       if (sai->is_lsb_first || sai->is_pdm_mode)
                val_cr5 |= FSL_SAI_CR5_FBT(0);
        else
                val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
@@ -519,13 +625,28 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
                                   FSL_SAI_CR5_FBT_MASK, val_cr5);
        }
 
-       if (sai->soc_data->pins > 1)
+       if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1)
+               regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
+                                  FSL_SAI_CR4_FCOMB_MASK, 0);
+       else
                regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
                                   FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
 
+       dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx;
+       dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) +
+                          dl_cfg[dl_cfg_idx].start_off[tx] * 0x4;
+
+       /* Find a proper tcre setting */
+       for (i = 0; i < sai->soc_data->pins; i++) {
+               trce_mask = (1 << (i + 1)) - 1;
+               if (hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins)
+                       break;
+       }
+
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
                           FSL_SAI_CR3_TRCE_MASK,
-                          FSL_SAI_CR3_TRCE((1 << pins) - 1));
+                          FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
+
        regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
                           FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
                           FSL_SAI_CR4_CHMOD_MASK,
@@ -737,6 +858,23 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static int fsl_sai_dai_resume(struct snd_soc_component *component)
+{
+       struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
+       struct device *dev = &sai->pdev->dev;
+       int ret;
+
+       if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) {
+               ret = pinctrl_select_state(sai->pinctrl, sai->pins_state);
+               if (ret) {
+                       dev_err(dev, "failed to set proper pins state: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static struct snd_soc_dai_driver fsl_sai_dai_template = {
        .probe = fsl_sai_dai_probe,
        .playback = {
@@ -744,7 +882,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
                .channels_min = 1,
                .channels_max = 32,
                .rate_min = 8000,
-               .rate_max = 192000,
+               .rate_max = 2822400,
                .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_SAI_FORMATS,
        },
@@ -753,7 +891,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
                .channels_min = 1,
                .channels_max = 32,
                .rate_min = 8000,
-               .rate_max = 192000,
+               .rate_max = 2822400,
                .rates = SNDRV_PCM_RATE_KNOT,
                .formats = FSL_SAI_FORMATS,
        },
@@ -761,7 +899,9 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
 };
 
 static const struct snd_soc_component_driver fsl_component = {
-       .name           = "fsl-sai",
+       .name                   = "fsl-sai",
+       .resume                 = fsl_sai_dai_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static struct reg_default fsl_sai_reg_defaults_ofs0[] = {
@@ -998,30 +1138,142 @@ static int fsl_sai_check_version(struct device *dev)
        return 0;
 }
 
+/*
+ * Calculate the offset between first two datalines, don't
+ * different offset in one case.
+ */
+static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask)
+{
+       int fbidx, nbidx, offset;
+
+       fbidx = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
+       nbidx = find_next_bit(&dl_mask, FSL_SAI_DL_NUM, fbidx + 1);
+       offset = nbidx - fbidx - 1;
+
+       return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset);
+}
+
+/*
+ * read the fsl,dataline property from dts file.
+ * It has 3 value for each configuration, first one means the type:
+ * I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is
+ * dataline mask for 'tx'. for example
+ *
+ * fsl,dataline = <1 0xff 0xff 2 0xff 0x11>,
+ *
+ * It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type
+ * rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled).
+ *
+ */
+static int fsl_sai_read_dlcfg(struct fsl_sai *sai)
+{
+       struct platform_device *pdev = sai->pdev;
+       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       int ret, elems, i, index, num_cfg;
+       char *propname = "fsl,dataline";
+       struct fsl_sai_dl_cfg *cfg;
+       unsigned long dl_mask;
+       unsigned int soc_dl;
+       u32 rx, tx, type;
+
+       elems = of_property_count_u32_elems(np, propname);
+
+       if (elems <= 0) {
+               elems = 0;
+       } else if (elems % 3) {
+               dev_err(dev, "Number of elements must be divisible to 3.\n");
+               return -EINVAL;
+       }
+
+       num_cfg = elems / 3;
+       /*  Add one more for default value */
+       cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+
+       /* Consider default value "0 0xFF 0xFF" if property is missing */
+       soc_dl = BIT(sai->soc_data->pins) - 1;
+       cfg[0].type = FSL_SAI_DL_DEFAULT;
+       cfg[0].pins[0] = sai->soc_data->pins;
+       cfg[0].mask[0] = soc_dl;
+       cfg[0].start_off[0] = 0;
+       cfg[0].next_off[0] = 0;
+
+       cfg[0].pins[1] = sai->soc_data->pins;
+       cfg[0].mask[1] = soc_dl;
+       cfg[0].start_off[1] = 0;
+       cfg[0].next_off[1] = 0;
+       for (i = 1, index = 0; i < num_cfg + 1; i++) {
+               /*
+                * type of dataline
+                * 0 means default mode
+                * 1 means I2S mode
+                * 2 means PDM mode
+                */
+               ret = of_property_read_u32_index(np, propname, index++, &type);
+               if (ret)
+                       return -EINVAL;
+
+               ret = of_property_read_u32_index(np, propname, index++, &rx);
+               if (ret)
+                       return -EINVAL;
+
+               ret = of_property_read_u32_index(np, propname, index++, &tx);
+               if (ret)
+                       return -EINVAL;
+
+               if ((rx & ~soc_dl) || (tx & ~soc_dl)) {
+                       dev_err(dev, "dataline cfg[%d] setting error, mask is 0x%x\n", i, soc_dl);
+                       return -EINVAL;
+               }
+
+               rx = rx & soc_dl;
+               tx = tx & soc_dl;
+
+               cfg[i].type = type;
+               cfg[i].pins[0] = hweight8(rx);
+               cfg[i].mask[0] = rx;
+               dl_mask = rx;
+               cfg[i].start_off[0] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
+               cfg[i].next_off[0] = fsl_sai_calc_dl_off(rx);
+
+               cfg[i].pins[1] = hweight8(tx);
+               cfg[i].mask[1] = tx;
+               dl_mask = tx;
+               cfg[i].start_off[1] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM);
+               cfg[i].next_off[1] = fsl_sai_calc_dl_off(tx);
+       }
+
+       sai->dl_cfg = cfg;
+       sai->dl_cfg_cnt = num_cfg + 1;
+       return 0;
+}
+
 static int fsl_sai_runtime_suspend(struct device *dev);
 static int fsl_sai_runtime_resume(struct device *dev);
 
 static int fsl_sai_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
        struct fsl_sai *sai;
        struct regmap *gpr;
-       struct resource *res;
        void __iomem *base;
        char tmp[8];
        int irq, ret, i;
        int index;
 
-       sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+       sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL);
        if (!sai)
                return -ENOMEM;
 
        sai->pdev = pdev;
-       sai->soc_data = of_device_get_match_data(&pdev->dev);
+       sai->soc_data = of_device_get_match_data(dev);
 
        sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
 
-       base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       base = devm_platform_get_and_ioremap_resource(pdev, 0, &sai->res);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
@@ -1032,18 +1284,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
                        ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
        }
 
-       sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config);
+       sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config);
        if (IS_ERR(sai->regmap)) {
-               dev_err(&pdev->dev, "regmap init failed\n");
+               dev_err(dev, "regmap init failed\n");
                return PTR_ERR(sai->regmap);
        }
 
-       sai->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       sai->bus_clk = devm_clk_get(dev, "bus");
        /* Compatible with old DTB cases */
        if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER)
-               sai->bus_clk = devm_clk_get(&pdev->dev, "sai");
+               sai->bus_clk = devm_clk_get(dev, "sai");
        if (IS_ERR(sai->bus_clk)) {
-               dev_err(&pdev->dev, "failed to get bus clock: %ld\n",
+               dev_err(dev, "failed to get bus clock: %ld\n",
                                PTR_ERR(sai->bus_clk));
                /* -EPROBE_DEFER */
                return PTR_ERR(sai->bus_clk);
@@ -1051,9 +1303,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
        for (i = 1; i < FSL_SAI_MCLK_MAX; i++) {
                sprintf(tmp, "mclk%d", i);
-               sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp);
+               sai->mclk_clk[i] = devm_clk_get(dev, tmp);
                if (IS_ERR(sai->mclk_clk[i])) {
-                       dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n",
+                       dev_err(dev, "failed to get mclk%d clock: %ld\n",
                                        i + 1, PTR_ERR(sai->mclk_clk[i]));
                        sai->mclk_clk[i] = NULL;
                }
@@ -1064,14 +1316,24 @@ static int fsl_sai_probe(struct platform_device *pdev)
        else
                sai->mclk_clk[0] = sai->bus_clk;
 
+       fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk,
+                               &sai->pll11k_clk);
+
+       /* read dataline mask for rx and tx*/
+       ret = fsl_sai_read_dlcfg(sai);
+       if (ret < 0) {
+               dev_err(dev, "failed to read dlcfg %d\n", ret);
+               return ret;
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
 
-       ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED,
+       ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED,
                               np->name, sai);
        if (ret) {
-               dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+               dev_err(dev, "failed to claim irq %u\n", irq);
                return ret;
        }
 
@@ -1088,7 +1350,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
        if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
            of_find_property(np, "fsl,sai-asynchronous", NULL)) {
                /* error out if both synchronous and asynchronous are present */
-               dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
+               dev_err(dev, "invalid binding for synchronous mode\n");
                return -EINVAL;
        }
 
@@ -1109,7 +1371,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
            of_device_is_compatible(np, "fsl,imx6ul-sai")) {
                gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
                if (IS_ERR(gpr)) {
-                       dev_err(&pdev->dev, "cannot find iomuxc registers\n");
+                       dev_err(dev, "cannot find iomuxc registers\n");
                        return PTR_ERR(gpr);
                }
 
@@ -1121,29 +1383,29 @@ static int fsl_sai_probe(struct platform_device *pdev)
                                   MCLK_DIR(index));
        }
 
-       sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0;
-       sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0;
+       sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0;
+       sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0;
        sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
        sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
 
+       sai->pinctrl = devm_pinctrl_get(&pdev->dev);
+
        platform_set_drvdata(pdev, sai);
-       pm_runtime_enable(&pdev->dev);
-       if (!pm_runtime_enabled(&pdev->dev)) {
-               ret = fsl_sai_runtime_resume(&pdev->dev);
+       pm_runtime_enable(dev);
+       if (!pm_runtime_enabled(dev)) {
+               ret = fsl_sai_runtime_resume(dev);
                if (ret)
                        goto err_pm_disable;
        }
 
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&pdev->dev);
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
                goto err_pm_get_sync;
-       }
 
        /* Get sai version */
-       ret = fsl_sai_check_version(&pdev->dev);
+       ret = fsl_sai_check_version(dev);
        if (ret < 0)
-               dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret);
+               dev_warn(dev, "Error reading SAI version: %d\n", ret);
 
        /* Select MCLK direction */
        if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
@@ -1152,7 +1414,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
                                   FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
        }
 
-       ret = pm_runtime_put_sync(&pdev->dev);
+       ret = pm_runtime_put_sync(dev);
        if (ret < 0)
                goto err_pm_get_sync;
 
@@ -1162,15 +1424,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
         */
        if (sai->soc_data->use_imx_pcm) {
                ret = imx_pcm_dma_init(pdev);
-               if (ret)
+               if (ret) {
+                       if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA))
+                               dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n");
                        goto err_pm_get_sync;
+               }
        } else {
-               ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+               ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
                if (ret)
                        goto err_pm_get_sync;
        }
 
-       ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+       ret = devm_snd_soc_register_component(dev, &fsl_component,
                                              &sai->cpu_dai_drv, 1);
        if (ret)
                goto err_pm_get_sync;
@@ -1178,10 +1443,10 @@ static int fsl_sai_probe(struct platform_device *pdev)
        return ret;
 
 err_pm_get_sync:
-       if (!pm_runtime_status_suspended(&pdev->dev))
-               fsl_sai_runtime_suspend(&pdev->dev);
+       if (!pm_runtime_status_suspended(dev))
+               fsl_sai_runtime_suspend(dev);
 err_pm_disable:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_disable(dev);
 
        return ret;
 }
index 1c8f5ca07f9d0fda6e605ede13200d1d9d6aff7a..17956b5731dc35d73066c292a7056a647bd16236 100644 (file)
 #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
                         SNDRV_PCM_FMTBIT_S20_3LE |\
                         SNDRV_PCM_FMTBIT_S24_LE |\
-                        SNDRV_PCM_FMTBIT_S32_LE)
+                        SNDRV_PCM_FMTBIT_S32_LE |\
+                        SNDRV_PCM_FMTBIT_DSD_U8 |\
+                        SNDRV_PCM_FMTBIT_DSD_U16_LE |\
+                        SNDRV_PCM_FMTBIT_DSD_U32_LE)
 
 /* SAI Register Map Register */
 #define FSL_SAI_VERID  0x00 /* SAI Version ID Register */
 
 #define PMQOS_CPU_LATENCY   BIT(0)
 
+/* Max number of dataline */
+#define FSL_SAI_DL_NUM         (8)
+/* default dataline type is zero */
+#define FSL_SAI_DL_DEFAULT     (0)
+#define FSL_SAI_DL_I2S         BIT(0)
+#define FSL_SAI_DL_PDM         BIT(1)
+
 struct fsl_sai_soc_data {
        bool use_imx_pcm;
        bool use_edma;
@@ -250,16 +260,30 @@ struct fsl_sai_param {
        u32 dataline;
 };
 
+struct fsl_sai_dl_cfg {
+       unsigned int type;
+       unsigned int pins[2];
+       unsigned int mask[2];
+       unsigned int start_off[2];
+       unsigned int next_off[2];
+};
+
 struct fsl_sai {
        struct platform_device *pdev;
        struct regmap *regmap;
        struct clk *bus_clk;
        struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
+       struct clk *pll8k_clk;
+       struct clk *pll11k_clk;
+       struct resource *res;
 
        bool is_consumer_mode;
        bool is_lsb_first;
        bool is_dsp_mode;
+       bool is_pdm_mode;
        bool synchronous[2];
+       struct fsl_sai_dl_cfg *dl_cfg;
+       unsigned int dl_cfg_cnt;
 
        unsigned int mclk_id[2];
        unsigned int mclk_streams;
@@ -274,6 +298,8 @@ struct fsl_sai {
        struct fsl_sai_verid verid;
        struct fsl_sai_param param;
        struct pm_qos_request pm_qos_req;
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *pins_state;
 };
 
 #define TX 1
index 42d11aca38a106f73547a7ed802f9f3e6c0631af..7fc1c96929bb841a282b3b728254d06adf8b3e90 100644 (file)
@@ -23,6 +23,7 @@
 #include <sound/soc.h>
 
 #include "fsl_spdif.h"
+#include "fsl_utils.h"
 #include "imx-pcm.h"
 
 #define FSL_SPDIF_TXFIFO_WML   0x8
@@ -114,6 +115,8 @@ struct spdif_mixer_control {
  * @dma_params_rx: DMA parameters for receive channel
  * @regcache_srpc: regcache for SRPC
  * @bypass: status of bypass input to output
+ * @pll8k_clk: PLL clock for the rate of multiply of 8kHz
+ * @pll11k_clk: PLL clock for the rate of multiply of 11kHz
  */
 struct fsl_spdif_priv {
        const struct fsl_spdif_soc_data *soc;
@@ -137,6 +140,8 @@ struct fsl_spdif_priv {
        /* regcache for SRPC */
        u32 regcache_srpc;
        bool bypass;
+       struct clk *pll8k_clk;
+       struct clk *pll11k_clk;
 };
 
 static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
@@ -480,6 +485,8 @@ static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
        return 0;
 }
 
+static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index);
+
 static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
                                int sample_rate)
 {
@@ -528,6 +535,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       ret = fsl_spdif_probe_txclk(spdif_priv, rate);
+       if (ret)
+               return ret;
+
        clk = spdif_priv->txclk_src[rate];
        if (clk >= STC_TXCLK_SRC_MAX) {
                dev_err(&pdev->dev, "tx clock source is out of range\n");
@@ -647,6 +658,29 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
+static int spdif_reparent_rootclk(struct fsl_spdif_priv *spdif_priv, unsigned int sample_rate)
+{
+       struct platform_device *pdev = spdif_priv->pdev;
+       struct clk *clk;
+       int ret;
+
+       /* Reparent clock if required condition is true */
+       if (!fsl_spdif_can_set_clk_rate(spdif_priv, STC_TXCLK_SPDIF_ROOT))
+               return 0;
+
+       /* Get root clock */
+       clk = spdif_priv->txclk[STC_TXCLK_SPDIF_ROOT];
+
+       /* Disable clock first, for it was enabled by pm_runtime */
+       clk_disable_unprepare(clk);
+       fsl_asoc_reparent_pll_clocks(&pdev->dev, clk, spdif_priv->pll8k_clk,
+                                    spdif_priv->pll11k_clk, sample_rate);
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return ret;
+
+       return 0;
+}
 static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
@@ -659,6 +693,13 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
        int ret = 0;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ret = spdif_reparent_rootclk(spdif_priv, sample_rate);
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: reparent root clk failed: %d\n",
+                               __func__, sample_rate);
+                       return ret;
+               }
+
                ret  = spdif_set_sample_rate(substream, sample_rate);
                if (ret) {
                        dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
@@ -1237,7 +1278,8 @@ static struct snd_soc_dai_driver fsl_spdif_dai = {
 };
 
 static const struct snd_soc_component_driver fsl_spdif_component = {
-       .name           = "fsl-spdif",
+       .name                   = "fsl-spdif",
+       .legacy_dai_naming      = 1,
 };
 
 /* FSL SPDIF REGMAP */
@@ -1547,11 +1589,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        }
        spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
 
-       for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
-               ret = fsl_spdif_probe_txclk(spdif_priv, i);
-               if (ret)
-                       return ret;
-       }
+       fsl_asoc_get_pll_clocks(&pdev->dev, &spdif_priv->pll8k_clk,
+                               &spdif_priv->pll11k_clk);
 
        /* Initial spinlock for control data */
        ctrl = &spdif_priv->fsl_spdif_control;
index 84cb36d9dfea93e2a24b8300b0037f4b7cc24bbe..c9e0e31d5b34d43db672c2aaee3d461dc3c247c1 100644 (file)
@@ -93,7 +93,7 @@
  */
 #define FSLSSI_AC97_DAIFMT \
        (SND_SOC_DAIFMT_AC97 | \
-        SND_SOC_DAIFMT_CBM_CFS | \
+        SND_SOC_DAIFMT_BC_FP | \
         SND_SOC_DAIFMT_NB_NF)
 
 #define FSLSSI_SIER_DBG_RX_FLAGS \
@@ -358,13 +358,13 @@ static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi)
 static bool fsl_ssi_is_i2s_clock_provider(struct fsl_ssi *ssi)
 {
        return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
-               SND_SOC_DAIFMT_CBC_CFC;
+               SND_SOC_DAIFMT_BP_FP;
 }
 
-static bool fsl_ssi_is_i2s_cbp_cfc(struct fsl_ssi *ssi)
+static bool fsl_ssi_is_i2s_bc_fp(struct fsl_ssi *ssi)
 {
        return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
-               SND_SOC_DAIFMT_CBP_CFC;
+               SND_SOC_DAIFMT_BC_FP;
 }
 
 /**
@@ -847,7 +847,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
                u8 i2s_net = ssi->i2s_net;
 
                /* Normal + Network mode to send 16-bit data in 32-bit frames */
-               if (fsl_ssi_is_i2s_cbp_cfc(ssi) && sample_size == 16)
+               if (fsl_ssi_is_i2s_bc_fp(ssi) && sample_size == 16)
                        i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET;
 
                /* Use Normal mode to send mono data at 1st slot of 2 slots */
@@ -920,17 +920,17 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-               case SND_SOC_DAIFMT_CBC_CFC:
+               case SND_SOC_DAIFMT_BP_FP:
                        if (IS_ERR(ssi->baudclk)) {
                                dev_err(ssi->dev,
                                        "missing baudclk for master mode\n");
                                return -EINVAL;
                        }
                        fallthrough;
-               case SND_SOC_DAIFMT_CBP_CFC:
+               case SND_SOC_DAIFMT_BC_FP:
                        ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER;
                        break;
-               case SND_SOC_DAIFMT_CBP_CFP:
+               case SND_SOC_DAIFMT_BC_FC:
                        ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE;
                        break;
                default:
@@ -992,15 +992,15 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
 
        /* DAI clock provider masks */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                /* Output bit and frame sync clocks */
                strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
                scr |= SSI_SCR_SYS_CLK_EN;
                break;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                /* Input bit or frame sync clocks */
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BC_FP:
                /* Input bit clock but output frame sync clock */
                strcr |= SSI_STCR_TFDIR;
                break;
@@ -1182,6 +1182,7 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
 
 static const struct snd_soc_component_driver fsl_ssi_component = {
        .name = "fsl-ssi",
+       .legacy_dai_naming = 1,
 };
 
 static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
index 9bab202569af8adc2a8576d337501d6547f8374b..d0fc430f7033dbaa015175d1247f1d23596c4a93 100644 (file)
@@ -6,6 +6,8 @@
 //
 // Copyright 2010 Freescale Semiconductor, Inc.
 
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <sound/soc.h>
@@ -83,6 +85,73 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
 }
 EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
 
+/**
+ * fsl_asoc_get_pll_clocks - get two PLL clock source
+ *
+ * @dev: device pointer
+ * @pll8k_clk: PLL clock pointer for 8kHz
+ * @pll11k_clk: PLL clock pointer for 11kHz
+ *
+ * This function get two PLL clock source
+ */
+void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk,
+                            struct clk **pll11k_clk)
+{
+       *pll8k_clk = devm_clk_get(dev, "pll8k");
+       if (IS_ERR(*pll8k_clk))
+               *pll8k_clk = NULL;
+
+       *pll11k_clk = devm_clk_get(dev, "pll11k");
+       if (IS_ERR(*pll11k_clk))
+               *pll11k_clk = NULL;
+}
+EXPORT_SYMBOL(fsl_asoc_get_pll_clocks);
+
+/**
+ * fsl_asoc_reparent_pll_clocks - set clock parent if necessary
+ *
+ * @dev: device pointer
+ * @clk: root clock pointer
+ * @pll8k_clk: PLL clock pointer for 8kHz
+ * @pll11k_clk: PLL clock pointer for 11kHz
+ * @ratio: target requency for root clock
+ *
+ * This function set root clock parent according to the target ratio
+ */
+void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
+                                 struct clk *pll8k_clk,
+                                 struct clk *pll11k_clk, u64 ratio)
+{
+       struct clk *p, *pll = NULL, *npll = NULL;
+       bool reparent = false;
+       int ret = 0;
+
+       if (!clk || !pll8k_clk || !pll11k_clk)
+               return;
+
+       p = clk;
+       while (p && pll8k_clk && pll11k_clk) {
+               struct clk *pp = clk_get_parent(p);
+
+               if (clk_is_match(pp, pll8k_clk) ||
+                   clk_is_match(pp, pll11k_clk)) {
+                       pll = pp;
+                       break;
+               }
+               p = pp;
+       }
+
+       npll = (do_div(ratio, 8000) ? pll11k_clk : pll8k_clk);
+       reparent = (pll && !clk_is_match(pll, npll));
+
+       if (reparent) {
+               ret = clk_set_parent(p, npll);
+               if (ret < 0)
+                       dev_warn(dev, "failed to set parent:%d\n", ret);
+       }
+}
+EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks);
+
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale ASoC utility code");
 MODULE_LICENSE("GPL v2");
index c5dc2a14b492ccb42e1ac65c7d1c6c82c03d1b3a..4d5f3d93bc813913eb33c5842b2fdd266f8df64a 100644 (file)
@@ -19,4 +19,11 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
                             struct snd_soc_dai_link *dai,
                             unsigned int *dma_channel_id,
                             unsigned int *dma_id);
+
+void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk,
+                            struct clk **pll11k_clk);
+
+void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
+                                 struct clk *pll8k_clk,
+                                 struct clk *pll11k_clk, u64 ratio);
 #endif /* _FSL_UTILS_H */
index d0556c79fdb1531aaa6f84d53c2e6fcc3da82c24..c043efe4548d16ea6dd4adca979dba95f93b9f50 100644 (file)
@@ -911,7 +911,8 @@ static struct snd_soc_dai_driver fsl_xcvr_dai = {
 };
 
 static const struct snd_soc_component_driver fsl_xcvr_comp = {
-       .name = "fsl-xcvr-dai",
+       .name                   = "fsl-xcvr-dai",
+       .legacy_dai_naming      = 1,
 };
 
 static const struct reg_default fsl_xcvr_reg_defaults[] = {
@@ -1228,6 +1229,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
         */
        ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
        if (ret) {
+               pm_runtime_disable(dev);
                dev_err(dev, "failed to pcm register\n");
                return ret;
        }
@@ -1235,6 +1237,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
        ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
                                              &fsl_xcvr_dai, 1);
        if (ret) {
+               pm_runtime_disable(dev);
                dev_err(dev, "failed to register component %s\n",
                        fsl_xcvr_comp.name);
        }
@@ -1242,6 +1245,12 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
        return ret;
 }
 
+static int fsl_xcvr_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+       return 0;
+}
+
 static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev)
 {
        struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
@@ -1370,6 +1379,7 @@ static struct platform_driver fsl_xcvr_driver = {
                .pm = &fsl_xcvr_pm_ops,
                .of_match_table = fsl_xcvr_dt_ids,
        },
+       .remove = fsl_xcvr_remove,
 };
 module_platform_driver(fsl_xcvr_driver);
 
index 502fe1b522aba7420aeee0ccc1fa8425b2f8ba1e..1292a845c42446797de09105d49d953998d9752c 100644 (file)
@@ -81,7 +81,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream,
        int ret, dir;
 
        /* For playback the AUDMIX is consumer, and for record is provider */
-       fmt |= tx ? SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBP_CFP;
+       fmt |= tx ? SND_SOC_DAIFMT_BP_FP : SND_SOC_DAIFMT_BC_FC;
        dir  = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN;
 
        /* set DAI configuration */
@@ -122,7 +122,7 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream,
                return 0;
 
        /* For playback the AUDMIX is consumer */
-       fmt |= SND_SOC_DAIFMT_CBP_CFP;
+       fmt |= SND_SOC_DAIFMT_BC_FC;
 
        /* set AUDMIX DAI configuration */
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
index dfa05d40b27645355bce73dafff82e631794230f..50b71e5d45897c128ee478f79ec233acb0d99b02 100644 (file)
@@ -62,17 +62,14 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
        uintptr_t port = (uintptr_t)file->private_data;
        u32 pdcr, ptcr;
 
-       if (audmux_clk) {
-               ret = clk_prepare_enable(audmux_clk);
-               if (ret)
-                       return ret;
-       }
+       ret = clk_prepare_enable(audmux_clk);
+       if (ret)
+               return ret;
 
        ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
        pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
 
-       if (audmux_clk)
-               clk_disable_unprepare(audmux_clk);
+       clk_disable_unprepare(audmux_clk);
 
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!buf)
@@ -209,17 +206,14 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
        if (!audmux_base)
                return -ENOSYS;
 
-       if (audmux_clk) {
-               ret = clk_prepare_enable(audmux_clk);
-               if (ret)
-                       return ret;
-       }
+       ret = clk_prepare_enable(audmux_clk);
+       if (ret)
+               return ret;
 
        writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
        writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
 
-       if (audmux_clk)
-               clk_disable_unprepare(audmux_clk);
+       clk_disable_unprepare(audmux_clk);
 
        return 0;
 }
@@ -298,7 +292,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
                audmux_clk = NULL;
        }
 
-       audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev);
+       audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev);
 
        switch (audmux_type) {
        case IMX31_AUDMUX:
index 6f8efd838fcc87ced7a7758f7955b52de7bc911f..14be29530fb5dfb47db422be2d356aa4f0f67a18 100644 (file)
@@ -17,6 +17,9 @@
 
 #include "fsl_sai.h"
 
+#define IMX_CARD_MCLK_22P5792MHZ  22579200
+#define IMX_CARD_MCLK_24P576MHZ   24576000
+
 enum codec_type {
        CODEC_DUMMY = 0,
        CODEC_AK5558 = 1,
@@ -115,7 +118,7 @@ struct imx_card_data {
        struct snd_soc_card card;
        int num_dapm_routes;
        u32 asrc_rate;
-       u32 asrc_format;
+       snd_pcm_format_t asrc_format;
 };
 
 static struct imx_akcodec_fs_mul ak4458_fs_mul[] = {
@@ -317,7 +320,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+       ret = snd_soc_dai_set_fmt(cpu_dai, snd_soc_daifmt_clock_provider_flipped(fmt));
        if (ret && ret != -ENOTSUPP) {
                dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
                return ret;
@@ -353,9 +356,14 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
                mclk_freq = akcodec_get_mclk_rate(substream, params, slots, slot_width);
        else
                mclk_freq = params_rate(params) * slots * slot_width;
-       /* Use the maximum freq from DSD512 (512*44100 = 22579200) */
-       if (format_is_dsd(params))
-               mclk_freq = 22579200;
+
+       if (format_is_dsd(params)) {
+               /* Use the maximum freq from DSD512 (512*44100 = 22579200) */
+               if (!(params_rate(params) % 11025))
+                       mclk_freq = IMX_CARD_MCLK_22P5792MHZ;
+               else
+                       mclk_freq = IMX_CARD_MCLK_24P576MHZ;
+       }
 
        ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq,
                                     SND_SOC_CLOCK_OUT);
@@ -466,7 +474,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 
        mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        snd_mask_none(mask);
-       snd_mask_set(mask, data->asrc_format);
+       snd_mask_set(mask, (__force unsigned int)data->asrc_format);
 
        return 0;
 }
@@ -485,6 +493,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
        struct dai_link_data *link_data;
        struct of_phandle_args args;
        int ret, num_links;
+       u32 asrc_fmt = 0;
        u32 width;
 
        ret = snd_soc_of_parse_card_name(card, "model");
@@ -631,7 +640,8 @@ static int imx_card_parse_of(struct imx_card_data *data)
                                goto err;
                        }
 
-                       ret = of_property_read_u32(args.np, "fsl,asrc-format", &data->asrc_format);
+                       ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt);
+                       data->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
                        if (ret) {
                                /* Fallback to old binding; translate to asrc_format */
                                ret = of_property_read_u32(args.np, "fsl,asrc-width", &width);
index 3149d59ae968d2ce969178b9ee9c845cfef2d2b0..73f3e61f208a7a579478b5b268de91d9e5cb26c2 100644 (file)
@@ -148,7 +148,8 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{
 } };
 
 static const struct snd_soc_component_driver psc_i2s_component = {
-       .name           = "mpc5200-i2s",
+       .name                   = "mpc5200-i2s",
+       .legacy_dai_naming      = 1,
 };
 
 /* ---------------------------------------------------------------------
index 83b4a22bf15ac0b8883f3144c55f34d5959f6012..997c3e66c636532589687412e26c6f61dd443d81 100644 (file)
@@ -101,8 +101,7 @@ static int pcm030_fabric_probe(struct platform_device *op)
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
-               platform_device_del(pdata->codec_device);
-               platform_device_put(pdata->codec_device);
+               platform_device_unregister(pdata->codec_device);
        }
 
        platform_set_drvdata(op, pdata);
@@ -113,12 +112,11 @@ static int pcm030_fabric_probe(struct platform_device *op)
 static int pcm030_fabric_remove(struct platform_device *op)
 {
        struct pcm030_audio_data *pdata = platform_get_drvdata(op);
-       int ret;
 
-       ret = snd_soc_unregister_card(pdata->card);
+       snd_soc_unregister_card(pdata->card);
        platform_device_unregister(pdata->codec_device);
 
-       return ret;
+       return 0;
 }
 
 static const struct of_device_id pcm030_audio_match[] = {
index 2b598af8feef8977e05f4b1e6cc97d23f48a70c0..b327372f2e4ae52aafa2511a564d6024b076d94d 100644 (file)
@@ -158,8 +158,10 @@ static int asoc_simple_parse_dai(struct device_node *ep,
         *    if he unbinded CPU or Codec.
         */
        ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
-       if (ret < 0)
+       if (ret < 0) {
+               of_node_put(node);
                return ret;
+       }
 
        dlc->of_node = node;
 
index 8eee7b821ff74cd2e0d84ca5ea0443968dc15015..fe547c18771ff3108f05732f1b88e30e0f8ed5b3 100644 (file)
  *     CONFIG_SND_AUDIO_GRAPH_CARD2
  *     CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE
  *     CONFIG_SND_TEST_COMPONENT
+ *
+ *
+ * You can indicate more detail each device behavior as debug if you modify
+ * "compatible" on each test-component. see below
+ *
+ *     test_cpu {
+ *     -       compatible = "test-cpu";
+ *     +       compatible = "test-cpu-verbose";
+ *             ...
+ *     };
+ *
+ *     test_codec {
+ *     -       compatible = "test-codec";
+ *     +       compatible = "test-codec-verbose";
+ *             ...
+ *     };
+ *
  */
 / {
        /*
                          "TC OUT",             "TC DAI11 Playback",
                          "TC DAI9 Capture",    "TC IN";
 
-               links = <&cpu0                  /* normal: cpu side only */
-                        &mcpu0                 /* multi:  cpu side only */
-                        &fe00 &fe01 &be0       /* dpcm:   both FE / BE  */
-                        &fe10 &fe11 &be1       /* dpcm-m: both FE / BE  */
-                        &c2c                   /* c2c:    cpu side only */
-                        &c2c_m                 /* c2c:    cpu side only */
+               links = <
+                       /*
+                        * [Normal]: cpu side only
+                        * cpu0/codec0
+                        */
+                        &cpu0
+
+                       /*
+                        * [Multi-CPU/Codec]: cpu side only
+                        * cpu1/cpu2/codec1/codec2
+                        */
+                        &mcpu0
+
+                       /*
+                        * [DPCM]: both FE / BE
+                        * cpu3/cpu4/codec3
+                        */
+                        &fe00 &fe01 &be0
+
+                       /*
+                        * [DPCM-Multi]: both FE / BE
+                        * cpu5/cpu6/codec4/codec5
+                        */
+                        &fe10 &fe11 &be1
+
+                       /*
+                        * [Codec2Codec]: cpu side only
+                        * codec6/codec7
+                        */
+                        &c2c
+
+                       /*
+                        * [Codec2Codec-Multi]: cpu side only
+                        * codec8/codec9/codec10/codec11
+                        */
+                        &c2c_m
                >;
 
                multi {
                        ports@0 {
+                       /* [Multi-CPU] */
                        mcpu0:  port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
                                port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>;    }; };
                                port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>;    }; };
                        };
+
+                       /* [Multi-Codec] */
                        ports@1 {
                                port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>;  }; };
                                port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
                                port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
                        };
+
+                       /* [DPCM-Multi]::BE */
                        ports@2 {
                                port@0 { mbe_ep:  endpoint { remote-endpoint = <&be10_ep>;  }; };
                                port@1 { mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; }; };
                                port@2 { mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; }; };
                        };
+
+                       /* [Codec2Codec-Multi]::CPU */
                        ports@3 {
                                port@0 { mc2c0_ep:  endpoint { remote-endpoint = <&c2cmf_ep>;  }; };
                                port@1 { mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; }; };
                                port@2 { mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; }; };
                        };
+
+                       /* [Codec2Codec-Multi]::Codec */
                        ports@4 {
                                port@0 { mc2c1_ep:  endpoint { remote-endpoint = <&c2cmb_ep>;  }; };
                                port@1 { mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; }; };
                };
 
                dpcm {
-                       /* FE */
                        ports@0 {
+                       /* [DPCM]::FE */
                        fe00:   port@0 { fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; };
                        fe01:   port@1 { fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; };
+
+                       /* [DPCM-Multi]::FE */
                        fe10:   port@2 { fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; };
                        fe11:   port@3 { fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; };
                        };
-                       /* BE */
+
                        ports@1 {
+                       /* [DPCM]::BE */
                        be0:    port@0 { be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; };
+
+                       /* [DPCM-Multi]::BE */
                        be1:    port@1 { be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; };
                        };
                };
 
                codec2codec {
+                       /* [Codec2Codec] */
                        ports@0 {
-                               rate = <48000>;
+                               /* use default settings */
                        c2c:    port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec6_ep>; }; };
                                port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; };
                        };
+
+                       /* [Codec2Codec-Multi] */
                        ports@1 {
+                               /* use original settings */
                                rate = <48000>;
                        c2c_m:  port@0 { c2cmf_ep: endpoint { remote-endpoint = <&mc2c0_ep>; }; };
                                port@1 { c2cmb_ep: endpoint { remote-endpoint = <&mc2c1_ep>; }; };
                ports {
                        bitclock-master;
                        frame-master;
+                       /* [Normal] */
                        cpu0: port@0 { cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
+
+                       /* [Multi-CPU] */
                              port@1 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
                              port@2 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; };
+
+                       /* [DPCM]::FE */
                              port@3 { cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; };
                              port@4 { cpu4_ep: endpoint { remote-endpoint = <&fe01_ep>; }; };
+
+                       /* [DPCM-Multi]::FE */
                              port@5 { cpu5_ep: endpoint { remote-endpoint = <&fe10_ep>; }; };
                              port@6 { cpu6_ep: endpoint { remote-endpoint = <&fe11_ep>; }; };
                };
                         */
                        prefix = "TC";
 
+                       /* [Normal] */
                        port@0  { codec0_ep:  endpoint { remote-endpoint = <&cpu0_ep>; }; };
+
+                       /* [Multi-Codec] */
                        port@1  { codec1_ep:  endpoint { remote-endpoint = <&mcodec1_ep>; }; };
                        port@2  { codec2_ep:  endpoint { remote-endpoint = <&mcodec2_ep>; }; };
+
+                       /* [DPCM]::BE */
                        port@3  { codec3_ep:  endpoint { remote-endpoint = <&be00_ep>; }; };
+
+                       /* [DPCM-Multi]::BE */
                        port@4  { codec4_ep:  endpoint { remote-endpoint = <&mbe1_ep>; }; };
                        port@5  { codec5_ep:  endpoint { remote-endpoint = <&mbe2_ep>; }; };
+
+                       /* [Codec2Codec] */
                        port@6  { bitclock-master;
                                  frame-master;
                                  codec6_ep:  endpoint { remote-endpoint = <&c2cf_ep>; }; };
                        port@7  { codec7_ep:  endpoint { remote-endpoint = <&c2cb_ep>; }; };
+
+                       /* [Codec2Codec-Multi] */
                        port@8  { bitclock-master;
                                  frame-master;
                                  codec8_ep:  endpoint { remote-endpoint = <&mc2c00_ep>; }; };
index d34b29a49268e979f0a279df5ddfa3001f8616cb..8ac6df645ee6ce4b32c9aadd4229d92863be435c 100644 (file)
@@ -229,7 +229,8 @@ enum graph_type {
 
 static enum graph_type __graph_get_type(struct device_node *lnk)
 {
-       struct device_node *np;
+       struct device_node *np, *parent_np;
+       enum graph_type ret;
 
        /*
         * target {
@@ -240,19 +241,33 @@ static enum graph_type __graph_get_type(struct device_node *lnk)
         * };
         */
        np = of_get_parent(lnk);
-       if (of_node_name_eq(np, "ports"))
-               np = of_get_parent(np);
+       if (of_node_name_eq(np, "ports")) {
+               parent_np = of_get_parent(np);
+               of_node_put(np);
+               np = parent_np;
+       }
 
-       if (of_node_name_eq(np, GRAPH_NODENAME_MULTI))
-               return GRAPH_MULTI;
+       if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) {
+               ret = GRAPH_MULTI;
+               goto out_put;
+       }
 
-       if (of_node_name_eq(np, GRAPH_NODENAME_DPCM))
-               return GRAPH_DPCM;
+       if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) {
+               ret = GRAPH_DPCM;
+               goto out_put;
+       }
+
+       if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) {
+               ret = GRAPH_C2C;
+               goto out_put;
+       }
 
-       if (of_node_name_eq(np, GRAPH_NODENAME_C2C))
-               return GRAPH_C2C;
+       ret = GRAPH_NORMAL;
+
+out_put:
+       of_node_put(np);
+       return ret;
 
-       return GRAPH_NORMAL;
 }
 
 static enum graph_type graph_get_type(struct asoc_simple_priv *priv,
@@ -430,8 +445,10 @@ static int asoc_simple_parse_dai(struct device_node *ep,
         *    if he unbinded CPU or Codec.
         */
        ret = snd_soc_get_dai_name(&args, &dlc->dai_name);
-       if (ret < 0)
+       if (ret < 0) {
+               of_node_put(node);
                return ret;
+       }
 
        dlc->of_node = node;
 
@@ -851,12 +868,10 @@ int audio_graph2_link_c2c(struct asoc_simple_priv *priv,
                          struct link_info *li)
 {
        struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
-       struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
-       struct snd_soc_pcm_stream *c2c_conf = dai_props->c2c_conf;
        struct device_node *port0, *port1, *ports;
        struct device_node *codec0_port, *codec1_port;
        struct device_node *ep0, *ep1;
-       u32 val;
+       u32 val = 0;
        int ret = -EINVAL;
 
        /*
@@ -880,19 +895,33 @@ int audio_graph2_link_c2c(struct asoc_simple_priv *priv,
        ports = of_get_parent(port0);
        port1 = of_get_next_child(ports, lnk);
 
-       if (!of_get_property(ports, "rate", &val)) {
+       /*
+        * Card2 can use original Codec2Codec settings if DT has.
+        * It will use default settings if no settings on DT.
+        * see
+        *      asoc_simple_init_for_codec2codec()
+        *
+        * Add more settings here if needed
+        */
+       of_property_read_u32(ports, "rate", &val);
+       if (val) {
                struct device *dev = simple_priv_to_dev(priv);
+               struct snd_soc_pcm_stream *c2c_conf;
 
-               dev_err(dev, "Codec2Codec needs rate settings\n");
-               goto err1;
-       }
+               c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL);
+               if (!c2c_conf)
+                       goto err1;
 
-       c2c_conf->formats       = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */
-       c2c_conf->rate_min      =
-       c2c_conf->rate_max      = val;
-       c2c_conf->channels_min  =
-       c2c_conf->channels_max  = 2; /* update ME */
-       dai_link->params        = c2c_conf;
+               c2c_conf->formats       = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */
+               c2c_conf->rates         = SNDRV_PCM_RATE_8000_384000;
+               c2c_conf->rate_min      =
+               c2c_conf->rate_max      = val;
+               c2c_conf->channels_min  =
+               c2c_conf->channels_max  = 2; /* update ME */
+
+               dai_link->params        = c2c_conf;
+               dai_link->num_params    = 1;
+       }
 
        ep0 = port_to_endpoint(port0);
        ep1 = port_to_endpoint(port1);
@@ -1086,7 +1115,6 @@ static int graph_count_c2c(struct asoc_simple_priv *priv,
        li->num[li->link].cpus          =
        li->num[li->link].platforms     = graph_counter(codec0);
        li->num[li->link].codecs        = graph_counter(codec1);
-       li->num[li->link].c2c           = 1;
 
        of_node_put(ports);
        of_node_put(port1);
index 539d7f081bd792c23b51e3fd23dec1773a52447e..4a29e314fa9530beac9b4352ed77e7f5953fdabd 100644 (file)
@@ -513,7 +513,12 @@ static int asoc_simple_init_dai(struct snd_soc_dai *dai,
        return 0;
 }
 
-static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
+static inline int asoc_simple_component_is_codec(struct snd_soc_component *component)
+{
+       return component->driver->endianness;
+}
+
+static int asoc_simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
                                            struct simple_dai_props *dai_props)
 {
        struct snd_soc_dai_link *dai_link = rtd->dai_link;
@@ -522,9 +527,17 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd,
        struct snd_pcm_hardware hw;
        int i, ret, stream;
 
+       /* Do nothing if it already has Codec2Codec settings */
+       if (dai_link->params)
+               return 0;
+
+       /* Do nothing if it was DPCM :: BE */
+       if (dai_link->no_pcm)
+               return 0;
+
        /* Only Codecs */
        for_each_rtd_components(rtd, i, component) {
-               if (!snd_soc_component_is_codec(component))
+               if (!asoc_simple_component_is_codec(component))
                        return 0;
        }
 
@@ -575,7 +588,7 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
                        return ret;
        }
 
-       ret = asoc_simple_init_dai_link_params(rtd, props);
+       ret = asoc_simple_init_for_codec2codec(rtd, props);
        if (ret < 0)
                return ret;
 
@@ -609,7 +622,7 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
 }
 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu);
 
-int asoc_simple_clean_reference(struct snd_soc_card *card)
+void asoc_simple_clean_reference(struct snd_soc_card *card)
 {
        struct snd_soc_dai_link *dai_link;
        struct snd_soc_dai_link_component *cpu;
@@ -622,7 +635,6 @@ int asoc_simple_clean_reference(struct snd_soc_card *card)
                for_each_link_codecs(dai_link, j, codec)
                        of_node_put(codec->of_node);
        }
-       return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_clean_reference);
 
@@ -742,8 +754,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
        struct asoc_simple_dai *dais;
        struct snd_soc_dai_link_component *dlcs;
        struct snd_soc_codec_conf *cconf = NULL;
-       struct snd_soc_pcm_stream *c2c_conf = NULL;
-       int i, dai_num = 0, dlc_num = 0, cnf_num = 0, c2c_num = 0;
+       int i, dai_num = 0, dlc_num = 0, cnf_num = 0;
 
        dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL);
        dai_link  = devm_kcalloc(dev, li->link, sizeof(*dai_link),  GFP_KERNEL);
@@ -762,8 +773,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 
                if (!li->num[i].cpus)
                        cnf_num += li->num[i].codecs;
-
-               c2c_num += li->num[i].c2c;
        }
 
        dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL);
@@ -777,12 +786,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
                        return -ENOMEM;
        }
 
-       if (c2c_num) {
-               c2c_conf = devm_kcalloc(dev, c2c_num, sizeof(*c2c_conf), GFP_KERNEL);
-               if (!c2c_conf)
-                       return -ENOMEM;
-       }
-
        dev_dbg(dev, "link %d, dais %d, ccnf %d\n",
                li->link, dai_num, cnf_num);
 
@@ -796,7 +799,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
        priv->dais              = dais;
        priv->dlcs              = dlcs;
        priv->codec_conf        = cconf;
-       priv->c2c_conf          = c2c_conf;
 
        card->dai_link          = priv->dai_link;
        card->num_links         = li->link;
@@ -814,12 +816,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 
                        dlcs += li->num[i].cpus;
                        dais += li->num[i].cpus;
-
-                       if (li->num[i].c2c) {
-                               /* Codec2Codec */
-                               dai_props[i].c2c_conf = c2c_conf;
-                               c2c_conf += li->num[i].c2c;
-                       }
                } else {
                        /* DPCM Be's CPU = dummy */
                        dai_props[i].cpus       =
@@ -877,7 +873,9 @@ int asoc_simple_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
 
-       return asoc_simple_clean_reference(card);
+       asoc_simple_clean_reference(card);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_remove);
 
index 5da4725d9e16cb5788fe865c2a914ff8698ee503..98c8990596a88400bad98da802c34a03a640d289 100644 (file)
@@ -66,7 +66,7 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        unsigned int format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
        unsigned int clock  = fmt & SND_SOC_DAIFMT_CLOCK_MASK;
        unsigned int inv    = fmt & SND_SOC_DAIFMT_INV_MASK;
-       unsigned int master = fmt & SND_SOC_DAIFMT_MASTER_MASK;
+       unsigned int master = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
        char *str;
 
        dev_info(dai->dev, "name   : %s", dai->name);
@@ -105,16 +105,16 @@ static int test_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        str = "unknown";
        switch (master) {
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BP_FP:
                str = "clk provider, frame provider";
                break;
-       case SND_SOC_DAIFMT_CBC_CFP:
+       case SND_SOC_DAIFMT_BC_FP:
                str = "clk consumer, frame provider";
                break;
-       case SND_SOC_DAIFMT_CBP_CFC:
+       case SND_SOC_DAIFMT_BP_FC:
                str = "clk provider, frame consumer";
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BC_FC:
                str = "clk consumer, frame consumer";
                break;
        }
@@ -192,10 +192,10 @@ static int test_dai_bespoke_trigger(struct snd_pcm_substream *substream,
 static u64 test_dai_formats =
        /*
         * Select below from Sound Card, not auto
-        *      SND_SOC_POSSIBLE_DAIFMT_CBP_CFP
-        *      SND_SOC_POSSIBLE_DAIFMT_CBC_CFP
-        *      SND_SOC_POSSIBLE_DAIFMT_CBP_CFC
-        *      SND_SOC_POSSIBLE_DAIFMT_CBC_CFC
+        *      SND_SOC_POSSIBLE_DAIFMT_BP_FP
+        *      SND_SOC_POSSIBLE_DAIFMT_BC_FP
+        *      SND_SOC_POSSIBLE_DAIFMT_BP_FC
+        *      SND_SOC_POSSIBLE_DAIFMT_BC_FC
         */
        SND_SOC_POSSIBLE_DAIFMT_I2S     |
        SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
@@ -564,11 +564,11 @@ static int test_driver_probe(struct platform_device *pdev)
                cdriv->pcm_construct            = test_component_pcm_construct;
                cdriv->pointer                  = test_component_pointer;
                cdriv->trigger                  = test_component_trigger;
+               cdriv->legacy_dai_naming        = 1;
        } else {
                cdriv->name                     = "test_codec";
                cdriv->idle_bias_on             = 1;
                cdriv->endianness               = 1;
-               cdriv->non_legacy_dai_naming    = 1;
        }
 
        cdriv->open             = test_component_open;
index a297d4af5099f99ddc504ed7bcc7245ac6f50547..27219a9e7d0d84c8bf79b963bae1e0a1e6505e97 100644 (file)
@@ -227,9 +227,9 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
         * We don't actually set the hardware until the hw_params
         * call, but we need to validate the user input here.
         */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_BP_FP:
                break;
        default:
                return -EINVAL;
@@ -245,8 +245,8 @@ static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        }
 
        i2s->format = fmt;
-       i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) ==
-                     SND_SOC_DAIFMT_CBS_CFS;
+       i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
+                     SND_SOC_DAIFMT_BP_FP;
 
        return 0;
 }
@@ -375,21 +375,21 @@ static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,
        hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val);
 
 
-       switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                i2s->master = false;
                val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
                val |= HII2S_I2S_CFG__S2_MST_SLV;
                hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                i2s->master = true;
                val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
                val &= ~HII2S_I2S_CFG__S2_MST_SLV;
                hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
                break;
        default:
-               WARN_ONCE(1, "Invalid i2s->fmt MASTER_MASK. This shouldn't happen\n");
+               WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n");
                return -EINVAL;
        }
 
@@ -539,6 +539,7 @@ static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
 
 static const struct snd_soc_component_driver hi6210_i2s_i2s_comp = {
        .name = "hi6210_i2s-i2s",
+       .legacy_dai_naming = 1,
 };
 
 static int hi6210_i2s_probe(struct platform_device *pdev)
index 09d23b11621c45a4bf3a2ae47491e7221f229373..56bb7bbd3976ce59516e598a80223104c8eb06ab 100644 (file)
@@ -333,8 +333,8 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                break;
        default:
                return -EINVAL;
@@ -386,7 +386,8 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_component_driver img_i2s_in_component = {
-       .name = "img-i2s-in"
+       .name = "img-i2s-in",
+       .legacy_dai_naming = 1,
 };
 
 static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st,
index 28f48ca1508a60997592af5e0d527b5dab841dc1..abeff78293100468434cffcde90bfe48a1488d77 100644 (file)
@@ -302,10 +302,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        if (force_clk_active)
                control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                control_set |= IMG_I2S_OUT_CTL_MASTER_MASK;
                break;
        default:
@@ -346,11 +346,9 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
 
-       ret = pm_runtime_get_sync(i2s->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(i2s->dev);
+       ret = pm_runtime_resume_and_get(i2s->dev);
+       if (ret < 0)
                return ret;
-       }
 
        img_i2s_out_disable(i2s);
 
@@ -394,7 +392,8 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_component_driver img_i2s_out_component = {
-       .name = "img-i2s-out"
+       .name = "img-i2s-out",
+       .legacy_dai_naming = 1,
 };
 
 static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st,
@@ -482,11 +481,9 @@ static int img_i2s_out_probe(struct platform_device *pdev)
                if (ret)
                        goto err_pm_disable;
        }
-       ret = pm_runtime_get_sync(&pdev->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(&pdev->dev);
+       ret = pm_runtime_resume_and_get(&pdev->dev);
+       if (ret < 0)
                goto err_suspend;
-       }
 
        reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
        img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
index cd6a6a82574199d230da37e236b6d4a1d42e172b..08506b05e226584bb7c746cf24ebb6d023fbb677 100644 (file)
@@ -201,7 +201,8 @@ static struct snd_soc_dai_driver img_prl_out_dai = {
 };
 
 static const struct snd_soc_component_driver img_prl_out_component = {
-       .name = "img-prl-out"
+       .name = "img-prl-out",
+       .legacy_dai_naming = 1,
 };
 
 static int img_prl_out_probe(struct platform_device *pdev)
index a79d1ccaeec019b3e6fe3cdc764547f3db736cae..3f1d1a7e8735b7b8cf502faf75756d5290be3d9d 100644 (file)
@@ -711,7 +711,8 @@ static struct snd_soc_dai_driver img_spdif_in_dai = {
 };
 
 static const struct snd_soc_component_driver img_spdif_in_component = {
-       .name = "img-spdif-in"
+       .name = "img-spdif-in",
+       .legacy_dai_naming = 1,
 };
 
 static int img_spdif_in_probe(struct platform_device *pdev)
index f7062eba2611a2bbdae9ee075d65e9d9ba286f78..983761d3fa7e6ce8af416df31772091ac39b4f52 100644 (file)
@@ -316,7 +316,8 @@ static struct snd_soc_dai_driver img_spdif_out_dai = {
 };
 
 static const struct snd_soc_component_driver img_spdif_out_component = {
-       .name = "img-spdif-out"
+       .name = "img-spdif-out",
+       .legacy_dai_naming = 1,
 };
 
 static int img_spdif_out_probe(struct platform_device *pdev)
index 802c0ee63aa26f3b46bb611621aaa9e4b3cf4754..e3b858643bd5d5e43941c17714b5535fd05b4e0e 100644 (file)
@@ -138,7 +138,6 @@ static const struct snd_soc_component_driver pistachio_internal_dac_driver = {
        .num_dapm_routes        = ARRAY_SIZE(pistachio_internal_dac_routes),
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static int pistachio_internal_dac_probe(struct platform_device *pdev)
index 7c85d1bb9c1296d7fb93c255dc016a120a1f2269..ded903f95b67c5c16a950580d5401749bf40a86f 100644 (file)
@@ -216,7 +216,7 @@ config SND_SOC_INTEL_AVS
        depends on COMMON_CLK
        select SND_SOC_ACPI if ACPI
        select SND_SOC_TOPOLOGY
-       select SND_HDA
+       select SND_SOC_HDA
        select SND_HDA_EXT_CORE
        select SND_HDA_DSP_LOADER
        select SND_INTEL_DSP_CONFIG
@@ -226,5 +226,8 @@ config SND_SOC_INTEL_AVS
          capabilities. This includes Skylake, Kabylake, Amberlake and
          Apollolake.
 
+# Machine board drivers
+source "sound/soc/intel/avs/boards/Kconfig"
+
 # ASoC codec drivers
 source "sound/soc/intel/boards/Kconfig"
index 335c3273299455f4045a1b451274b53d776a9b85..fd59b35a62bae7b42e4eb732b750fdc45f0894e1 100644 (file)
@@ -831,9 +831,9 @@ static int sst_get_ssp_mode(struct snd_soc_dai *dai, unsigned int fmt)
        dev_dbg(dai->dev, "Enter:%s, format=%x\n", __func__, format);
 
        switch (format) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                return SSP_MODE_PROVIDER;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                return SSP_MODE_CONSUMER;
        default:
                dev_err(dai->dev, "Invalid ssp protocol: %d\n", format);
@@ -1328,7 +1328,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
 {
        struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
        struct snd_soc_dapm_widget *w;
-       struct snd_soc_dapm_path *p = NULL;
+       struct snd_soc_dapm_path *p;
 
        dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream);
 
@@ -1392,7 +1392,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
 static int sst_fill_module_list(struct snd_kcontrol *kctl,
         struct snd_soc_dapm_widget *w, int type)
 {
-       struct sst_module *module = NULL;
+       struct sst_module *module;
        struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
        struct sst_ids *ids = w->priv;
        int ret = 0;
index 3a42d68c0247b16f1b74c95b13dd9bb2b67e152a..160b50f479fb4f3a1171f0785a705a76fba8dc80 100644 (file)
@@ -114,7 +114,7 @@ static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
 static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
 {
        struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
-       struct ipc_post *__msg, *msg = NULL;
+       struct ipc_post *__msg, *msg;
        unsigned long irq_flags;
 
        spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
index 4e8382097e6186ce77183aa2e888e13ce42ae1f9..4e039c7173d8ca23bec75cc46ba56e7fadf85353 100644 (file)
@@ -28,7 +28,7 @@
 struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
                                        u32 msg_id, u32 drv_id)
 {
-       struct sst_block *msg = NULL;
+       struct sst_block *msg;
 
        dev_dbg(ctx->dev, "Enter\n");
        msg = kzalloc(sizeof(*msg), GFP_KERNEL);
@@ -63,7 +63,7 @@ struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
 int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
                u32 drv_id, u32 ipc, void *data, u32 size)
 {
-       struct sst_block *block = NULL;
+       struct sst_block *block;
 
        dev_dbg(ctx->dev, "Enter\n");
 
@@ -91,7 +91,7 @@ int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
 
 int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed)
 {
-       struct sst_block *block = NULL, *__block;
+       struct sst_block *block, *__block;
 
        dev_dbg(ctx->dev, "Enter\n");
        spin_lock_bh(&ctx->block_lock);
@@ -341,7 +341,7 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
        }
 
        /* FW sent short error response for an IPC */
-       if (msg_high.part.result && drv_id && !msg_high.part.large) {
+       if (msg_high.part.result && !msg_high.part.large) {
                /* 32-bit FW error code in msg_low */
                dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low);
                sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
index b6b93ae80304b2c4df596b29950f90b444a4cfb6..919212825f21645c29b4baed97d1ae4b2e3adadf 100644 (file)
@@ -10,3 +10,6 @@ snd-soc-avs-objs += trace.o
 CFLAGS_trace.o := -I$(src)
 
 obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
+
+# Machine support
+obj-$(CONFIG_SND_SOC) += boards/
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
new file mode 100644 (file)
index 0000000..4d68e3e
--- /dev/null
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "Intel AVS Machine drivers"
+       depends on SND_SOC_INTEL_AVS
+
+comment "Available DSP configurations"
+
+config SND_SOC_INTEL_AVS_MACH_DA7219
+       tristate "da7219 I2S board"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_DA7219
+       help
+         This adds support for AVS with DA7219 I2S codec configuration.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_DMIC
+       tristate "DMIC generic board"
+       select SND_SOC_DMIC
+       help
+         This adds support for AVS with Digital Mic array configuration.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_HDAUDIO
+       tristate "HD-Audio generic board"
+       select SND_SOC_HDA
+       help
+         This adds support for AVS with HDAudio codec configuration.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_I2S_TEST
+       tristate "I2S test board"
+       help
+          This adds support for I2S test-board which can be used to verify
+          transfer over I2S interface with SSP loopback scenarios.
+
+config SND_SOC_INTEL_AVS_MACH_MAX98357A
+       tristate "max98357A I2S board"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_MAX98357A
+       help
+         This adds support for AVS with MAX98357A I2S codec configuration.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_MAX98373
+       tristate "max98373 I2S board"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_MAX98373
+       help
+         This adds support for AVS with MAX98373 I2S codec configuration.
+         Say Y or m if you have such a device. This is a recommended option.
+         If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_NAU8825
+       tristate "nau8825 I2S board"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_NAU8825
+       help
+          This adds support for ASoC machine driver with NAU8825 I2S audio codec.
+          It is meant to be used with AVS driver.
+          Say Y or m if you have such a device. This is a recommended option.
+          If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT274
+       tristate "rt274 in I2S mode"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_RT274
+       help
+          This adds support for ASoC machine driver with RT274 I2S audio codec.
+          Say Y or m if you have such a device. This is a recommended option.
+          If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT286
+       tristate "rt286 in I2S mode"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_RT286
+       help
+          This adds support for ASoC machine driver with RT286 I2S audio codec.
+          Say Y or m if you have such a device. This is a recommended option.
+          If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT298
+       tristate "rt298 in I2S mode"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_RT298
+       help
+          This adds support for ASoC machine driver with RT298 I2S audio codec.
+          Say Y or m if you have such a device. This is a recommended option.
+          If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_RT5682
+       tristate "rt5682 in I2S mode"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_RT5682_I2C
+       help
+          This adds support for ASoC machine driver with RT5682 I2S audio codec.
+          Say Y or m if you have such a device. This is a recommended option.
+          If unsure select "N".
+
+config SND_SOC_INTEL_AVS_MACH_SSM4567
+       tristate "ssm4567 I2S board"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_SSM4567
+       help
+          This adds support for ASoC machine driver with SSM4567 I2S audio codec.
+          It is meant to be used with AVS driver.
+          Say Y or m if you have such a device. This is a recommended option.
+          If unsure select "N".
+
+endmenu
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
new file mode 100644 (file)
index 0000000..bc75376
--- /dev/null
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+snd-soc-avs-da7219-objs := da7219.o
+snd-soc-avs-dmic-objs := dmic.o
+snd-soc-avs-hdaudio-objs := hdaudio.o
+snd-soc-avs-i2s-test-objs := i2s_test.o
+snd-soc-avs-max98357a-objs := max98357a.o
+snd-soc-avs-max98373-objs := max98373.o
+snd-soc-avs-nau8825-objs := nau8825.o
+snd-soc-avs-rt274-objs := rt274.o
+snd-soc-avs-rt286-objs := rt286.o
+snd-soc-avs-rt298-objs := rt298.o
+snd-soc-avs-rt5682-objs := rt5682.o
+snd-soc-avs-ssm4567-objs := ssm4567.o
+
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_HDAUDIO) += snd-soc-avs-hdaudio.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_I2S_TEST) += snd-soc-avs-i2s-test.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT5682) += snd-soc-avs-rt5682.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_SSM4567) += snd-soc-avs-ssm4567.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
new file mode 100644 (file)
index 0000000..02ae542
--- /dev/null
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+#include <uapi/linux/input-event-codes.h>
+#include "../../../codecs/da7219.h"
+#include "../../../codecs/da7219-aad.h"
+
+#define DA7219_DAI_NAME                "da7219-hifi"
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret = 0;
+
+       codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found. Unable to set/unset codec pll\n");
+               return -EIO;
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+               if (ret)
+                       dev_err(card->dev, "failed to stop PLL: %d\n", ret);
+       } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM,
+                                         0, DA7219_PLL_FREQ_OUT_98304);
+               if (ret)
+                       dev_err(card->dev, "failed to start PLL: %d\n", ret);
+       }
+
+       return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+                           SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       /* HP jack connectors - unknown if we have jack detection */
+       {"Headphone Jack", NULL, "HPL"},
+       {"Headphone Jack", NULL, "HPR"},
+
+       {"MIC", NULL, "Headset Mic"},
+
+       { "Headphone Jack", NULL, "Platform Clock" },
+       { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+       struct snd_soc_card *card = runtime->card;
+       struct snd_soc_jack *jack;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+       int clk_freq;
+       int ret;
+
+       jack = snd_soc_card_get_drvdata(card);
+       clk_freq = 19200000;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(card->dev, "can't set codec sysclk configuration\n");
+               return ret;
+       }
+
+       /*
+        * Headset buttons map to the google Reference headset.
+        * These can be configured by userspace.
+        */
+       ret = snd_soc_card_jack_new(card, "Headset Jack",
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                   SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack);
+       if (ret) {
+               dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+       da7219_aad_jack_det(component, jack);
+
+       return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-DLGS7219:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, DA7219_DAI_NAME);
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->init = avs_da7219_codec_init;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component)
+               snd_soc_component_set_jack(component, jack, NULL);
+       return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       return avs_card_set_jack(card, jack);
+}
+
+static int avs_da7219_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct snd_soc_jack *jack;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!jack || !card)
+               return -ENOMEM;
+
+       card->name = "avs_da7219";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->remove = avs_card_remove;
+       card->suspend_pre = avs_card_suspend_pre;
+       card->resume_post = avs_card_resume_post;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, jack);
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_da7219_driver = {
+       .probe = avs_da7219_probe,
+       .driver = {
+               .name = "avs_da7219",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_da7219_driver);
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_da7219");
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
new file mode 100644 (file)
index 0000000..90a9216
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+
+SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin")));
+SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin")));
+SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
+/* Name overridden on probe */
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+       /* Back ends */
+       {
+               .name = "DMIC",
+               .id = 0,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .no_pcm = 1,
+               SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform),
+       },
+       {
+               .name = "DMIC WoV",
+               .id = 1,
+               .dpcm_capture = 1,
+               .nonatomic = 1,
+               .no_pcm = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(dmic_wov_pin, dmic_codec, platform),
+       },
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+       {"DMic", NULL, "SoC DMIC"},
+       {"DMIC Rx", NULL, "Capture"},
+       {"DMIC WoV Rx", NULL, "Capture"},
+};
+
+static int avs_dmic_probe(struct platform_device *pdev)
+{
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       mach = dev_get_platdata(dev);
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = "avs_dmic";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = card_dai_links;
+       card->num_links = ARRAY_SIZE(card_dai_links);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = card_routes;
+       card->num_dapm_routes = ARRAY_SIZE(card_routes);
+       card->fully_routed = true;
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_dmic_driver = {
+       .probe = avs_dmic_probe,
+       .driver = {
+               .name = "avs_dmic",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_dmic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_dmic");
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
new file mode 100644 (file)
index 0000000..d2fc41d
--- /dev/null
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/platform_device.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_i915.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/hda.h"
+
+static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,
+                               const char *platform_name, struct snd_soc_dai_link **links)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+       struct hda_pcm *pcm;
+       const char *cname = dev_name(&codec->core.dev);
+       int i;
+
+       dl = devm_kcalloc(dev, pcm_count, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+       pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+       for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+               dl[i].name = devm_kasprintf(dev, GFP_KERNEL, "%s link%d", cname, i);
+               if (!dl[i].name)
+                       return -ENOMEM;
+
+               dl[i].id = i;
+               dl[i].nonatomic = 1;
+               dl[i].no_pcm = 1;
+               dl[i].dpcm_playback = 1;
+               dl[i].dpcm_capture = 1;
+               dl[i].platforms = platform;
+               dl[i].num_platforms = 1;
+
+               dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+               dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+               if (!dl[i].codecs || !dl[i].cpus)
+                       return -ENOMEM;
+
+               dl[i].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d", cname, i);
+               if (!dl[i].cpus->dai_name)
+                       return -ENOMEM;
+
+               dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL);
+               dl[i].codecs->dai_name = pcm->name;
+               dl[i].num_codecs = 1;
+               dl[i].num_cpus = 1;
+       }
+
+       *links = dl;
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, struct hda_codec *codec, int pcm_count,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       struct hda_pcm *pcm;
+       const char *cname = dev_name(&codec->core.dev);
+       int i, n = 0;
+
+       /* at max twice the number of pcms */
+       dr = devm_kcalloc(dev, pcm_count * 2, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);
+
+       for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {
+               struct hda_pcm_stream *stream;
+               int dir;
+
+               dir = SNDRV_PCM_STREAM_PLAYBACK;
+               stream = &pcm->stream[dir];
+               if (!stream->substreams)
+                       goto capture_routes;
+
+               dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+                                           snd_pcm_direction_name(dir));
+               dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Tx", cname, i);
+               if (!dr[n].sink || !dr[n].source)
+                       return -ENOMEM;
+               n++;
+
+capture_routes:
+               dir = SNDRV_PCM_STREAM_CAPTURE;
+               stream = &pcm->stream[dir];
+               if (!stream->substreams)
+                       continue;
+
+               dr[n].sink = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d Rx", cname, i);
+               dr[n].source = devm_kasprintf(dev, GFP_KERNEL, "%s %s", pcm->name,
+                                             snd_pcm_direction_name(dir));
+               if (!dr[n].sink || !dr[n].source)
+                       return -ENOMEM;
+               n++;
+       }
+
+       *routes = dr;
+       *num_routes = n;
+       return 0;
+}
+
+/* Should be aligned with SectionPCM's name from topology */
+#define FEDAI_NAME_PREFIX "HDMI"
+
+static struct snd_pcm *
+avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx)
+{
+       struct snd_soc_pcm_runtime *rtd;
+       int dir = SNDRV_PCM_STREAM_PLAYBACK;
+
+       for_each_card_rtds(card, rtd) {
+               struct snd_pcm *spcm;
+               int ret, n;
+
+               spcm = rtd->pcm ? rtd->pcm->streams[dir].pcm : NULL;
+               if (!spcm || !strstr(spcm->id, FEDAI_NAME_PREFIX))
+                       continue;
+
+               ret = sscanf(spcm->id, FEDAI_NAME_PREFIX "%d", &n);
+               if (ret != 1)
+                       continue;
+               if (n == hdmi_idx)
+                       return rtd->pcm;
+       }
+
+       return NULL;
+}
+
+static int avs_card_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+       struct hda_codec *codec = mach->pdata;
+       struct hda_pcm *hpcm;
+       /* Topology pcm indexing is 1-based */
+       int i = 1;
+
+       list_for_each_entry(hpcm, &codec->pcm_list_head, list) {
+               struct snd_pcm *spcm;
+
+               spcm = avs_card_hdmi_pcm_at(card, i);
+               if (spcm) {
+                       hpcm->pcm = spcm;
+                       hpcm->device = spcm->device;
+                       dev_info(card->dev, "%s: mapping HDMI converter %d to PCM %d (%p)\n",
+                                __func__, i, hpcm->device, spcm);
+               } else {
+                       hpcm->pcm = NULL;
+                       hpcm->device = SNDRV_PCM_INVALID_DEVICE;
+                       dev_warn(card->dev, "%s: no PCM in topology for HDMI converter %d\n",
+                                __func__, i);
+               }
+               i++;
+       }
+
+       return hda_codec_probe_complete(codec);
+}
+
+static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_dai_link *links = NULL;
+       struct snd_soc_card *card = rtm->card;
+       struct hda_codec *codec;
+       struct hda_pcm *pcm;
+       int ret, n, pcm_count = 0;
+
+       mach = dev_get_platdata(card->dev);
+       codec = mach->pdata;
+
+       if (list_empty(&codec->pcm_list_head))
+               return -EINVAL;
+       list_for_each_entry(pcm, &codec->pcm_list_head, list)
+               pcm_count++;
+
+       ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links);
+       if (ret < 0) {
+               dev_err(card->dev, "create links failed: %d\n", ret);
+               return ret;
+       }
+
+       for (n = 0; n < pcm_count; n++) {
+               ret = snd_soc_add_pcm_runtime(card, &links[n]);
+               if (ret < 0) {
+                       dev_err(card->dev, "add links failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = avs_create_dapm_routes(card->dev, codec, pcm_count, &routes, &n);
+       if (ret < 0) {
+               dev_err(card->dev, "create routes failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, routes, n);
+       if (ret < 0) {
+               dev_err(card->dev, "add routes failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+
+static struct snd_soc_dai_link probing_link = {
+       .name = "probing-LINK",
+       .id = -1,
+       .nonatomic = 1,
+       .no_pcm = 1,
+       .dpcm_playback = 1,
+       .dpcm_capture = 1,
+       .cpus = dummy,
+       .num_cpus = ARRAY_SIZE(dummy),
+       .init = avs_probing_link_init,
+};
+
+static int avs_hdaudio_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dai_link *binder;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       struct hda_codec *codec;
+
+       mach = dev_get_platdata(dev);
+       codec = mach->pdata;
+
+       /* codec may be unloaded before card's probe() fires */
+       if (!device_is_registered(&codec->core.dev))
+               return -ENODEV;
+
+       binder = devm_kmemdup(dev, &probing_link, sizeof(probing_link), GFP_KERNEL);
+       if (!binder)
+               return -ENOMEM;
+
+       binder->platforms = devm_kzalloc(dev, sizeof(*binder->platforms), GFP_KERNEL);
+       binder->codecs = devm_kzalloc(dev, sizeof(*binder->codecs), GFP_KERNEL);
+       if (!binder->platforms || !binder->codecs)
+               return -ENOMEM;
+
+       binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL);
+       if (!binder->codecs->name)
+               return -ENOMEM;
+
+       binder->platforms->name = mach->mach_params.platform;
+       binder->num_platforms = 1;
+       binder->codecs->dai_name = "codec-probing-DAI";
+       binder->num_codecs = 1;
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = binder->codecs->name;
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = binder;
+       card->num_links = 1;
+       card->fully_routed = true;
+       if (hda_codec_is_display(codec))
+               card->late_probe = avs_card_late_probe;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_hdaudio_driver = {
+       .probe = avs_hdaudio_probe,
+       .driver = {
+               .name = "avs_hdaudio",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_hdaudio_driver)
+
+MODULE_DESCRIPTION("Intel HD-Audio machine driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_hdaudio");
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
new file mode 100644 (file)
index 0000000..8f0fd87
--- /dev/null
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "snd-soc-dummy-dai");
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_dr = 2;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+       dr[0].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[0].sink || !dr[0].source)
+               return -ENOMEM;
+
+       dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[1].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+       if (!dr[1].sink || !dr[1].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_create_dapm_widgets(struct device *dev, int ssp_port,
+                                  struct snd_soc_dapm_widget **widgets, int *num_widgets)
+{
+       struct snd_soc_dapm_widget *dw;
+       const int num_dw = 2;
+
+       dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL);
+       if (!dw)
+               return -ENOMEM;
+
+       dw[0].id = snd_soc_dapm_hp;
+       dw[0].reg = SND_SOC_NOPM;
+       dw[0].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dpb", ssp_port);
+       if (!dw[0].name)
+               return -ENOMEM;
+
+       dw[1].id = snd_soc_dapm_mic;
+       dw[1].reg = SND_SOC_NOPM;
+       dw[1].name = devm_kasprintf(dev, GFP_KERNEL, "ssp%dcp", ssp_port);
+       if (!dw[1].name)
+               return -ENOMEM;
+
+       *widgets = dw;
+       *num_widgets = num_dw;
+
+       return 0;
+}
+
+static int avs_i2s_test_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_widget *widgets;
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, num_widgets;
+       int ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-loopback", ssp_port);
+       if (!card->name)
+               return -ENOMEM;
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d\n", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d\n", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_widgets(dev, ssp_port, &widgets, &num_widgets);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm widgets: %d\n", ret);
+               return ret;
+       }
+
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->dapm_widgets = widgets;
+       card->num_dapm_widgets = num_widgets;
+       card->fully_routed = true;
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_i2s_test_driver = {
+       .probe = avs_i2s_test_probe,
+       .driver = {
+               .name = "avs_i2s_test",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_i2s_test_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_i2s_test");
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
new file mode 100644 (file)
index 0000000..921f42c
--- /dev/null
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       { "Spk", NULL, "Speaker" },
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "MX98357A:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "HiFi");
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 1;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "HiFi Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_max98357a_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = "avs_max98357a";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98357a_driver = {
+       .probe = avs_max98357a_probe,
+       .driver = {
+               .name = "avs_max98357a",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_max98357a_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98357a");
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
new file mode 100644 (file)
index 0000000..0fa8f56
--- /dev/null
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-dapm.h>
+
+#define MAX98373_DEV0_NAME     "i2c-MX98373:00"
+#define MAX98373_DEV1_NAME     "i2c-MX98373:01"
+#define MAX98373_CODEC_NAME    "max98373-aif1"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME),
+               .name_prefix = "Right",
+       },
+       {
+               .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME),
+               .name_prefix = "Left",
+       },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       { "Left Spk", NULL, "Left BE_OUT" },
+       { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static int
+avs_max98373_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 16 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+       return 0;
+}
+
+static int avs_max98373_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai;
+       int ret, i;
+
+       for_each_rtd_codec_dais(runtime, i, codec_dai) {
+               if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) {
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
+                       if (ret < 0) {
+                               dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+               }
+               if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) {
+                       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
+                       if (ret < 0) {
+                               dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops avs_max98373_ops = {
+       .hw_params = avs_max98373_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV0_NAME);
+       dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+       dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_DEV1_NAME);
+       dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, MAX98373_CODEC_NAME);
+       if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+           !dl->codecs[1].name || !dl->codecs[1].dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 2;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+       dl->be_hw_params_fixup = avs_max98373_be_fixup;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+       dl->ignore_pmdown_time = 1;
+       dl->ops = &avs_max98373_ops;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left HiFi Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right HiFi Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_max98373_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = "avs_max98373";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->codec_conf = card_codec_conf;
+       card->num_configs = ARRAY_SIZE(card_codec_conf);
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_max98373_driver = {
+       .probe = avs_max98373_probe,
+       .driver = {
+               .name = "avs_max98373",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_max98373_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_max98373");
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
new file mode 100644 (file)
index 0000000..f76909e
--- /dev/null
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI  "nau8825-hifi"
+
+static int
+avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found\n");
+               return -EINVAL;
+       }
+
+       if (!SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_nau8825_clock_control,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       { "MIC", NULL, "Headset Mic" },
+
+       { "Headphone Jack", NULL, "Platform Clock" },
+       { "Headset Mic", NULL, "Platform Clock" },
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       struct snd_soc_jack_pin *pins;
+       struct snd_soc_jack *jack;
+       struct snd_soc_card *card = runtime->card;
+       int num_pins, ret;
+
+       jack = snd_soc_card_get_drvdata(card);
+       num_pins = ARRAY_SIZE(card_headset_pins);
+
+       pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       /*
+        * 4 buttons here map to the google Reference headset.
+        * The use of these buttons can be decided by the user space.
+        */
+       ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        jack, pins, num_pins);
+       if (ret)
+               return ret;
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       //snd_soc_component_set_jack(component, jack, NULL);
+       // TODO: Fix nau8825 codec to use .set_jack, like everyone else
+       nau8825_enable_jack_detect(component, jack);
+
+       return 0;
+}
+
+static int
+avs_nau8825_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int avs_nau8825_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
+                       break;
+               }
+
+               ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+               if (ret < 0)
+                       dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+               break;
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+               ret = snd_soc_dai_set_pll(codec_dai, 0, 0, runtime->rate, runtime->rate * 256);
+               if (ret < 0)
+                       dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+               break;
+       }
+
+       return ret;
+}
+
+
+static const struct snd_soc_ops avs_nau8825_ops = {
+       .trigger = avs_nau8825_trigger,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10508825:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, SKL_NUVOTON_CODEC_DAI);
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->init = avs_nau8825_codec_init;
+       dl->be_hw_params_fixup = avs_nau8825_be_fixup;
+       dl->ops = &avs_nau8825_ops;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Capture");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component)
+               snd_soc_component_set_jack(component, jack, NULL);
+       return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found\n");
+               return -EINVAL;
+       }
+
+       if (codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK] &&
+           codec_dai->playback_widget->active)
+               snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN);
+
+       return avs_card_set_jack(card, jack);
+}
+
+static int avs_nau8825_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct snd_soc_jack *jack;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!jack || !card)
+               return -ENOMEM;
+
+       card->name = "avs_nau8825";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->remove = avs_card_remove;
+       card->suspend_pre = avs_card_suspend_pre;
+       card->resume_post = avs_card_resume_post;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, jack);
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_nau8825_driver = {
+       .probe = avs_nau8825_probe,
+       .driver = {
+               .name = "avs_nau8825",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_nau8825_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_nau8825");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
new file mode 100644 (file)
index 0000000..afef5a3
--- /dev/null
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt274.h"
+
+#define AVS_RT274_FREQ_OUT     24000000
+#define AVS_RT274_BE_FIXUP_RATE        48000
+#define RT274_CODEC_DAI                "rt274-aif1"
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
+static int
+avs_rt274_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI);
+       if (!codec_dai)
+               return -EINVAL;
+
+       /* Codec needs clock for Jack detection and button press */
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, AVS_RT274_FREQ_OUT,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret);
+               return ret;
+       }
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               int ratio = 100;
+
+               snd_soc_dai_set_bclk_ratio(codec_dai, ratio);
+
+               ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK,
+                                         AVS_RT274_BE_FIXUP_RATE * ratio, AVS_RT274_FREQ_OUT);
+               if (ret) {
+                       dev_err(codec_dai->dev, "failed to enable PLL2: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, avs_rt274_clock_control,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       {"Headphone Jack", NULL, "HPO Pin"},
+       {"MIC", NULL, "Mic Jack"},
+
+       {"Headphone Jack", NULL, "Platform Clock"},
+       {"MIC", NULL, "Platform Clock"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       struct snd_soc_jack_pin *pins;
+       struct snd_soc_jack *jack;
+       struct snd_soc_card *card = runtime->card;
+       int num_pins, ret;
+
+       jack = snd_soc_card_get_drvdata(card);
+       num_pins = ARRAY_SIZE(card_headset_pins);
+
+       pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins);
+       if (ret)
+               return ret;
+
+       snd_soc_component_set_jack(component, jack, NULL);
+
+       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+       if (ret < 0) {
+               dev_err(card->dev, "can't set codec pcm format %d\n", ret);
+               return ret;
+       }
+
+       card->dapm.idle_bias_off = true;
+
+       return 0;
+}
+
+static int avs_rt274_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = AVS_RT274_BE_FIXUP_RATE;
+       channels->min = channels->max = 2;
+
+       /* set SSPN to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT34C2:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt274-aif1");
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->init = avs_rt274_codec_init;
+       dl->be_hw_params_fixup = avs_rt274_be_fixup;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component)
+               snd_soc_component_set_jack(component, jack, NULL);
+       return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt274_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct snd_soc_jack *jack;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!jack || !card)
+               return -ENOMEM;
+
+       card->name = "avs_rt274";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->remove = avs_card_remove;
+       card->suspend_pre = avs_card_suspend_pre;
+       card->resume_post = avs_card_resume_post;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, jack);
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt274_driver = {
+       .probe = avs_rt274_probe,
+       .driver = {
+               .name = "avs_rt274",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_rt274_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt274");
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
new file mode 100644 (file)
index 0000000..e51d4e1
--- /dev/null
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt286.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       /* HP jack connectors - unknown if we have jack detect */
+       {"Headphone Jack", NULL, "HPO Pin"},
+       {"MIC1", NULL, "Mic Jack"},
+
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+       struct snd_soc_jack_pin *pins;
+       struct snd_soc_jack *jack;
+       struct snd_soc_card *card = runtime->card;
+       int num_pins, ret;
+
+       jack = snd_soc_card_get_drvdata(card);
+       num_pins = ARRAY_SIZE(card_headset_pins);
+
+       pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+                                        pins, num_pins);
+       if (ret)
+               return ret;
+
+       snd_soc_component_set_jack(component, jack, NULL);
+
+       return 0;
+}
+
+static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int
+avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *runtime = substream->private_data;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+       return ret;
+}
+
+static const struct snd_soc_ops avs_rt286_ops = {
+       .hw_params = avs_rt286_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt286-aif1");
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->init = avs_rt286_codec_init;
+       dl->be_hw_params_fixup = avs_rt286_be_fixup;
+       dl->ops = &avs_rt286_ops;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component)
+               snd_soc_component_set_jack(component, jack, NULL);
+       return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt286_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct snd_soc_jack *jack;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!jack || !card)
+               return -ENOMEM;
+
+       card->name = "avs_rt286";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->remove = avs_card_remove;
+       card->suspend_pre = avs_card_suspend_pre;
+       card->resume_post = avs_card_resume_post;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, jack);
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt286_driver = {
+       .probe = avs_rt286_probe,
+       .driver = {
+               .name = "avs_rt286",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_rt286_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt286");
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
new file mode 100644 (file)
index 0000000..b28d368
--- /dev/null
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/rt298.h"
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       /* HP jack connectors - unknown if we have jack detect */
+       {"Headphone Jack", NULL, "HPO Pin"},
+       {"MIC1", NULL, "Mic Jack"},
+
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "SPOL"},
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+       struct snd_soc_jack_pin *pins;
+       struct snd_soc_jack *jack;
+       struct snd_soc_card *card = runtime->card;
+       int num_pins, ret;
+
+       jack = snd_soc_card_get_drvdata(card);
+       num_pins = ARRAY_SIZE(card_headset_pins);
+
+       pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack,
+                                        pins, num_pins);
+       if (ret)
+               return ret;
+
+       snd_soc_component_set_jack(component, jack, NULL);
+
+       return 0;
+}
+
+static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will convert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int
+avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, 19200000, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(rtd->dev, "Set codec sysclk failed: %d\n", ret);
+
+       return ret;
+}
+
+static const struct snd_soc_ops avs_rt298_ops = {
+       .hw_params = avs_rt298_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343A:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt298-aif1");
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->init = avs_rt298_codec_init;
+       dl->be_hw_params_fixup = avs_rt298_be_fixup;
+       dl->ops = &avs_rt298_ops;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component)
+               snd_soc_component_set_jack(component, jack, NULL);
+       return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt298_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct snd_soc_jack *jack;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!jack || !card)
+               return -ENOMEM;
+
+       card->name = "avs_rt298";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->remove = avs_card_remove;
+       card->suspend_pre = avs_card_suspend_pre;
+       card->resume_post = avs_card_resume_post;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, jack);
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt298_driver = {
+       .probe = avs_rt298_probe,
+       .driver = {
+               .name = "avs_rt298",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_rt298_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt298");
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
new file mode 100644 (file)
index 0000000..01f9b9f
--- /dev/null
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/clk.h>
+#include <linux/dmi.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../common/soc-intel-quirks.h"
+#include "../../../codecs/rt5682.h"
+
+#define AVS_RT5682_SSP_CODEC(quirk)    ((quirk) & GENMASK(2, 0))
+#define AVS_RT5682_SSP_CODEC_MASK      (GENMASK(2, 0))
+#define AVS_RT5682_MCLK_EN             BIT(3)
+#define AVS_RT5682_MCLK_24MHZ          BIT(4)
+
+/* Default: MCLK on, MCLK 19.2M, SSP0 */
+static unsigned long avs_rt5682_quirk = AVS_RT5682_MCLK_EN | AVS_RT5682_SSP_CODEC(0);
+
+static int avs_rt5682_quirk_cb(const struct dmi_system_id *id)
+{
+       avs_rt5682_quirk = (unsigned long)id->driver_data;
+       return 1;
+}
+
+static const struct dmi_system_id avs_rt5682_quirk_table[] = {
+       {
+               .callback = avs_rt5682_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
+               },
+               .driver_data = (void *)(AVS_RT5682_MCLK_EN |
+                                       AVS_RT5682_MCLK_24MHZ |
+                                       AVS_RT5682_SSP_CODEC(1)),
+       },
+       {
+               .callback = avs_rt5682_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
+               },
+               .driver_data = (void *)(AVS_RT5682_MCLK_EN |
+                                       AVS_RT5682_SSP_CODEC(0)),
+       },
+       {}
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       /* HP jack connectors - unknown if we have jack detect */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* other jacks */
+       { "IN1P", NULL, "Headset Mic" },
+};
+
+static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
+       struct snd_soc_jack *jack;
+       struct snd_soc_card *card = runtime->card;
+       int ret;
+
+       jack = snd_soc_card_get_drvdata(card);
+
+       /* Need to enable ASRC function for 24MHz mclk rate */
+       if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
+           (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)) {
+               rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
+                                       RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC);
+       }
+
+       /*
+        * Headset buttons map to the google Reference headset.
+        * These can be configured by userspace.
+        */
+       ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack);
+       if (ret) {
+               dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       ret = snd_soc_component_set_jack(component, jack, NULL);
+       if (ret) {
+               dev_err(card->dev, "Headset Jack call-back failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+};
+
+static int
+avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+       int clk_id, clk_freq;
+       int pll_out, ret;
+
+       if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
+               clk_id = RT5682_PLL1_S_MCLK;
+               if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
+                       clk_freq = 24000000;
+               else
+                       clk_freq = 19200000;
+       } else {
+               clk_id = RT5682_PLL1_S_BCLK1;
+               clk_freq = params_rate(params) * 50;
+       }
+
+       pll_out = params_rate(params) * 512;
+
+       ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+       if (ret < 0)
+               dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+
+       /* Configure sysclk for codec */
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, pll_out, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+       /* slot_width should equal or large than data length, set them be the same */
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, params_width(params));
+       if (ret < 0) {
+               dev_err(runtime->dev, "set TDM slot err:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops avs_rt5682_ops = {
+       .hw_params = avs_rt5682_hw_params,
+};
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs->name = devm_kasprintf(dev, GFP_KERNEL, "i2c-10EC5682:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, "rt5682-aif1");
+       if (!dl->cpus->dai_name || !dl->codecs->name || !dl->codecs->dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 1;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->init = avs_rt5682_codec_init;
+       dl->ops = &avs_rt5682_ops;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 2;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "AIF1 Capture");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_card_set_jack(struct snd_soc_card *card, struct snd_soc_jack *jack)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component)
+               snd_soc_component_set_jack(component, jack, NULL);
+       return 0;
+}
+
+static int avs_card_remove(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       return avs_card_set_jack(card, NULL);
+}
+
+static int avs_card_resume_post(struct snd_soc_card *card)
+{
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       return avs_card_set_jack(card, jack);
+}
+
+static int avs_rt5682_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct snd_soc_jack *jack;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       if (pdev->id_entry && pdev->id_entry->driver_data)
+               avs_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
+
+       dmi_check_system(avs_rt5682_quirk_table);
+       dev_dbg(dev, "avs_rt5682_quirk = %lx\n", avs_rt5682_quirk);
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       jack = devm_kzalloc(dev, sizeof(*jack), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!jack || !card)
+               return -ENOMEM;
+
+       card->name = "avs_rt5682";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->remove = avs_card_remove;
+       card->suspend_pre = avs_card_suspend_pre;
+       card->resume_post = avs_card_resume_post;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, jack);
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_rt5682_driver = {
+       .probe = avs_rt5682_probe,
+       .driver = {
+               .name = "avs_rt5682",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_rt5682_driver)
+
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt5682");
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
new file mode 100644 (file)
index 0000000..9f84c8a
--- /dev/null
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
+//
+// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
+//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../../codecs/nau8825.h"
+
+#define SKL_NUVOTON_CODEC_DAI  "nau8825-hifi"
+#define SKL_SSM_CODEC_DAI      "ssm4567-hifi"
+
+static struct snd_soc_codec_conf card_codec_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF("i2c-INT343B:00"),
+               .name_prefix = "Left",
+       },
+       {
+               .dlc = COMP_CODEC_CONF("i2c-INT343B:01"),
+               .name_prefix = "Right",
+       },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Left Speaker"),
+       SOC_DAPM_PIN_SWITCH("Right Speaker"),
+};
+
+static int
+platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found\n");
+               return -EINVAL;
+       }
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000,
+                                            SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+       } else {
+               ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+       }
+
+       return ret;
+}
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_SPK("Left Speaker", NULL),
+       SND_SOC_DAPM_SPK("Right Speaker", NULL),
+       SND_SOC_DAPM_SPK("DP1", NULL),
+       SND_SOC_DAPM_SPK("DP2", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route card_base_routes[] = {
+       {"Left Speaker", NULL, "Left OUT"},
+       {"Right Speaker", NULL, "Right OUT"},
+};
+
+static int avs_ssm4567_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+
+       /* Slot 1 for left */
+       ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 0), 0x01, 0x01, 2, 48);
+       if (ret < 0)
+               return ret;
+
+       /* Slot 2 for right */
+       ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_codec(runtime, 1), 0x02, 0x02, 2, 48);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int
+avs_ssm4567_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate, *channels;
+       struct snd_mask *fmt;
+
+       rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+       /* The ADSP will covert the FE rate to 48k, stereo */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP0 to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+                              struct snd_soc_dai_link **dai_link)
+{
+       struct snd_soc_dai_link_component *platform;
+       struct snd_soc_dai_link *dl;
+
+       dl = devm_kzalloc(dev, sizeof(*dl), GFP_KERNEL);
+       platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+       if (!dl || !platform)
+               return -ENOMEM;
+
+       platform->name = platform_name;
+
+       dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
+       dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
+       dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+       if (!dl->name || !dl->cpus || !dl->codecs)
+               return -ENOMEM;
+
+       dl->cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port);
+       dl->codecs[0].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:00");
+       dl->codecs[0].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+       dl->codecs[1].name = devm_kasprintf(dev, GFP_KERNEL, "i2c-INT343B:01");
+       dl->codecs[1].dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssm4567-hifi");
+       if (!dl->cpus->dai_name || !dl->codecs[0].name || !dl->codecs[0].dai_name ||
+           !dl->codecs[1].name || !dl->codecs[1].dai_name)
+               return -ENOMEM;
+
+       dl->num_cpus = 1;
+       dl->num_codecs = 2;
+       dl->platforms = platform;
+       dl->num_platforms = 1;
+       dl->id = 0;
+       dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS;
+       dl->init = avs_ssm4567_codec_init;
+       dl->be_hw_params_fixup = avs_ssm4567_be_fixup;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+       dl->ignore_pmdown_time = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_create_dapm_routes(struct device *dev, int ssp_port,
+                                 struct snd_soc_dapm_route **routes, int *num_routes)
+{
+       struct snd_soc_dapm_route *dr;
+       const int num_base = ARRAY_SIZE(card_base_routes);
+       const int num_dr = num_base + 4;
+       int idx;
+
+       dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       memcpy(dr, card_base_routes, num_base * sizeof(*dr));
+
+       idx = num_base;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Left Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "Right Playback");
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Tx", ssp_port);
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Left Capture Sense");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       idx++;
+       dr[idx].sink = devm_kasprintf(dev, GFP_KERNEL, "ssp%d Rx", ssp_port);
+       dr[idx].source = devm_kasprintf(dev, GFP_KERNEL, "Right Capture Sense");
+       if (!dr[idx].sink || !dr[idx].source)
+               return -ENOMEM;
+
+       *routes = dr;
+       *num_routes = num_dr;
+
+       return 0;
+}
+
+static int avs_ssm4567_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dapm_route *routes;
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int num_routes, ssp_port, ret;
+
+       mach = dev_get_platdata(dev);
+       pname = mach->mach_params.platform;
+       ssp_port = __ffs(mach->mach_params.i2s_link_mask);
+
+       ret = avs_create_dai_link(dev, pname, ssp_port, &dai_link);
+       if (ret) {
+               dev_err(dev, "Failed to create dai link: %d", ret);
+               return ret;
+       }
+
+       ret = avs_create_dapm_routes(dev, ssp_port, &routes, &num_routes);
+       if (ret) {
+               dev_err(dev, "Failed to create dapm routes: %d", ret);
+               return ret;
+       }
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+
+       card->name = "avs_ssm4567-adi";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = dai_link;
+       card->num_links = 1;
+       card->codec_conf = card_codec_conf;
+       card->num_configs = ARRAY_SIZE(card_codec_conf);
+       card->controls = card_controls;
+       card->num_controls = ARRAY_SIZE(card_controls);
+       card->dapm_widgets = card_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+       card->dapm_routes = routes;
+       card->num_dapm_routes = num_routes;
+       card->fully_routed = true;
+       card->disable_route_checks = true;
+
+       ret = snd_soc_fixup_dai_links_platform_name(card, pname);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static struct platform_driver avs_ssm4567_driver = {
+       .probe = avs_ssm4567_probe,
+       .driver = {
+               .name = "avs_ssm4567",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_ssm4567_driver)
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_ssm4567");
index d100c6ba4d8aa667cb664ce589c60060ff93980f..d7a9390b5e483c91dc0939da1fbdb1d1aeaaacff 100644 (file)
@@ -176,17 +176,17 @@ int hda_cldma_reset(struct hda_cldma *cl)
                return ret;
        }
 
-       snd_hdac_stream_updateb(cl, SD_CTL, 1, 1);
-       ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & 1), AVS_CL_OP_INTERVAL_US,
-                                        AVS_CL_OP_TIMEOUT_US);
+       snd_hdac_stream_updateb(cl, SD_CTL, SD_CTL_STREAM_RESET, SD_CTL_STREAM_RESET);
+       ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, (reg & SD_CTL_STREAM_RESET),
+                                        AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US);
        if (ret < 0) {
                dev_err(cl->dev, "cldma set SRST failed: %d\n", ret);
                return ret;
        }
 
-       snd_hdac_stream_updateb(cl, SD_CTL, 1, 0);
-       ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & 1), AVS_CL_OP_INTERVAL_US,
-                                        AVS_CL_OP_TIMEOUT_US);
+       snd_hdac_stream_updateb(cl, SD_CTL, SD_CTL_STREAM_RESET, 0);
+       ret = snd_hdac_stream_readb_poll(cl, SD_CTL, reg, !(reg & SD_CTL_STREAM_RESET),
+                                        AVS_CL_OP_INTERVAL_US, AVS_CL_OP_TIMEOUT_US);
        if (ret < 0) {
                dev_err(cl->dev, "cldma unset SRST failed: %d\n", ret);
                return ret;
index 3a0997c3af2b9aab472305422bbdb601ccae8201..c50c20fd681a165f3afc6a13726663d0ec2bfa99 100644 (file)
@@ -23,6 +23,7 @@
 #include <sound/hdaudio_ext.h>
 #include <sound/intel-dsp-config.h>
 #include <sound/intel-nhlt.h>
+#include "../../codecs/hda.h"
 #include "avs.h"
 #include "cldma.h"
 
@@ -356,7 +357,7 @@ static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct
        struct device *dev = &pci->dev;
        int ret;
 
-       ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, NULL);
+       ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops);
        if (ret < 0)
                return ret;
 
@@ -439,12 +440,9 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
        if (bus->mlcap)
                snd_hdac_ext_bus_get_ml_capabilities(bus);
 
-       if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
-               dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
-       } else {
-               dma_set_mask(dev, DMA_BIT_MASK(32));
-               dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
-       }
+       if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
+               dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+       dma_set_max_seg_size(dev, UINT_MAX);
 
        ret = avs_hdac_bus_init_streams(bus);
        if (ret < 0) {
@@ -555,6 +553,7 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
                return AVS_IPC_RET(ret);
        }
 
+       avs_ipc_block(adev->ipc);
        avs_dsp_op(adev, int_control, false);
        snd_hdac_ext_bus_ppcap_int_enable(bus, false);
 
index 06d2f7af520fe17f890b6da4f2260b62ad4b74c3..b881100d3e02ac49c01bbeb41bc5d26f45fce22d 100644 (file)
@@ -13,6 +13,7 @@
 
 #define AVS_ADSPCS_INTERVAL_US         500
 #define AVS_ADSPCS_TIMEOUT_US          50000
+#define AVS_ADSPCS_DELAY_US            1000
 
 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
 {
@@ -26,6 +27,8 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
        value = power ? mask : 0;
 
        snd_hdac_adsp_updatel(adev, AVS_ADSP_REG_ADSPCS, mask, value);
+       /* Delay the polling to avoid false positives. */
+       usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
 
        mask = AVS_ADSPCS_CPA_MASK(core_mask);
        value = power ? mask : 0;
@@ -82,11 +85,15 @@ int avs_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
                                       reg, (reg & mask) == value,
                                       AVS_ADSPCS_INTERVAL_US,
                                       AVS_ADSPCS_TIMEOUT_US);
-       if (ret)
+       if (ret) {
                dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
                        core_mask, stall ? "" : "un", ret);
+               return ret;
+       }
 
-       return ret;
+       /* Give HW time to propagate the change. */
+       usleep_range(AVS_ADSPCS_DELAY_US, 2 * AVS_ADSPCS_DELAY_US);
+       return 0;
 }
 
 int avs_dsp_core_enable(struct avs_dev *adev, u32 core_mask)
index d755ba8b85188b307467e86be21cd68927a1eb04..020d85c7520de99fd52ffa3f1c28d007cefe8196 100644 (file)
@@ -480,6 +480,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
        ret = ipc->rx.rsp.status;
        if (reply) {
                reply->header = ipc->rx.header;
+               reply->size = ipc->rx.size;
                if (reply->data && ipc->rx.size)
                        memcpy(reply->data, ipc->rx.data, reply->size);
        }
index 542fd44aa501e5a65469f1926054c16d474d2914..9e3f8ff33a87ac85b47d4b2552bc801f295a99b7 100644 (file)
@@ -27,8 +27,8 @@
 #define APL_ROM_INIT_RETRIES           3
 
 #define AVS_FW_INIT_POLLING_US         500
-#define AVS_FW_INIT_TIMEOUT_US         3000000
 #define AVS_FW_INIT_TIMEOUT_MS         3000
+#define AVS_FW_INIT_TIMEOUT_US         (AVS_FW_INIT_TIMEOUT_MS * 1000)
 
 #define AVS_CLDMA_START_DELAY_MS       100
 
index 6404fce8cde455bd20d88cb4ad1dc6f35d99ad7c..d4bcee1aabcf2788e61edf9db31ce13a5204999e 100644 (file)
@@ -59,7 +59,7 @@ int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids)
        request.data = mod_ids;
        request.size = sizeof(*mod_ids) * num_mod_ids;
 
-       ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS);
+       ret = avs_dsp_send_msg(adev, &request, NULL);
        if (ret)
                avs_ipc_err(adev, &request, "unload multiple modules", ret);
 
@@ -378,7 +378,6 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
        union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_GET);
        struct avs_ipc_msg request;
        struct avs_ipc_msg reply = {{0}};
-       size_t size;
        void *buf;
        int ret;
 
@@ -406,15 +405,14 @@ int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id
                return ret;
        }
 
-       size = reply.rsp.ext.large_config.data_off_size;
-       buf = krealloc(reply.data, size, GFP_KERNEL);
+       buf = krealloc(reply.data, reply.size, GFP_KERNEL);
        if (!buf) {
                kfree(reply.data);
                return -ENOMEM;
        }
 
        *reply_data = buf;
-       *reply_size = size;
+       *reply_size = reply.size;
 
        return 0;
 }
@@ -476,6 +474,9 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
                                       &payload, &payload_size);
        if (ret)
                return ret;
+       /* Non-zero payload expected for FIRMWARE_CONFIG. */
+       if (!payload_size)
+               return -EREMOTEIO;
 
        while (offset < payload_size) {
                tlv = (struct avs_tlv *)(payload + offset);
@@ -561,6 +562,7 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
                case AVS_FW_CFG_DMA_BUFFER_CONFIG:
                case AVS_FW_CFG_SCHEDULER_CONFIG:
                case AVS_FW_CFG_CLOCKS_CONFIG:
+               case AVS_FW_CFG_RESERVED:
                        break;
 
                default:
@@ -589,6 +591,9 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg)
                                       &payload, &payload_size);
        if (ret)
                return ret;
+       /* Non-zero payload expected for HARDWARE_CONFIG. */
+       if (!payload_size)
+               return -EREMOTEIO;
 
        while (offset < payload_size) {
                tlv = (struct avs_tlv *)(payload + offset);
@@ -672,6 +677,9 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
                                       &payload, &payload_size);
        if (ret)
                return ret;
+       /* Non-zero payload expected for MODULES_INFO. */
+       if (!payload_size)
+               return -EREMOTEIO;
 
        *info = (struct avs_mods_info *)payload;
        return 0;
index 3d46dd5e5bc4946ed54c2a89fa17802d6750360b..ce157a8d65520a651a1165012b07a3f24f98cbd7 100644 (file)
@@ -449,35 +449,39 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)
        return ret;
 }
 
+static int avs_probe_create(struct avs_dev *adev, struct avs_path_module *mod)
+{
+       dev_err(adev->dev, "Probe module can't be instantiated by topology");
+       return -EINVAL;
+}
+
+struct avs_module_create {
+       guid_t *guid;
+       int (*create)(struct avs_dev *adev, struct avs_path_module *mod);
+};
+
+static struct avs_module_create avs_module_create[] = {
+       { &AVS_MIXIN_MOD_UUID, avs_modbase_create },
+       { &AVS_MIXOUT_MOD_UUID, avs_modbase_create },
+       { &AVS_KPBUFF_MOD_UUID, avs_modbase_create },
+       { &AVS_COPIER_MOD_UUID, avs_copier_create },
+       { &AVS_MICSEL_MOD_UUID, avs_micsel_create },
+       { &AVS_MUX_MOD_UUID, avs_mux_create },
+       { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create },
+       { &AVS_SRCINTC_MOD_UUID, avs_src_create },
+       { &AVS_AEC_MOD_UUID, avs_aec_create },
+       { &AVS_ASRC_MOD_UUID, avs_asrc_create },
+       { &AVS_INTELWOV_MOD_UUID, avs_wov_create },
+       { &AVS_PROBE_MOD_UUID, avs_probe_create },
+};
+
 static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod)
 {
        const guid_t *type = &mod->template->cfg_ext->type;
 
-       if (guid_equal(type, &AVS_MIXIN_MOD_UUID) ||
-           guid_equal(type, &AVS_MIXOUT_MOD_UUID) ||
-           guid_equal(type, &AVS_KPBUFF_MOD_UUID))
-               return avs_modbase_create(adev, mod);
-       if (guid_equal(type, &AVS_COPIER_MOD_UUID))
-               return avs_copier_create(adev, mod);
-       if (guid_equal(type, &AVS_MICSEL_MOD_UUID))
-               return avs_micsel_create(adev, mod);
-       if (guid_equal(type, &AVS_MUX_MOD_UUID))
-               return avs_mux_create(adev, mod);
-       if (guid_equal(type, &AVS_UPDWMIX_MOD_UUID))
-               return avs_updown_mix_create(adev, mod);
-       if (guid_equal(type, &AVS_SRCINTC_MOD_UUID))
-               return avs_src_create(adev, mod);
-       if (guid_equal(type, &AVS_AEC_MOD_UUID))
-               return avs_aec_create(adev, mod);
-       if (guid_equal(type, &AVS_ASRC_MOD_UUID))
-               return avs_asrc_create(adev, mod);
-       if (guid_equal(type, &AVS_INTELWOV_MOD_UUID))
-               return avs_wov_create(adev, mod);
-
-       if (guid_equal(type, &AVS_PROBE_MOD_UUID)) {
-               dev_err(adev->dev, "Probe module can't be instantiated by topology");
-               return -EINVAL;
-       }
+       for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++)
+               if (guid_equal(type, avs_module_create[i].guid))
+                       return avs_module_create[i].create(adev, mod);
 
        return avs_modext_create(adev, mod);
 }
index 668f533578a69e89aa7f2817fe4094754ea217af..f21b0cdd320630cfca48253574e701470a1b8919 100644 (file)
@@ -846,7 +846,6 @@ static const struct snd_soc_component_driver avs_component_driver = {
        .pcm_construct          = avs_component_construct,
        .module_get_upon_open   = 1, /* increment refcount when a pcm is opened */
        .topology_name_prefix   = "intel/avs",
-       .non_legacy_dai_naming  = true,
 };
 
 static int avs_soc_component_register(struct device *dev, const char *name,
@@ -1172,7 +1171,6 @@ static const struct snd_soc_component_driver avs_hda_component_driver = {
        .remove_order           = SND_SOC_COMP_ORDER_EARLY,
        .module_get_upon_open   = 1,
        .topology_name_prefix   = "intel/avs",
-       .non_legacy_dai_naming  = true,
 };
 
 int avs_hda_platform_register(struct avs_dev *adev, const char *name)
index 6a06fe387d13bde13a3356178ed804a185e65b81..8a9f9fc48938e2ceaa7e692afcbe715b4dd6397d 100644 (file)
@@ -808,6 +808,30 @@ static const struct avs_tplg_token_parser pin_format_parsers[] = {
        },
 };
 
+static void
+assign_copier_gtw_instance(struct snd_soc_component *comp, struct avs_tplg_modcfg_ext *cfg)
+{
+       struct snd_soc_acpi_mach *mach;
+
+       if (!guid_equal(&cfg->type, &AVS_COPIER_MOD_UUID))
+               return;
+
+       /* Only I2S boards assign port instance in ->i2s_link_mask. */
+       switch (cfg->copier.dma_type) {
+       case AVS_DMA_I2S_LINK_OUTPUT:
+       case AVS_DMA_I2S_LINK_INPUT:
+               break;
+       default:
+               return;
+       }
+
+       mach = dev_get_platdata(comp->card->dev);
+
+       /* Automatic assignment only when board describes single SSP. */
+       if (hweight_long(mach->mach_params.i2s_link_mask) == 1 && !cfg->copier.vindex.i2s.instance)
+               cfg->copier.vindex.i2s.instance = __ffs(mach->mach_params.i2s_link_mask);
+}
+
 static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
                                     struct avs_tplg_modcfg_ext *cfg,
                                     struct snd_soc_tplg_vendor_array *tuples,
@@ -827,6 +851,9 @@ static int avs_tplg_parse_modcfg_ext(struct snd_soc_component *comp,
        if (ret)
                return ret;
 
+       /* Update copier gateway based on board's i2s_link_mask. */
+       assign_copier_gtw_instance(comp, cfg);
+
        block_size -= esize;
        /* Parse trailing in/out pin formats if any. */
        if (block_size) {
index f3873b5bea87e02f3573b24ab7e8e2b363589670..aa12d7e3dd2f9b86605186678a911677508b53ac 100644 (file)
@@ -41,7 +41,7 @@ config SND_SOC_INTEL_SOF_CIRRUS_COMMON
 if SND_SOC_INTEL_CATPT
 
 config SND_SOC_INTEL_HASWELL_MACH
-       tristate "Haswell Lynxpoint"
+       tristate "Haswell with RT5640 I2S codec"
        depends on I2C
        depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
        depends on X86_INTEL_LPSS || COMPILE_TEST
@@ -85,7 +85,7 @@ config SND_SOC_INTEL_BDW_RT5677_MACH
          If unsure select "N".
 
 config SND_SOC_INTEL_BROADWELL_MACH
-       tristate "Broadwell Wildcatpoint"
+       tristate "Broadwell with RT286 I2S codec"
        depends on I2C
        depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST
        depends on X86_INTEL_LPSS || COMPILE_TEST
@@ -660,7 +660,6 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
        depends on MFD_INTEL_LPSS || COMPILE_TEST
        depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
        depends on SOUNDWIRE
-       depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC
        select SND_SOC_MAX98373_I2C
        select SND_SOC_MAX98373_SDW
        select SND_SOC_RT700_SDW
index 40c0c3d1c500766631621f213679e387cf1743af..eea1e26acfdaa206eef3f9d938d2a8d47294479d 100644 (file)
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0-only
-snd-soc-sst-haswell-objs := haswell.o
+snd-soc-sst-haswell-objs := hsw_rt5640.o
 snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o
 snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
-snd-soc-sst-broadwell-objs := broadwell.o
+snd-soc-sst-broadwell-objs := bdw_rt286.o
 snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
 snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
 snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o
index aae857fdcdb8b27d96de986515b20c6345cddce6..67c3f49b924c9c88b9e86443a03d611a841892e6 100644 (file)
@@ -249,6 +249,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = {
                /* SSP0 - Codec */
                .name = "Codec",
                .id = 0,
+               .nonatomic = 1,
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBC_CFC,
index d0ecbba2febe2b8dd9b26dfe77a2f11a9f244223..31488702768eb2785f100995cedde33eabaa06e1 100644 (file)
@@ -349,6 +349,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = {
                /* SSP0 - Codec */
                .name = "Codec",
                .id = 0,
+               .nonatomic = 1,
                .no_pcm = 1,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                        SND_SOC_DAIFMT_CBC_CFC,
diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c
new file mode 100644 (file)
index 0000000..6b76df0
--- /dev/null
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sound card driver for Intel Broadwell Wildcat Point with Realtek 286
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/rt286.h"
+
+static struct snd_soc_jack card_headset;
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+};
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_MIC("DMIC1", NULL),
+       SND_SOC_DAPM_MIC("DMIC2", NULL),
+       SND_SOC_DAPM_LINE("Line Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+       {"Speaker", NULL, "SPOR"},
+       {"Speaker", NULL, "SPOL"},
+
+       {"Headphone Jack", NULL, "HPO Pin"},
+
+       {"MIC1", NULL, "Mic Jack"},
+       {"LINE1", NULL, "Line Jack"},
+
+       {"DMIC1 Pin", NULL, "DMIC1"},
+       {"DMIC2 Pin", NULL, "DMIC2"},
+
+       /* CODEC BE connections */
+       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int codec_link_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *codec = asoc_rtd_to_codec(rtd, 0)->component;
+       int ret;
+
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                        &card_headset, card_headset_pins,
+                                        ARRAY_SIZE(card_headset_pins));
+       if (ret)
+               return ret;
+
+       return snd_soc_component_set_jack(codec, &card_headset, NULL);
+}
+
+static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                     struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+       /* The ADSP will convert the FE rate to 48kHz, stereo. */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+       /* Set SSP0 to 16 bit. */
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+       return 0;
+}
+
+static int codec_link_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static const struct snd_soc_ops codec_link_ops = {
+       .hw_params = codec_link_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
+SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
+SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
+SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
+SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
+SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+       /* Front End DAI links */
+       {
+               .name = "System PCM",
+               .stream_name = "System Playback/Capture",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(system, dummy, platform),
+       },
+       {
+               .name = "Offload0",
+               .stream_name = "Offload0 Playback",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(offload0, dummy, platform),
+       },
+       {
+               .name = "Offload1",
+               .stream_name = "Offload1 Playback",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(offload1, dummy, platform),
+       },
+       {
+               .name = "Loopback PCM",
+               .stream_name = "Loopback",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(loopback, dummy, platform),
+       },
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "Codec",
+               .id = 0,
+               .nonatomic = 1,
+               .no_pcm = 1,
+               .init = codec_link_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = codec_link_hw_params_fixup,
+               .ops = &codec_link_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
+       },
+};
+
+static void bdw_rt286_disable_jack(struct snd_soc_card *card)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component) {
+               if (!strcmp(component->name, "i2c-INT343A:00")) {
+                       dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
+                       snd_soc_component_set_jack(component, NULL, NULL);
+                       break;
+               }
+       }
+}
+
+static int bdw_rt286_suspend(struct snd_soc_card *card)
+{
+       bdw_rt286_disable_jack(card);
+
+       return 0;
+}
+
+static int bdw_rt286_resume(struct snd_soc_card *card)
+{
+       struct snd_soc_component *component;
+
+       for_each_card_components(card, component) {
+               if (!strcmp(component->name, "i2c-INT343A:00")) {
+                       dev_dbg(component->dev, "enabling jack detect for resume.\n");
+                       snd_soc_component_set_jack(component, &card_headset, NULL);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static struct snd_soc_card bdw_rt286_card = {
+       .owner = THIS_MODULE,
+       .dai_link = card_dai_links,
+       .num_links = ARRAY_SIZE(card_dai_links),
+       .controls = card_controls,
+       .num_controls = ARRAY_SIZE(card_controls),
+       .dapm_widgets = card_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(card_widgets),
+       .dapm_routes = card_routes,
+       .num_dapm_routes = ARRAY_SIZE(card_routes),
+       .fully_routed = true,
+       .suspend_pre = bdw_rt286_suspend,
+       .resume_post = bdw_rt286_resume,
+};
+
+/* Use space before codec name to simplify card ID, and simplify driver name. */
+#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
+#define SOF_DRIVER_NAME "SOF"
+
+#define CARD_NAME "broadwell-rt286"
+
+static int bdw_rt286_probe(struct platform_device *pdev)
+{
+       struct snd_soc_acpi_mach *mach;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       bdw_rt286_card.dev = dev;
+       mach = dev_get_platdata(dev);
+
+       ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt286_card, mach->mach_params.platform);
+       if (ret)
+               return ret;
+
+       if (snd_soc_acpi_sof_parent(dev)) {
+               bdw_rt286_card.name = SOF_CARD_NAME;
+               bdw_rt286_card.driver_name = SOF_DRIVER_NAME;
+       } else {
+               bdw_rt286_card.name = CARD_NAME;
+       }
+
+       return devm_snd_soc_register_card(dev, &bdw_rt286_card);
+}
+
+static int bdw_rt286_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       bdw_rt286_disable_jack(card);
+
+       return 0;
+}
+
+static struct platform_driver bdw_rt286_driver = {
+       .probe = bdw_rt286_probe,
+       .remove = bdw_rt286_remove,
+       .driver = {
+               .name = "bdw_rt286",
+               .pm = &snd_soc_pm_ops
+       },
+};
+
+module_platform_driver(bdw_rt286_driver)
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Sound card driver for Intel Broadwell Wildcat Point with Realtek 286");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bdw_rt286");
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c
deleted file mode 100644 (file)
index c30a9dc..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Broadwell Wildcatpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-#include <sound/pcm_params.h>
-#include <sound/soc-acpi.h>
-
-#include "../../codecs/rt286.h"
-
-static struct snd_soc_jack broadwell_headset;
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin broadwell_headset_pins[] = {
-       {
-               .pin = "Mic Jack",
-               .mask = SND_JACK_MICROPHONE,
-       },
-       {
-               .pin = "Headphone Jack",
-               .mask = SND_JACK_HEADPHONE,
-       },
-};
-
-static const struct snd_kcontrol_new broadwell_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Speaker"),
-       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
-};
-
-static const struct snd_soc_dapm_widget broadwell_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_SPK("Speaker", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-       SND_SOC_DAPM_MIC("DMIC1", NULL),
-       SND_SOC_DAPM_MIC("DMIC2", NULL),
-       SND_SOC_DAPM_LINE("Line Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
-
-       /* speaker */
-       {"Speaker", NULL, "SPOR"},
-       {"Speaker", NULL, "SPOL"},
-
-       /* HP jack connectors - unknown if we have jack deteck */
-       {"Headphone Jack", NULL, "HPO Pin"},
-
-       /* other jacks */
-       {"MIC1", NULL, "Mic Jack"},
-       {"LINE1", NULL, "Line Jack"},
-
-       /* digital mics */
-       {"DMIC1 Pin", NULL, "DMIC1"},
-       {"DMIC2 Pin", NULL, "DMIC2"},
-
-       /* CODEC BE connections */
-       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
-       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
-};
-
-static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
-       int ret = 0;
-       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
-               SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset,
-               broadwell_headset_pins, ARRAY_SIZE(broadwell_headset_pins));
-       if (ret)
-               return ret;
-
-       rt286_mic_detect(component, &broadwell_headset);
-       return 0;
-}
-
-
-static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
-                       struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                                                     SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *chan = hw_param_interval(params,
-                                                     SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The ADSP will covert the FE rate to 48k, stereo */
-       rate->min = rate->max = 48000;
-       chan->min = chan->max = 2;
-
-       /* set SSP0 to 16 bit */
-       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
-       return 0;
-}
-
-static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000,
-               SND_SOC_CLOCK_IN);
-
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
-               return ret;
-       }
-
-       return ret;
-}
-
-static const struct snd_soc_ops broadwell_rt286_ops = {
-       .hw_params = broadwell_rt286_hw_params,
-};
-
-static const unsigned int channels[] = {
-       2,
-};
-
-static const struct snd_pcm_hw_constraint_list constraints_channels = {
-       .count = ARRAY_SIZE(channels),
-       .list = channels,
-       .mask = 0,
-};
-
-static int broadwell_fe_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       /* Board supports stereo configuration only */
-       runtime->hw.channels_max = 2;
-       return snd_pcm_hw_constraint_list(runtime, 0,
-                                         SNDRV_PCM_HW_PARAM_CHANNELS,
-                                         &constraints_channels);
-}
-
-static const struct snd_soc_ops broadwell_fe_ops = {
-       .startup = broadwell_fe_startup,
-};
-
-SND_SOC_DAILINK_DEF(system,
-       DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(offload0,
-       DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
-
-SND_SOC_DAILINK_DEF(offload1,
-       DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
-
-SND_SOC_DAILINK_DEF(loopback,
-       DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
-
-SND_SOC_DAILINK_DEF(dummy,
-       DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(platform,
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
-
-SND_SOC_DAILINK_DEF(codec,
-       DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1")));
-
-SND_SOC_DAILINK_DEF(ssp0_port,
-           DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-
-/* broadwell digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link broadwell_rt286_dais[] = {
-       /* Front End DAI links */
-       {
-               .name = "System PCM",
-               .stream_name = "System Playback/Capture",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .ops = &broadwell_fe_ops,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               SND_SOC_DAILINK_REG(system, dummy, platform),
-       },
-       {
-               .name = "Offload0",
-               .stream_name = "Offload0 Playback",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               SND_SOC_DAILINK_REG(offload0, dummy, platform),
-       },
-       {
-               .name = "Offload1",
-               .stream_name = "Offload1 Playback",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               SND_SOC_DAILINK_REG(offload1, dummy, platform),
-       },
-       {
-               .name = "Loopback PCM",
-               .stream_name = "Loopback",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_capture = 1,
-               SND_SOC_DAILINK_REG(loopback, dummy, platform),
-       },
-       /* Back End DAI links */
-       {
-               /* SSP0 - Codec */
-               .name = "Codec",
-               .id = 0,
-               .no_pcm = 1,
-               .init = broadwell_rt286_codec_init,
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBC_CFC,
-               .ignore_pmdown_time = 1,
-               .be_hw_params_fixup = broadwell_ssp0_fixup,
-               .ops = &broadwell_rt286_ops,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
-       },
-};
-
-static int broadwell_disable_jack(struct snd_soc_card *card)
-{
-       struct snd_soc_component *component;
-
-       for_each_card_components(card, component) {
-               if (!strcmp(component->name, "i2c-INT343A:00")) {
-
-                       dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
-                       rt286_mic_detect(component, NULL);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int broadwell_suspend(struct snd_soc_card *card)
-{
-       return broadwell_disable_jack(card);
-}
-
-static int broadwell_resume(struct snd_soc_card *card){
-       struct snd_soc_component *component;
-
-       for_each_card_components(card, component) {
-               if (!strcmp(component->name, "i2c-INT343A:00")) {
-
-                       dev_dbg(component->dev, "enabling jack detect for resume.\n");
-                       rt286_mic_detect(component, &broadwell_headset);
-                       break;
-               }
-       }
-       return 0;
-}
-
-/* use space before codec name to simplify card ID, and simplify driver name */
-#define SOF_CARD_NAME "bdw rt286" /* card name will be 'sof-bdw rt286' */
-#define SOF_DRIVER_NAME "SOF"
-
-#define CARD_NAME "broadwell-rt286"
-#define DRIVER_NAME NULL /* card name will be used for driver name */
-
-/* broadwell audio machine driver for WPT + RT286S */
-static struct snd_soc_card broadwell_rt286 = {
-       .owner = THIS_MODULE,
-       .dai_link = broadwell_rt286_dais,
-       .num_links = ARRAY_SIZE(broadwell_rt286_dais),
-       .controls = broadwell_controls,
-       .num_controls = ARRAY_SIZE(broadwell_controls),
-       .dapm_widgets = broadwell_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
-       .dapm_routes = broadwell_rt286_map,
-       .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map),
-       .fully_routed = true,
-       .suspend_pre = broadwell_suspend,
-       .resume_post = broadwell_resume,
-};
-
-static int broadwell_audio_probe(struct platform_device *pdev)
-{
-       struct snd_soc_acpi_mach *mach;
-       int ret;
-
-       broadwell_rt286.dev = &pdev->dev;
-
-       /* override platform name, if required */
-       mach = pdev->dev.platform_data;
-       ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286,
-                                                   mach->mach_params.platform);
-       if (ret)
-               return ret;
-
-       /* set card and driver name */
-       if (snd_soc_acpi_sof_parent(&pdev->dev)) {
-               broadwell_rt286.name = SOF_CARD_NAME;
-               broadwell_rt286.driver_name = SOF_DRIVER_NAME;
-       } else {
-               broadwell_rt286.name = CARD_NAME;
-               broadwell_rt286.driver_name = DRIVER_NAME;
-       }
-
-       return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286);
-}
-
-static int broadwell_audio_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       return broadwell_disable_jack(card);
-}
-
-static struct platform_driver broadwell_audio = {
-       .probe = broadwell_audio_probe,
-       .remove = broadwell_audio_remove,
-       .driver = {
-               .name = "broadwell-audio",
-               .pm = &snd_soc_pm_ops
-       },
-};
-
-module_platform_driver(broadwell_audio)
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:broadwell-audio");
index d98376da425a6699c833c861d424a1f611760fdf..7c6c95e99ade298d7c4e34972c49069123cb75a0 100644 (file)
@@ -186,6 +186,17 @@ static const struct snd_soc_dapm_route gemini_map[] = {
        {"ssp2 Rx", NULL, "Capture"},
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
                        struct snd_pcm_hw_params *params)
 {
@@ -231,10 +242,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
-                       &broxton_headset);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                        &broxton_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
index 75995d17597d9527ccaaec6f80d96e6648747a58..4bd93c3ba3777046267e47442b415ee64302ef2a 100644 (file)
@@ -176,7 +176,7 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                return ret;
 
-       rt298_mic_detect(component, &broxton_headset);
+       snd_soc_component_set_jack(component, &broxton_headset, NULL);
 
        snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
index 0eed68a11f7e1ef4b4d46596fb697981b1fa80ca..ae899866863e5de9f15c0c1b702152aa8f966e9e 100644 (file)
@@ -126,7 +126,7 @@ static int byt_cht_cx2072x_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                SND_SOC_DAIFMT_I2S     |
                                SND_SOC_DAIFMT_NB_NF   |
-                               SND_SOC_DAIFMT_CBC_CFC);
+                               SND_SOC_DAIFMT_BP_FP);
        if (ret < 0) {
                dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
                return ret;
index eb19bf16afad47b1878d076ac7bfd2d17e2ee74b..a0c8f1d3f8cec83a77cfb6098c645d939281d10e 100644 (file)
@@ -81,7 +81,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                  SND_SOC_DAIFMT_I2S     |
                                  SND_SOC_DAIFMT_NB_NF   |
-                                 SND_SOC_DAIFMT_CBC_CFC);
+                                 SND_SOC_DAIFMT_BP_FP);
        if (ret < 0) {
                dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
                return ret;
index a08507783e44ac42545a135751c294829416af56..6432b83f616f38e6edc9daed67e9d1c274a47b99 100644 (file)
@@ -265,7 +265,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                SND_SOC_DAIFMT_I2S     |
                                SND_SOC_DAIFMT_NB_NF   |
-                               SND_SOC_DAIFMT_CBC_CFC
+                               SND_SOC_DAIFMT_BP_FP
                );
        if (ret < 0) {
                dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
index 115c2bcaabd4fd4e2285117ac692aa0a92a4dd0a..7fc03f2efd35608ada9a461e135d49b1ff366a05 100644 (file)
@@ -61,7 +61,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                  SND_SOC_DAIFMT_I2S     |
                                  SND_SOC_DAIFMT_NB_NF   |
-                                 SND_SOC_DAIFMT_CBC_CFC);
+                                 SND_SOC_DAIFMT_BP_FP);
 
        if (ret < 0) {
                dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
index ed9fa17287227078b9f00fc642aede73da960f67..fb9d9e271845daae00b9afad7a17c24a91387d9b 100644 (file)
@@ -1413,7 +1413,7 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                  SND_SOC_DAIFMT_I2S     |
                                  SND_SOC_DAIFMT_NB_NF   |
-                                 SND_SOC_DAIFMT_CBC_CFC);
+                                 SND_SOC_DAIFMT_BP_FP);
        if (ret < 0) {
                dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
                return ret;
@@ -1636,7 +1636,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
                 * with the codec driver/pdata are non-existent
                 */
 
-               struct acpi_chan_package chan_package;
+               struct acpi_chan_package chan_package = { 0 };
 
                /* format specified: 2 64-bit integers */
                struct acpi_buffer format = {sizeof("NN"), "NN"};
index d467fcaa48eaa007cf3500b9d59b697b11b3351e..2beb686768f24b717ef162882460120ddf55aef3 100644 (file)
@@ -706,7 +706,7 @@ static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                  SND_SOC_DAIFMT_I2S     |
                                  SND_SOC_DAIFMT_NB_NF   |
-                                 SND_SOC_DAIFMT_CBC_CFC
+                                 SND_SOC_DAIFMT_BP_FP
                                  );
 
        if (ret < 0) {
@@ -952,7 +952,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
                 * with the codec driver/pdata are non-existent
                 */
 
-               struct acpi_chan_package chan_package;
+               struct acpi_chan_package chan_package = { 0 };
 
                /* format specified: 2 64-bit integers */
                struct acpi_buffer format = {sizeof("NN"), "NN"};
index 330c0ace16387ea54e5662a64aba5830da89c354..45a6805787f569cde54c4ea459a5752f583e6788 100644 (file)
@@ -265,7 +265,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                  SND_SOC_DAIFMT_I2S     |
                                  SND_SOC_DAIFMT_NB_NF   |
-                                 SND_SOC_DAIFMT_CBC_CFC);
+                                 SND_SOC_DAIFMT_BP_FP);
        if (ret) {
                dev_err(rtd->dev, "Error setting format to I2S: %d\n", ret);
                return ret;
index a5160f27adea93ef90ea655c678e296a942634c7..64eb73525ee3767b1e599b23af8b6c020fea9e92 100644 (file)
@@ -264,8 +264,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                return ret;
        }
 
-       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-                               | SND_SOC_DAIFMT_CBC_CFC;
+       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;
 
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
        if (ret < 0) {
index 45c301ea5e0034ace44fc6dcc51b38f63558b077..96501aed8bee261feddc8657d30b23f71c1800fb 100644 (file)
@@ -362,7 +362,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                        SND_SOC_DAIFMT_I2S     |
                                        SND_SOC_DAIFMT_NB_NF   |
-                                       SND_SOC_DAIFMT_CBC_CFC
+                                       SND_SOC_DAIFMT_BP_FP
                        );
                if (ret < 0) {
                        dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
@@ -372,7 +372,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
                                        SND_SOC_DAIFMT_I2S     |
                                        SND_SOC_DAIFMT_NB_NF   |
-                                       SND_SOC_DAIFMT_CBC_CFC
+                                       SND_SOC_DAIFMT_BC_FC
                        );
                if (ret < 0) {
                        dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
@@ -396,7 +396,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
                ret = snd_soc_dai_set_fmt(asoc_rtd_to_codec(rtd, 0),
                                        SND_SOC_DAIFMT_DSP_B |
                                        SND_SOC_DAIFMT_IB_NF |
-                                       SND_SOC_DAIFMT_CBC_CFC);
+                                       SND_SOC_DAIFMT_BC_FC);
                if (ret < 0) {
                        dev_err(rtd->dev, "can't set format to TDM %d\n", ret);
                        return ret;
@@ -603,7 +603,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
                 * with the codec driver/pdata are non-existent
                 */
 
-               struct acpi_chan_package chan_package;
+               struct acpi_chan_package chan_package = { 0 };
 
                /* format specified: 2 64-bit integers */
                struct acpi_buffer format = {sizeof("NN"), "NN"};
index c80324f34b1b2b9271d79e367bfb701afae83f24..ca47f6476b07731145e3839bf2d6df2e00c3d6e2 100644 (file)
@@ -300,7 +300,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
        ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
                                  SND_SOC_DAIFMT_I2S     |
                                  SND_SOC_DAIFMT_NB_NF   |
-                                 SND_SOC_DAIFMT_CBC_CFC);
+                                 SND_SOC_DAIFMT_BP_FP);
        if (ret < 0) {
                dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
                return ret;
index a99f74a15b5fda4ad8a4d18146362d2cf1a87a57..20da83d9eeced55a57e3d7cf1542e1ebe5c47ea3 100644 (file)
@@ -121,6 +121,17 @@ static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = {
        {"TR Ext Spk", NULL, "TR SPO" },
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -137,11 +148,13 @@ static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                                   SND_JACK_BTN_3,
-                                   &ctx->headset);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3,
+                                        &ctx->headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
index 170164baae7da2547af214a5d2c29fce4bbd69a1..cf0f89db3e204fcddf70da03753ca04d59e1b7e0 100644 (file)
@@ -78,6 +78,17 @@ static const struct snd_soc_dapm_widget geminilake_widgets[] = {
        SND_SOC_DAPM_SPK("HDMI3", NULL),
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route geminilake_map[] = {
        /* HP jack connectors - unknown if we have jack detection */
        { "Headphone Jack", NULL, "HPOL" },
@@ -173,10 +184,12 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
-                       &ctx->geminilake_headset);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                        &ctx->geminilake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c
deleted file mode 100644 (file)
index aa61e10..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Haswell Lynxpoint SST Audio
- *
- * Copyright (C) 2013, Intel Corporation. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
-#include <sound/pcm_params.h>
-
-#include "../../codecs/rt5640.h"
-
-/* Haswell ULT platforms have a Headphone and Mic jack */
-static const struct snd_soc_dapm_widget haswell_widgets[] = {
-       SND_SOC_DAPM_HP("Headphones", NULL),
-       SND_SOC_DAPM_MIC("Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
-
-       {"Headphones", NULL, "HPOR"},
-       {"Headphones", NULL, "HPOL"},
-       {"IN2P", NULL, "Mic"},
-
-       /* CODEC BE connections */
-       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
-       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
-};
-
-static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
-                       struct snd_pcm_hw_params *params)
-{
-       struct snd_interval *rate = hw_param_interval(params,
-                       SNDRV_PCM_HW_PARAM_RATE);
-       struct snd_interval *channels = hw_param_interval(params,
-                                               SNDRV_PCM_HW_PARAM_CHANNELS);
-
-       /* The ADSP will covert the FE rate to 48k, stereo */
-       rate->min = rate->max = 48000;
-       channels->min = channels->max = 2;
-
-       /* set SSP0 to 16 bit */
-       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
-       return 0;
-}
-
-static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
-               SND_SOC_CLOCK_IN);
-
-       if (ret < 0) {
-               dev_err(rtd->dev, "can't set codec sysclk configuration\n");
-               return ret;
-       }
-
-       /* set correct codec filter for DAI format and clock config */
-       snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
-
-       return ret;
-}
-
-static const struct snd_soc_ops haswell_rt5640_ops = {
-       .hw_params = haswell_rt5640_hw_params,
-};
-
-SND_SOC_DAILINK_DEF(dummy,
-       DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
-SND_SOC_DAILINK_DEF(system,
-       DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
-
-SND_SOC_DAILINK_DEF(offload0,
-       DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
-
-SND_SOC_DAILINK_DEF(offload1,
-       DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
-
-SND_SOC_DAILINK_DEF(loopback,
-       DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
-
-SND_SOC_DAILINK_DEF(codec,
-       DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));
-
-SND_SOC_DAILINK_DEF(platform,
-       DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
-
-SND_SOC_DAILINK_DEF(ssp0_port,
-           DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
-
-static struct snd_soc_dai_link haswell_rt5640_dais[] = {
-       /* Front End DAI links */
-       {
-               .name = "System",
-               .stream_name = "System Playback/Capture",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               SND_SOC_DAILINK_REG(system, dummy, platform),
-       },
-       {
-               .name = "Offload0",
-               .stream_name = "Offload0 Playback",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               SND_SOC_DAILINK_REG(offload0, dummy, platform),
-       },
-       {
-               .name = "Offload1",
-               .stream_name = "Offload1 Playback",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_playback = 1,
-               SND_SOC_DAILINK_REG(offload1, dummy, platform),
-       },
-       {
-               .name = "Loopback",
-               .stream_name = "Loopback",
-               .nonatomic = 1,
-               .dynamic = 1,
-               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
-               .dpcm_capture = 1,
-               SND_SOC_DAILINK_REG(loopback, dummy, platform),
-       },
-
-       /* Back End DAI links */
-       {
-               /* SSP0 - Codec */
-               .name = "Codec",
-               .id = 0,
-               .no_pcm = 1,
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBC_CFC,
-               .ignore_pmdown_time = 1,
-               .be_hw_params_fixup = haswell_ssp0_fixup,
-               .ops = &haswell_rt5640_ops,
-               .dpcm_playback = 1,
-               .dpcm_capture = 1,
-               SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
-       },
-};
-
-/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
-static struct snd_soc_card haswell_rt5640 = {
-       .name = "haswell-rt5640",
-       .owner = THIS_MODULE,
-       .dai_link = haswell_rt5640_dais,
-       .num_links = ARRAY_SIZE(haswell_rt5640_dais),
-       .dapm_widgets = haswell_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
-       .dapm_routes = haswell_rt5640_map,
-       .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
-       .fully_routed = true,
-};
-
-static int haswell_audio_probe(struct platform_device *pdev)
-{
-       struct snd_soc_acpi_mach *mach;
-       int ret;
-
-       haswell_rt5640.dev = &pdev->dev;
-
-       /* override platform name, if required */
-       mach = pdev->dev.platform_data;
-       ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640,
-                                                   mach->mach_params.platform);
-       if (ret)
-               return ret;
-
-       return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640);
-}
-
-static struct platform_driver haswell_audio = {
-       .probe = haswell_audio_probe,
-       .driver = {
-               .name = "haswell-audio",
-               .pm = &snd_soc_pm_ops,
-       },
-};
-
-module_platform_driver(haswell_audio)
-
-/* Module information */
-MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
-MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:haswell-audio");
index 5c31ddc0884abebd26a0c6139d44f44099c85d6d..83c7dfbccd9d4575812705b9f1dd12881eb88444 100644 (file)
@@ -62,8 +62,8 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card,
                        hpcm->pcm = spcm;
                        hpcm->device = spcm->device;
                        dev_dbg(card->dev,
-                               "%s: mapping HDMI converter %d to PCM %d (%p)\n",
-                               __func__, i, hpcm->device, spcm);
+                               "mapping HDMI converter %d to PCM %d (%p)\n",
+                               i, hpcm->device, spcm);
                } else {
                        hpcm->pcm = NULL;
                        hpcm->device = SNDRV_PCM_INVALID_DEVICE;
diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c
new file mode 100644 (file)
index 0000000..050c53e
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sound card driver for Intel Haswell Lynx Point with Realtek 5640
+ *
+ * Copyright (C) 2013, Intel Corporation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "../../codecs/rt5640.h"
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+       {"Headphones", NULL, "HPOR"},
+       {"Headphones", NULL, "HPOL"},
+       {"IN2P", NULL, "Mic"},
+
+       /* CODEC BE connections */
+       {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
+       {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
+};
+
+static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                     struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+       /* The ADSP will convert the FE rate to 48k, stereo. */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+       /* Set SSP0 to 16 bit. */
+       params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+       return 0;
+}
+
+static int codec_link_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);
+               return ret;
+       }
+
+       /* Set correct codec filter for DAI format and clock config. */
+       snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
+
+       return ret;
+}
+
+static const struct snd_soc_ops codec_link_ops = {
+       .hw_params = codec_link_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));
+SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));
+SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));
+SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));
+
+SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
+SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));
+SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));
+SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));
+
+static struct snd_soc_dai_link card_dai_links[] = {
+       /* Front End DAI links */
+       {
+               .name = "System",
+               .stream_name = "System Playback/Capture",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(system, dummy, platform),
+       },
+       {
+               .name = "Offload0",
+               .stream_name = "Offload0 Playback",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(offload0, dummy, platform),
+       },
+       {
+               .name = "Offload1",
+               .stream_name = "Offload1 Playback",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(offload1, dummy, platform),
+       },
+       {
+               .name = "Loopback",
+               .stream_name = "Loopback",
+               .nonatomic = 1,
+               .dynamic = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(loopback, dummy, platform),
+       },
+       /* Back End DAI links */
+       {
+               /* SSP0 - Codec */
+               .name = "Codec",
+               .id = 0,
+               .nonatomic = 1,
+               .no_pcm = 1,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+               .ignore_pmdown_time = 1,
+               .be_hw_params_fixup = codec_link_hw_params_fixup,
+               .ops = &codec_link_ops,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(ssp0_port, codec, platform),
+       },
+};
+
+static struct snd_soc_card hsw_rt5640_card = {
+       .name = "haswell-rt5640",
+       .owner = THIS_MODULE,
+       .dai_link = card_dai_links,
+       .num_links = ARRAY_SIZE(card_dai_links),
+       .dapm_widgets = card_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(card_widgets),
+       .dapm_routes = card_routes,
+       .num_dapm_routes = ARRAY_SIZE(card_routes),
+       .fully_routed = true,
+};
+
+static int hsw_rt5640_probe(struct platform_device *pdev)
+{
+       struct snd_soc_acpi_mach *mach;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       hsw_rt5640_card.dev = dev;
+       mach = dev_get_platdata(dev);
+
+       ret = snd_soc_fixup_dai_links_platform_name(&hsw_rt5640_card, mach->mach_params.platform);
+       if (ret)
+               return ret;
+
+       return devm_snd_soc_register_card(dev, &hsw_rt5640_card);
+}
+
+static struct platform_driver hsw_rt5640_driver = {
+       .probe = hsw_rt5640_probe,
+       .driver = {
+               .name = "hsw_rt5640",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(hsw_rt5640_driver)
+
+MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
+MODULE_DESCRIPTION("Sound card driver for Intel Haswell Lynx Point with Realtek 5640");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hsw_rt5640");
index ceabed85e9daab9abf018855836075526dd46321..329457e3e3a22de7550b20813fd91c3d2c71bfc9 100644 (file)
@@ -99,6 +99,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
                        SND_SOC_DAPM_POST_PMD),
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route kabylake_map[] = {
        { "Headphone Jack", NULL, "HPL" },
        { "Headphone Jack", NULL, "HPR" },
@@ -179,10 +190,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
-                       &ctx->kabylake_headset);
+       ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                        &ctx->kabylake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
index 703ccff634b014d99bfd9db3b9d2505c94dd1e06..362579f25835ec88e081635d40ec1330f7505f74 100644 (file)
@@ -119,6 +119,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
                        SND_SOC_DAPM_POST_PMD),
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route kabylake_map[] = {
        /* speaker */
        { "Left Spk", NULL, "Left BE_OUT" },
@@ -354,10 +365,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
-                       &ctx->kabylake_headset);
+       ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                        &ctx->kabylake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
index 8d37b2676a81aa85db7b764a43941fbec2ed240a..2d4224c5b1520b39e5044f0446c53a3353ca2902 100644 (file)
@@ -206,6 +206,17 @@ static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
                        SND_SOC_DAPM_POST_PMD),
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route kabylake_5663_map[] = {
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headphone Jack", NULL, "HPOL" },
@@ -271,10 +282,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                       &ctx->kabylake_headset);
+       ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &ctx->kabylake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
                return ret;
index 564c70a0fbc83386078ff4838eb5301d97e7ecb4..2c79fca57b19e76bf9a22707d3495a5edadada7b 100644 (file)
@@ -145,6 +145,17 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
 
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route kabylake_map[] = {
        /* Headphones */
        { "Headphone Jack", NULL, "Platform Clock" },
@@ -228,10 +239,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                       &ctx->kabylake_headset);
+       ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &ctx->kabylake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
                return ret;
index f4b4eeca3e03c2d03b00cbf06de073c7666cd8ab..81144efb4b44e4bcc826f653c32e336d40972687 100644 (file)
@@ -75,7 +75,7 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
        struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
        int ret = 0;
 
-       dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name);
+       dev_dbg(card->dev, "dai link name - %s\n", link->name);
        link->platforms->name = ctx->platform_name;
        link->nonatomic = 1;
 
@@ -203,7 +203,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
        struct skl_hda_private *ctx;
        int ret;
 
-       dev_dbg(&pdev->dev, "%s: entry\n", __func__);
+       dev_dbg(&pdev->dev, "entry\n");
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
index 8e2d03e36079263c500326fe55317989af26db1c..8dceb0b025812cda4ee603a3a567eb0f02984d3e 100644 (file)
@@ -97,6 +97,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
                        SND_SOC_DAPM_POST_PMD),
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route skylake_map[] = {
        /* HP jack connectors - unknown if we have jack detection */
        { "Headphone Jack", NULL, "HPOL" },
@@ -163,9 +174,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset);
+       ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
                return ret;
index 501f0bbfc4045fc7eebd0fed5e3a586354883392..62c0d46d008624deea76938363cf7877725f5ea9 100644 (file)
@@ -101,6 +101,17 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
                        SND_SOC_DAPM_POST_PMD),
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static const struct snd_soc_dapm_route skylake_map[] = {
        /* HP jack connectors - unknown if we have jack detection */
        {"Headphone Jack", NULL, "HPOL"},
@@ -182,9 +193,11 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
         * 4 buttons here map to the google Reference headset
         * The use of these buttons can be decided by the user space.
         */
-       ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
-               SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-               SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset);
+       ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
                return ret;
index e9f9520dcea43a870bf3b8020a3b2ff66d87ec01..4f3d655e2bfa8dd79d6952bee9ed73ea638de2be 100644 (file)
@@ -133,7 +133,7 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                return ret;
 
-       rt286_mic_detect(component, &skylake_headset);
+       snd_soc_component_set_jack(component, &skylake_headset, NULL);
 
        snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
 
index 6a979c333bc59e65b1ed99d2c1def7f426894d32..85ffd065895d3bc0d3df5638e844ab066f7f702c 100644 (file)
 #define SOF_CS42L42_DAILINK_MASK               (GENMASK(24, 10))
 #define SOF_CS42L42_DAILINK(link1, link2, link3, link4, link5) \
        ((((link1) | ((link2) << 3) | ((link3) << 6) | ((link4) << 9) | ((link5) << 12)) << SOF_CS42L42_DAILINK_SHIFT) & SOF_CS42L42_DAILINK_MASK)
-#define SOF_MAX98357A_SPEAKER_AMP_PRESENT      BIT(25)
-#define SOF_MAX98360A_SPEAKER_AMP_PRESENT      BIT(26)
+#define SOF_BT_OFFLOAD_PRESENT                 BIT(25)
+#define SOF_CS42L42_SSP_BT_SHIFT               26
+#define SOF_CS42L42_SSP_BT_MASK                        (GENMASK(28, 26))
+#define SOF_CS42L42_SSP_BT(quirk)      \
+       (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK)
+#define SOF_MAX98357A_SPEAKER_AMP_PRESENT      BIT(29)
+#define SOF_MAX98360A_SPEAKER_AMP_PRESENT      BIT(30)
 
 enum {
        LINK_NONE = 0,
@@ -50,6 +55,18 @@ enum {
        LINK_SPK = 2,
        LINK_DMIC = 3,
        LINK_HDMI = 4,
+       LINK_BT = 5,
+};
+
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
 };
 
 /* Default: SSP2 */
@@ -98,11 +115,13 @@ static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                                   SND_JACK_BTN_3,
-                                   jack);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3,
+                                        jack,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
@@ -277,6 +296,13 @@ static struct snd_soc_dai_link_component dmic_component[] = {
        }
 };
 
+static struct snd_soc_dai_link_component dummy_component[] = {
+       {
+               .name = "snd-soc-dummy",
+               .dai_name = "snd-soc-dummy-dai",
+       }
+};
+
 static int create_spk_amp_dai_links(struct device *dev,
                                    struct snd_soc_dai_link *links,
                                    struct snd_soc_dai_link_component *cpus,
@@ -466,9 +492,50 @@ devm_err:
        return -ENOMEM;
 }
 
+static int create_bt_offload_dai_links(struct device *dev,
+                                      struct snd_soc_dai_link *links,
+                                      struct snd_soc_dai_link_component *cpus,
+                                      int *id, int ssp_bt)
+{
+       /* bt offload */
+       if (!(sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT))
+               return 0;
+
+       links[*id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT",
+                                        ssp_bt);
+       if (!links[*id].name)
+               goto devm_err;
+
+       links[*id].id = *id;
+       links[*id].codecs = dummy_component;
+       links[*id].num_codecs = ARRAY_SIZE(dummy_component);
+       links[*id].platforms = platform_component;
+       links[*id].num_platforms = ARRAY_SIZE(platform_component);
+
+       links[*id].dpcm_playback = 1;
+       links[*id].dpcm_capture = 1;
+       links[*id].no_pcm = 1;
+       links[*id].cpus = &cpus[*id];
+       links[*id].num_cpus = 1;
+
+       links[*id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+                                                  "SSP%d Pin",
+                                                  ssp_bt);
+       if (!links[*id].cpus->dai_name)
+               goto devm_err;
+
+       (*id)++;
+
+       return 0;
+
+devm_err:
+       return -ENOMEM;
+}
+
 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                                                          int ssp_codec,
                                                          int ssp_amp,
+                                                         int ssp_bt,
                                                          int dmic_be_num,
                                                          int hdmi_num)
 {
@@ -521,6 +588,14 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                                goto devm_err;
                        }
                        break;
+               case LINK_BT:
+                       ret = create_bt_offload_dai_links(dev, links, cpus, &id, ssp_bt);
+                       if (ret < 0) {
+                               dev_err(dev, "fail to create bt offload dai links, ret %d\n",
+                                       ret);
+                               goto devm_err;
+                       }
+                       break;
                case LINK_NONE:
                        /* caught here if it's not used as terminator in macro */
                default:
@@ -542,7 +617,7 @@ static int sof_audio_probe(struct platform_device *pdev)
        struct snd_soc_acpi_mach *mach;
        struct sof_card_private *ctx;
        int dmic_be_num, hdmi_num;
-       int ret, ssp_amp, ssp_codec;
+       int ret, ssp_bt, ssp_amp, ssp_codec;
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
@@ -567,6 +642,9 @@ static int sof_audio_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk);
 
+       ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >>
+                       SOF_CS42L42_SSP_BT_SHIFT;
+
        ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >>
                        SOF_CS42L42_SSP_AMP_SHIFT;
 
@@ -577,9 +655,11 @@ static int sof_audio_probe(struct platform_device *pdev)
 
        if (sof_cs42l42_quirk & SOF_SPEAKER_AMP_PRESENT)
                sof_audio_card_cs42l42.num_links++;
+       if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT)
+               sof_audio_card_cs42l42.num_links++;
 
        dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
-                                             dmic_be_num, hdmi_num);
+                                             ssp_bt, dmic_be_num, hdmi_num);
        if (!dai_links)
                return -ENOMEM;
 
@@ -620,6 +700,17 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_CS42L42_SSP_AMP(1)) |
                                        SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_NONE),
        },
+       {
+               .name = "adl_mx98360a_cs4242",
+               .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) |
+                               SOF_SPEAKER_AMP_PRESENT |
+                               SOF_MAX98360A_SPEAKER_AMP_PRESENT |
+                               SOF_CS42L42_SSP_AMP(1) |
+                               SOF_CS42L42_NUM_HDMIDEV(4) |
+                               SOF_BT_OFFLOAD_PRESENT |
+                               SOF_CS42L42_SSP_BT(2) |
+                               SOF_CS42L42_DAILINK(LINK_HP, LINK_DMIC, LINK_HDMI, LINK_SPK, LINK_BT)),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index a83f30b687cf375b6ca472263f1d32aaef4d926f..34cf849a8344e9382a01eacfad7ca279de43ee71 100644 (file)
@@ -135,6 +135,17 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
        {"DMic", NULL, "SoC DMIC"},
 };
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static struct snd_soc_jack headset;
 
 static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
@@ -156,11 +167,13 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                                   SND_JACK_BTN_3 | SND_JACK_LINEOUT,
-                                   &headset);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                        &headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
index 23d03e0f77599239553c70a1d026570ddc55dc51..c7f33c89588e746abfd89b1fbbcff4046100e162 100644 (file)
 #define SOF_ES8336_SSP_CODEC_MASK              (GENMASK(3, 0))
 
 #define SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK     BIT(4)
+
+/* HDMI capture*/
+#define SOF_SSP_HDMI_CAPTURE_PRESENT           BIT(14)
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT               15
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_MASK                (GENMASK(16, 15))
+#define SOF_NO_OF_HDMI_CAPTURE_SSP(quirk)      \
+       (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK)
+
+#define SOF_HDMI_CAPTURE_1_SSP_SHIFT           7
+#define SOF_HDMI_CAPTURE_1_SSP_MASK            (GENMASK(9, 7))
+#define SOF_HDMI_CAPTURE_1_SSP(quirk)  \
+       (((quirk) << SOF_HDMI_CAPTURE_1_SSP_SHIFT) & SOF_HDMI_CAPTURE_1_SSP_MASK)
+
+#define SOF_HDMI_CAPTURE_2_SSP_SHIFT           10
+#define SOF_HDMI_CAPTURE_2_SSP_MASK            (GENMASK(12, 10))
+#define SOF_HDMI_CAPTURE_2_SSP(quirk)  \
+       (((quirk) << SOF_HDMI_CAPTURE_2_SSP_SHIFT) & SOF_HDMI_CAPTURE_2_SSP_MASK)
+
 #define SOF_ES8336_ENABLE_DMIC                 BIT(5)
 #define SOF_ES8336_JD_INVERTED                 BIT(6)
 #define SOF_ES8336_HEADPHONE_GPIO              BIT(7)
@@ -57,28 +75,26 @@ static const struct acpi_gpio_params enable_gpio0 = { 0, 0, true };
 static const struct acpi_gpio_params enable_gpio1 = { 1, 0, true };
 
 static const struct acpi_gpio_mapping acpi_speakers_enable_gpio0[] = {
-       { "speakers-enable-gpios", &enable_gpio0, 1 },
+       { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
        { }
 };
 
 static const struct acpi_gpio_mapping acpi_speakers_enable_gpio1[] = {
-       { "speakers-enable-gpios", &enable_gpio1, 1 },
+       { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
 };
 
 static const struct acpi_gpio_mapping acpi_enable_both_gpios[] = {
-       { "speakers-enable-gpios", &enable_gpio0, 1 },
-       { "headphone-enable-gpios", &enable_gpio1, 1 },
+       { "speakers-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+       { "headphone-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
        { }
 };
 
 static const struct acpi_gpio_mapping acpi_enable_both_gpios_rev_order[] = {
-       { "speakers-enable-gpios", &enable_gpio1, 1 },
-       { "headphone-enable-gpios", &enable_gpio0, 1 },
+       { "speakers-enable-gpios", &enable_gpio1, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+       { "headphone-enable-gpios", &enable_gpio0, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
        { }
 };
 
-static const struct acpi_gpio_mapping *gpio_mapping = acpi_speakers_enable_gpio0;
-
 static void log_quirks(struct device *dev)
 {
        dev_info(dev, "quirk mask %#lx\n", quirk);
@@ -272,15 +288,6 @@ static int sof_es8336_quirk_cb(const struct dmi_system_id *id)
 {
        quirk = (unsigned long)id->driver_data;
 
-       if (quirk & SOF_ES8336_HEADPHONE_GPIO) {
-               if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
-                       gpio_mapping = acpi_enable_both_gpios;
-               else
-                       gpio_mapping = acpi_enable_both_gpios_rev_order;
-       } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) {
-               gpio_mapping = acpi_speakers_enable_gpio1;
-       }
-
        return 1;
 }
 
@@ -356,6 +363,13 @@ static struct snd_soc_dai_link_component dmic_component[] = {
        }
 };
 
+static struct snd_soc_dai_link_component dummy_component[] = {
+       {
+               .name = "snd-soc-dummy",
+               .dai_name = "snd-soc-dummy-dai",
+       }
+};
+
 static int sof_es8336_late_probe(struct snd_soc_card *card)
 {
        struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
@@ -507,6 +521,37 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                id++;
        }
 
+       /* HDMI-In SSP */
+       if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT) {
+               int num_of_hdmi_ssp = (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
+                               SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+
+               for (i = 1; i <= num_of_hdmi_ssp; i++) {
+                       int port = (i == 1 ? (quirk & SOF_HDMI_CAPTURE_1_SSP_MASK) >>
+                                               SOF_HDMI_CAPTURE_1_SSP_SHIFT :
+                                               (quirk & SOF_HDMI_CAPTURE_2_SSP_MASK) >>
+                                               SOF_HDMI_CAPTURE_2_SSP_SHIFT);
+
+                       links[id].cpus = &cpus[id];
+                       links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+                                                                 "SSP%d Pin", port);
+                       if (!links[id].cpus->dai_name)
+                               return NULL;
+                       links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
+                       if (!links[id].name)
+                               return NULL;
+                       links[id].id = id + hdmi_id_offset;
+                       links[id].codecs = dummy_component;
+                       links[id].num_codecs = ARRAY_SIZE(dummy_component);
+                       links[id].platforms = platform_component;
+                       links[id].num_platforms = ARRAY_SIZE(platform_component);
+                       links[id].dpcm_capture = 1;
+                       links[id].no_pcm = 1;
+                       links[id].num_cpus = 1;
+                       id++;
+               }
+       }
+
        return links;
 
 devm_err:
@@ -529,6 +574,7 @@ static int sof_es8336_probe(struct platform_device *pdev)
        struct acpi_device *adev;
        struct snd_soc_dai_link *dai_links;
        struct device *codec_dev;
+       const struct acpi_gpio_mapping *gpio_mapping;
        unsigned int cnt = 0;
        int dmic_be_num = 0;
        int hdmi_num = 3;
@@ -541,29 +587,34 @@ static int sof_es8336_probe(struct platform_device *pdev)
        card = &sof_es8336_card;
        card->dev = dev;
 
+       if (pdev->id_entry && pdev->id_entry->driver_data)
+               quirk = (unsigned long)pdev->id_entry->driver_data;
+
        /* check GPIO DMI quirks */
        dmi_check_system(sof_es8336_quirk_table);
 
-       if (!mach->mach_params.i2s_link_mask) {
-               dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
-       } else {
-               /*
-                * Set configuration based on platform NHLT.
-                * In this machine driver, we can only support one SSP for the
-                * ES8336 link, the else-if below are intentional.
-                * In some cases multiple SSPs can be reported by NHLT, starting MSB-first
-                * seems to pick the right connection.
-                */
-               unsigned long ssp = 0;
-
-               if (mach->mach_params.i2s_link_mask & BIT(2))
-                       ssp = SOF_ES8336_SSP_CODEC(2);
-               else if (mach->mach_params.i2s_link_mask & BIT(1))
-                       ssp = SOF_ES8336_SSP_CODEC(1);
-               else  if (mach->mach_params.i2s_link_mask & BIT(0))
-                       ssp = SOF_ES8336_SSP_CODEC(0);
-
-               quirk |= ssp;
+       /* Use NHLT configuration only for Non-HDMI capture use case.
+        * Because more than one SSP will be enabled for HDMI capture hence wrong codec
+        * SSP will be set.
+        */
+       if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER) {
+               if (!mach->mach_params.i2s_link_mask) {
+                       dev_warn(dev, "No I2S link information provided, using SSP0. This may need to be modified with the quirk module parameter\n");
+               } else {
+                       /*
+                        * Set configuration based on platform NHLT.
+                        * In this machine driver, we can only support one SSP for the
+                        * ES8336 link.
+                        * In some cases multiple SSPs can be reported by NHLT, starting MSB-first
+                        * seems to pick the right connection.
+                        */
+                       unsigned long ssp;
+
+                       /* fls returns 1-based results, SSPs indices are 0-based */
+                       ssp = fls(mach->mach_params.i2s_link_mask) - 1;
+
+                       quirk |= ssp;
+               }
        }
 
        if (mach->mach_params.dmic_num)
@@ -579,7 +630,13 @@ static int sof_es8336_probe(struct platform_device *pdev)
        if (quirk & SOF_ES8336_ENABLE_DMIC)
                dmic_be_num = 2;
 
-       sof_es8336_card.num_links += dmic_be_num + hdmi_num;
+       /* compute number of dai links */
+       sof_es8336_card.num_links = 1 + dmic_be_num + hdmi_num;
+
+       if (quirk & SOF_SSP_HDMI_CAPTURE_PRESENT)
+               sof_es8336_card.num_links += (quirk & SOF_NO_OF_HDMI_CAPTURE_SSP_MASK) >>
+                               SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+
        dai_links = sof_card_dai_links_create(dev,
                                              SOF_ES8336_SSP_CODEC(quirk),
                                              dmic_be_num, hdmi_num);
@@ -635,6 +692,17 @@ static int sof_es8336_probe(struct platform_device *pdev)
        }
 
        /* get speaker enable GPIO */
+       if (quirk & SOF_ES8336_HEADPHONE_GPIO) {
+               if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK)
+                       gpio_mapping = acpi_enable_both_gpios;
+               else
+                       gpio_mapping = acpi_enable_both_gpios_rev_order;
+       } else if (quirk & SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK) {
+               gpio_mapping = acpi_speakers_enable_gpio1;
+       } else {
+               gpio_mapping = acpi_speakers_enable_gpio0;
+       }
+
        ret = devm_acpi_dev_add_driver_gpios(codec_dev, gpio_mapping);
        if (ret)
                dev_warn(codec_dev, "unable to add GPIO mapping table\n");
@@ -690,6 +758,21 @@ static int sof_es8336_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id board_ids[] = {
+       {
+               .name = "adl_es83x6_c1_h02",
+               .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+                                       SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+                                       SOF_HDMI_CAPTURE_1_SSP(0) |
+                                       SOF_HDMI_CAPTURE_2_SSP(2) |
+                                       SOF_SSP_HDMI_CAPTURE_PRESENT |
+                                       SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+                                       SOF_ES8336_JD_INVERTED),
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, board_ids);
+
 static struct platform_driver sof_es8336_driver = {
        .driver = {
                .name = "sof-essx8336",
@@ -697,6 +780,7 @@ static struct platform_driver sof_es8336_driver = {
        },
        .probe = sof_es8336_probe,
        .remove = sof_es8336_remove,
+       .id_table = board_ids,
 };
 module_platform_driver(sof_es8336_driver);
 
index 97dcd204a24664f26d31768c02b101971b77a346..8d7e5ba9e51627521e7f0ce122dbb829560df0cf 100644 (file)
@@ -81,6 +81,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -93,11 +104,13 @@ static int sof_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                                   SND_JACK_BTN_3,
-                                   &ctx->sof_headset);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3,
+                                        &ctx->sof_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
@@ -177,11 +190,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
        struct sof_hdmi_pcm *pcm;
        int err;
 
-       if (list_empty(&ctx->hdmi_pcm_list))
-               return -EINVAL;
-
-       pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
-
        if (sof_nau8825_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
                /* Disable Left and Right Spk pin after boot */
                snd_soc_dapm_disable_pin(dapm, "Left Spk");
@@ -191,6 +199,11 @@ static int sof_card_late_probe(struct snd_soc_card *card)
                        return err;
        }
 
+       if (list_empty(&ctx->hdmi_pcm_list))
+               return -EINVAL;
+
+       pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, head);
+
        return hda_dsp_hdmi_build_controls(card, pcm->codec_dai->component);
 }
 
index 6815204e58d588f88140f23222d8f927de7dbb09..d4c67d5340a92a5bda7da1bd8b45fd229ad35c2c 100644 (file)
@@ -419,7 +419,7 @@ static int sof_audio_probe(struct platform_device *pdev)
 static int sof_pcm512x_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct snd_soc_component *component = NULL;
+       struct snd_soc_component *component;
 
        for_each_card_components(card, component) {
                if (!strcmp(component->name, pcm512x_component[0].name)) {
index 2ab568c1d40bad85ec720adb3653264768695585..b9643ca2e2f228cf220e322ab3ca44d08c93edd8 100644 (file)
@@ -463,26 +463,26 @@ EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
  * 2-amp Configuration for RT1019
  */
 
-static const struct snd_soc_dapm_route rt1019_dapm_routes[] = {
+static const struct snd_soc_dapm_route rt1019p_dapm_routes[] = {
        /* speaker */
        { "Left Spk", NULL, "Speaker" },
        { "Right Spk", NULL, "Speaker" },
 };
 
-static struct snd_soc_dai_link_component rt1019_components[] = {
+static struct snd_soc_dai_link_component rt1019p_components[] = {
        {
-               .name = RT1019_DEV0_NAME,
-               .dai_name = RT1019_CODEC_DAI,
+               .name = RT1019P_DEV0_NAME,
+               .dai_name = RT1019P_CODEC_DAI,
        },
 };
 
-static int rt1019_init(struct snd_soc_pcm_runtime *rtd)
+static int rt1019p_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
        int ret;
 
-       ret = snd_soc_dapm_add_routes(&card->dapm, rt1019_dapm_routes,
-                                     ARRAY_SIZE(rt1019_dapm_routes));
+       ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes,
+                                     ARRAY_SIZE(rt1019p_dapm_routes));
        if (ret) {
                dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
                return ret;
@@ -490,13 +490,13 @@ static int rt1019_init(struct snd_soc_pcm_runtime *rtd)
        return ret;
 }
 
-void sof_rt1019_dai_link(struct snd_soc_dai_link *link)
+void sof_rt1019p_dai_link(struct snd_soc_dai_link *link)
 {
-       link->codecs = rt1019_components;
-       link->num_codecs = ARRAY_SIZE(rt1019_components);
-       link->init = rt1019_init;
+       link->codecs = rt1019p_components;
+       link->num_codecs = ARRAY_SIZE(rt1019p_components);
+       link->init = rt1019p_init;
 }
-EXPORT_SYMBOL_NS(sof_rt1019_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
+EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON);
 
 MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers");
 MODULE_LICENSE("GPL");
index ec3eea633e048e54704607792c169c288532d03b..77844342109003cc678c4f08fd7101f919446046 100644 (file)
@@ -39,9 +39,9 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card);
 #define RT1308_DEV0_NAME       "i2c-10EC1308:00"
 void sof_rt1308_dai_link(struct snd_soc_dai_link *link);
 
-#define RT1019_CODEC_DAI       "HiFi"
-#define RT1019_DEV0_NAME       "RTL1019:00"
+#define RT1019P_CODEC_DAI      "HiFi"
+#define RT1019P_DEV0_NAME      "RTL1019:00"
 
-void sof_rt1019_dai_link(struct snd_soc_dai_link *link);
+void sof_rt1019p_dai_link(struct snd_soc_dai_link *link);
 
 #endif /* __SOF_REALTEK_COMMON_H */
index 4a90a0a5d8315b8c68cfcc9103102ea2d8ccab61..045965312245b4bb5ace04ab3ef2e940b3703f79 100644 (file)
@@ -247,6 +247,17 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
@@ -294,11 +305,13 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                                   SND_JACK_BTN_3,
-                                   &ctx->sof_headset);
+       ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3,
+                                        &ctx->sof_headset,
+                                        jack_pins,
+                                        ARRAY_SIZE(jack_pins));
        if (ret) {
                dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
@@ -434,6 +447,15 @@ static int sof_card_late_probe(struct snd_soc_card *card)
        struct sof_hdmi_pcm *pcm;
        int err;
 
+       if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
+               /* Disable Left and Right Spk pin after boot */
+               snd_soc_dapm_disable_pin(dapm, "Left Spk");
+               snd_soc_dapm_disable_pin(dapm, "Right Spk");
+               err = snd_soc_dapm_sync(dapm);
+               if (err < 0)
+                       return err;
+       }
+
        /* HDMI is not supported by SOF on Baytrail/CherryTrail */
        if (is_legacy_cpu || !ctx->idisp_codec)
                return 0;
@@ -464,15 +486,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
                        return err;
        }
 
-       if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
-               /* Disable Left and Right Spk pin after boot */
-               snd_soc_dapm_disable_pin(dapm, "Left Spk");
-               snd_soc_dapm_disable_pin(dapm, "Right Spk");
-               err = snd_soc_dapm_sync(dapm);
-               if (err < 0)
-                       return err;
-       }
-
        return hdac_hdmi_jack_port_init(component, &card->dapm);
 }
 
@@ -731,7 +744,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
                        sof_rt1015p_dai_link(&links[id]);
                } else if (sof_rt5682_quirk & SOF_RT1019_SPEAKER_AMP_PRESENT) {
-                       sof_rt1019_dai_link(&links[id]);
+                       sof_rt1019p_dai_link(&links[id]);
                } else if (sof_rt5682_quirk &
                                SOF_MAX98373_SPEAKER_AMP_PRESENT) {
                        links[id].codecs = max_98373_components;
@@ -1079,6 +1092,14 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_RT5682_SSP_AMP(1) |
                                        SOF_RT5682_NUM_HDMIDEV(4)),
        },
+       {
+               .name = "mtl_mx98357_rt5682",
+               .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT5682_SSP_AMP(1) |
+                                       SOF_RT5682_NUM_HDMIDEV(4)),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index ad826ad82d51a78f59fea863fe8747ea0f616675..a49bfaab6b21fa8c41cd63bea0cc5c933d47d6e7 100644 (file)
@@ -246,6 +246,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_BT_OFFLOAD_SSP(2) |
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
        },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
@@ -315,6 +325,23 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        RT711_JD2 |
                                        SOF_SDW_FOUR_SPK),
        },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2),
+       },
+       /* MeteorLake devices */
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
+               },
+               .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
+       },
        {}
 };
 
@@ -1127,10 +1154,14 @@ static int sof_card_dai_links_create(struct device *dev,
        for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
                codec_info_list[i].amp_num = 0;
 
-       if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
-               hdmi_num = SOF_TGL_HDMI_COUNT;
-       else
-               hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
+       if (mach_params->codec_mask & IDISP_CODEC_MASK) {
+               ctx->idisp_codec = true;
+
+               if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
+                       hdmi_num = SOF_TGL_HDMI_COUNT;
+               else
+                       hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
+       }
 
        ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
        /*
@@ -1150,9 +1181,6 @@ static int sof_card_dai_links_create(struct device *dev,
                return ret;
        }
 
-       if (mach_params->codec_mask & IDISP_CODEC_MASK)
-               ctx->idisp_codec = true;
-
        /* enable dmic01 & dmic16k */
        dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
        comp_num += dmic_num;
@@ -1375,7 +1403,9 @@ HDMI:
 
 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
 {
-       int i, ret;
+       struct mc_private *ctx = snd_soc_card_get_drvdata(card);
+       int ret = 0;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
                if (!codec_info_list[i].late_probe)
@@ -1386,7 +1416,10 @@ static int sof_sdw_card_late_probe(struct snd_soc_card *card)
                        return ret;
        }
 
-       return sof_sdw_hdmi_card_late_probe(card);
+       if (ctx->idisp_codec)
+               ret = sof_sdw_hdmi_card_late_probe(card);
+
+       return ret;
 }
 
 /* SoC card */
@@ -1433,7 +1466,7 @@ static int mc_probe(struct platform_device *pdev)
        int amp_num = 0, i;
        int ret;
 
-       dev_dbg(&pdev->dev, "Entry %s\n", __func__);
+       dev_dbg(&pdev->dev, "Entry\n");
 
        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
index 49ff0871e9e776743b6f36d5a37499868d4a9b19..8291967f23f30f0ccac487fb2b6b3db32704c133 100644 (file)
@@ -139,6 +139,9 @@ int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_l
 {
        struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 
+       if (!ctx->headset_codec_dev)
+               return 0;
+
        device_remove_software_node(ctx->headset_codec_dev);
        put_device(ctx->headset_codec_dev);
 
index b3fc32bacfa8f9cee593357071de6cd1a24aa3e4..7f16304d025be955e9f3ac09d28c0a066980caac 100644 (file)
@@ -140,6 +140,9 @@ int sof_sdw_rt711_sdca_exit(struct snd_soc_card *card, struct snd_soc_dai_link *
 {
        struct mc_private *ctx = snd_soc_card_get_drvdata(card);
 
+       if (!ctx->headset_codec_dev)
+               return 0;
+
        device_remove_software_node(ctx->headset_codec_dev);
        put_device(ctx->headset_codec_dev);
 
index 85a34e37316d0aa9467aee95146b4894d943bc78..d48a71d2cf1ecaeb043d8224794c631ebec01ee3 100644 (file)
@@ -254,14 +254,11 @@ static int catpt_acpi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       spec = device_get_match_data(dev);
-       if (!spec)
-               return -ENODEV;
-
        cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
        if (!cdev)
                return -ENOMEM;
 
+       spec = (const struct catpt_spec *)id->driver_data;
        catpt_dev_init(cdev, dev, spec);
 
        /* map DSP bar address */
index a26000cd5cebceb27512a26e983db9a28725fdff..30ca5416c9a3f6610710ec26a0723d9c07ccc11d 100644 (file)
@@ -667,7 +667,9 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
        if (!memcmp(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt)))
                return 0;
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        ret = catpt_ipc_set_device_format(cdev, &devfmt);
 
@@ -853,9 +855,12 @@ static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
                snd_soc_kcontrol_component(kcontrol);
        struct catpt_dev *cdev = dev_get_drvdata(component->dev);
        u32 dspvol;
+       int ret;
        int i;
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
                dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
@@ -876,7 +881,9 @@ static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
        struct catpt_dev *cdev = dev_get_drvdata(component->dev);
        int ret;
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
                               ucontrol->value.integer.value);
@@ -897,6 +904,7 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
        struct catpt_dev *cdev = dev_get_drvdata(component->dev);
        long *ctlvol = (long *)kcontrol->private_value;
        u32 dspvol;
+       int ret;
        int i;
 
        stream = catpt_stream_find(cdev, pin_id);
@@ -906,7 +914,9 @@ static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
                return 0;
        }
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
                dspvol = catpt_stream_volume(cdev, stream, i);
@@ -937,7 +947,9 @@ static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
                return 0;
        }
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
                               ucontrol->value.integer.value);
@@ -1013,7 +1025,9 @@ static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
                return 0;
        }
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
 
index 9579e233a15db4d851148ab16124d541ff54d281..1bdbcc04dc71285199d0a06c843cafcbe25d306f 100644 (file)
@@ -15,7 +15,9 @@ static ssize_t fw_version_show(struct device *dev,
        struct catpt_fw_version version;
        int ret;
 
-       pm_runtime_get_sync(cdev->dev);
+       ret = pm_runtime_resume_and_get(cdev->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
 
        ret = catpt_ipc_get_fw_version(cdev, &version);
 
index fef0b2d1de68b1d6208f0de68a755115952d7fff..8ca8f872ec80ccb050a3e7e119553baae5395eed 100644 (file)
@@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m
        soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \
        soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \
        soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \
+       soc-acpi-intel-mtl-match.o \
        soc-acpi-intel-hda-match.o \
        soc-acpi-intel-sdw-mockup-match.o
 
index c1385161cdc84e9d0dfa98956e71dc0a8e19d34c..9990d5502d264689b20befd46ec665ba3f7c28cf 100644 (file)
@@ -8,6 +8,11 @@
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 
+static const struct snd_soc_acpi_codecs essx_83x6 = {
+       .num_codecs = 3,
+       .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
 static const struct snd_soc_acpi_endpoint single_endpoint = {
        .num = 0,
        .aggregated = 0,
@@ -137,6 +142,15 @@ static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
+       {
+               .adr = 0x000330025D131601ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt1316-1"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
        {
                .adr = 0x000030025D071401ull,
@@ -326,6 +340,20 @@ static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = {
        {}
 };
 
+static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link0_rt1316_link3[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+               .adr_d = rt711_sdca_0_adr,
+       },
+       {
+               .mask = BIT(3),
+               .num_adr = ARRAY_SIZE(rt1316_3_single_adr),
+               .adr_d = rt1316_3_single_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_adr_device mx8373_2_adr[] = {
        {
                .adr = 0x000223019F837300ull,
@@ -412,6 +440,11 @@ static const struct snd_soc_acpi_codecs adl_max98390_amp = {
        .codecs = {"MX98390"}
 };
 
+static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
+       .num_codecs = 1,
+       .codecs = {"INTC10B0"}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
        {
                .comp_ids = &adl_rt5682_rt5682s_hp,
@@ -479,12 +512,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
                .drv_name = "adl_rt5682",
                .sof_tplg_filename = "sof-adl-rt5682.tplg",
        },
+       {
+               .id = "10134242",
+               .drv_name = "adl_mx98360a_cs4242",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &adl_max98360a_amp,
+               .sof_tplg_filename = "sof-adl-max98360a-cs42l42.tplg",
+       },
        /* place amp-only boards in the end of table */
        {
                .id = "CSC3541",
                .drv_name = "adl_cs35l41",
                .sof_tplg_filename = "sof-adl-cs35l41.tplg",
        },
+       {
+               .comp_ids = &essx_83x6,
+               .drv_name = "adl_es83x6_c1_h02",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &adl_lt6911_hdmi,
+               .sof_tplg_filename = "sof-adl-es83x6-ssp1-hdmi-ssp02.tplg",
+       },
+       {
+               .comp_ids = &essx_83x6,
+               .drv_name = "sof-essx8336",
+               .sof_tplg_filename = "sof-adl-es83x6", /* the tplg suffix is added at run time */
+               .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+                                       SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+                                       SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines);
@@ -539,6 +594,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l0.tplg",
        },
+       {
+               .link_mask = 0x9, /* 2 active links required */
+               .links = adl_sdw_rt711_link0_rt1316_link3,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l3.tplg",
+       },
        {
                .link_mask = 0x1, /* link0 required */
                .links = adl_rvp,
index 0441df97b260573480f3fcc67c5b13477406cbdb..cbcb649604e57975f56cf8a4610fb7eaa94addcc 100644 (file)
@@ -12,7 +12,7 @@
 struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = {
        {
                .id = "INT33CA",
-               .drv_name = "haswell-audio",
+               .drv_name = "hsw_rt5640",
                .fw_filename = "intel/IntcSST1.bin",
                .sof_tplg_filename = "sof-hsw.tplg",
        },
@@ -23,7 +23,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_haswell_machines);
 struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
        {
                .id = "INT343A",
-               .drv_name = "broadwell-audio",
+               .drv_name = "bdw_rt286",
                .fw_filename =  "intel/IntcSST2.bin",
                .sof_tplg_filename = "sof-bdw-rt286.tplg",
        },
@@ -41,7 +41,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
        },
        {
                .id = "INT33CA",
-               .drv_name = "haswell-audio",
+               .drv_name = "hsw_rt5640",
                .fw_filename = "intel/IntcSST2.bin",
                .sof_tplg_filename = "sof-bdw-rt5640.tplg",
        },
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
new file mode 100644 (file)
index 0000000..36c361f
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * soc-acpi-intel-mtl-match.c - tables and support for MTL ACPI enumeration.
+ *
+ * Copyright (c) 2022, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "soc-acpi-intel-sdw-mockup-match.h"
+
+static const struct snd_soc_acpi_codecs mtl_max98357a_amp = {
+       .num_codecs = 1,
+       .codecs = {"MX98357A"}
+};
+
+static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = {
+       .num_codecs = 2,
+       .codecs = {"10EC5682", "RTL5682"},
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = {
+       {
+               .comp_ids = &mtl_rt5682_rt5682s_hp,
+               .drv_name = "mtl_mx98357_rt5682",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &mtl_max98357a_amp,
+               .sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_machines);
+
+static const struct snd_soc_acpi_endpoint single_endpoint = {
+       .num = 0,
+       .aggregated = 0,
+       .group_position = 0,
+       .group_id = 0,
+};
+
+static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
+       {
+               .adr = 0x000030025D071101ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt711"
+       }
+};
+
+static const struct snd_soc_acpi_link_adr mtl_rvp[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+               .adr_d = rt711_sdca_0_adr,
+       },
+       {}
+};
+
+/* this table is used when there is no I2S codec present */
+struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
+       /* mockup tests need to be first */
+       {
+               .link_mask = GENMASK(3, 0),
+               .links = sdw_mockup_headset_2amps_mic,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-mtl-rt711-rt1308-rt715.tplg",
+       },
+       {
+               .link_mask = BIT(0) | BIT(1) | BIT(3),
+               .links = sdw_mockup_headset_1amp_mic,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-mtl-rt711-rt1308-mono-rt715.tplg",
+       },
+       {
+               .link_mask = GENMASK(2, 0),
+               .links = sdw_mockup_mic_headset_1amp,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-mtl-rt715-rt711-rt1308-mono.tplg",
+       },
+       {
+               .link_mask = BIT(0),
+               .links = mtl_rvp,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-mtl-rt711.tplg",
+       },
+       {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines);
index a6fb74ba1c4246239a2d2b86df115f4efdab3c3a..b4893365d01d5e537e805c9c8fd03b6b23b625a7 100644 (file)
@@ -388,15 +388,17 @@ static snd_pcm_uframes_t kmb_pcm_pointer(struct snd_soc_component *component,
 }
 
 static const struct snd_soc_component_driver kmb_component = {
-       .name           = "kmb",
-       .pcm_construct  = kmb_platform_pcm_new,
-       .open           = kmb_pcm_open,
-       .trigger        = kmb_pcm_trigger,
-       .pointer        = kmb_pcm_pointer,
+       .name                   = "kmb",
+       .pcm_construct          = kmb_platform_pcm_new,
+       .open                   = kmb_pcm_open,
+       .trigger                = kmb_pcm_trigger,
+       .pointer                = kmb_pcm_pointer,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct snd_soc_component_driver kmb_component_dma = {
-       .name           = "kmb",
+       .name                   = "kmb",
+       .legacy_dai_naming      = 1,
 };
 
 static int kmb_probe(struct snd_soc_dai *cpu_dai)
@@ -497,11 +499,11 @@ static int kmb_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        int ret;
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                kmb_i2s->clock_provider = false;
                ret = 0;
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                writel(CLOCK_PROVIDER_MODE, kmb_i2s->pss_base + I2S_GEN_CFG_0);
 
                ret = clk_prepare_enable(kmb_i2s->clk_i2s);
index 55f310e91b55ce574608d5f9796bc8913be19ab0..9d72ebd812af9958ba62e046ddd6fa831ead63d1 100644 (file)
@@ -1380,7 +1380,10 @@ static int skl_platform_soc_probe(struct snd_soc_component *component)
        const struct skl_dsp_ops *ops;
        int ret;
 
-       pm_runtime_get_sync(component->dev);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
        if (bus->ppcap) {
                skl->component = component;
 
index 9bdf020a2b643e3c05ad4d2a5cbb6a9253f1b273..e06eac592da128a831577d05a34f215ef58ca2a5 100644 (file)
@@ -2950,9 +2950,6 @@ static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
                block_size = ret;
                off += array->size;
 
-               array = (struct snd_soc_tplg_vendor_array *)
-                       (tplg_w->priv.data + off);
-
                data = (tplg_w->priv.data + off);
 
                if (block_type == SKL_TYPE_TUPLE) {
@@ -3599,9 +3596,6 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
                block_size = ret;
                off += array->size;
 
-               array = (struct snd_soc_tplg_vendor_array *)
-                       (manifest->priv.data + off);
-
                data = (manifest->priv.data + off);
 
                if (block_type == SKL_TYPE_TUPLE) {
index 29144720cb622c5e0a187a0b0cd5e3d0cec997ae..e72f826062e9623f17ef8269968849a0665edc41 100644 (file)
@@ -2,7 +2,7 @@
 config SND_JZ4740_SOC_I2S
        tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
        depends on MIPS || COMPILE_TEST
-       depends on OF && HAS_IOMEM
+       depends on HAS_IOMEM
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
index 7ad5d9a924d8085c6decc6b65ae7d3571efbabfc..c4c1e89b47c1b91725810f52ca6946041af455b9 100644 (file)
@@ -5,10 +5,9 @@
 
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -94,9 +93,7 @@ struct i2s_soc_info {
 };
 
 struct jz4740_i2s {
-       struct resource *mem;
        void __iomem *base;
-       dma_addr_t phys_base;
 
        struct clk *clk_aic;
        struct clk *clk_i2s;
@@ -206,18 +203,18 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER;
                format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                conf |= JZ_AIC_CONF_SYNC_CLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_BP_FC:
                conf |= JZ_AIC_CONF_BIT_CLK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                break;
        default:
                return -EINVAL;
@@ -371,21 +368,6 @@ static int jz4740_i2s_resume(struct snd_soc_component *component)
        return 0;
 }
 
-static void jz4740_i2s_init_pcm_config(struct jz4740_i2s *i2s)
-{
-       struct snd_dmaengine_dai_dma_data *dma_data;
-
-       /* Playback */
-       dma_data = &i2s->playback_dma_data;
-       dma_data->maxburst = 16;
-       dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-
-       /* Capture */
-       dma_data = &i2s->capture_dma_data;
-       dma_data->maxburst = 16;
-       dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-}
-
 static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -396,7 +378,6 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
        if (ret)
                return ret;
 
-       jz4740_i2s_init_pcm_config(i2s);
        snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
                &i2s->capture_dma_data);
 
@@ -498,9 +479,10 @@ static const struct i2s_soc_info jz4780_i2s_soc_info = {
 };
 
 static const struct snd_soc_component_driver jz4740_i2s_component = {
-       .name           = "jz4740-i2s",
-       .suspend        = jz4740_i2s_suspend,
-       .resume         = jz4740_i2s_resume,
+       .name                   = "jz4740-i2s",
+       .suspend                = jz4740_i2s_suspend,
+       .resume                 = jz4740_i2s_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct of_device_id jz4740_of_matches[] = {
@@ -529,7 +511,11 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
        if (IS_ERR(i2s->base))
                return PTR_ERR(i2s->base);
 
-       i2s->phys_base = mem->start;
+       i2s->playback_dma_data.maxburst = 16;
+       i2s->playback_dma_data.addr = mem->start + JZ_REG_AIC_FIFO;
+
+       i2s->capture_dma_data.maxburst = 16;
+       i2s->capture_dma_data.addr = mem->start + JZ_REG_AIC_FIFO;
 
        i2s->clk_aic = devm_clk_get(dev, "aic");
        if (IS_ERR(i2s->clk_aic))
index 9e5ce1a82639977e29321e31e582f0d7504006bb..363fa4d476800fffdf2e3d6fdab753fd80076091 100644 (file)
@@ -152,6 +152,51 @@ config SND_SOC_MT8183_DA7219_MAX98357A
          Select Y if you have such device.
          If unsure select "N".
 
+config SND_SOC_MT8186
+       tristate "ASoC support for Mediatek MT8186 chip"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       depends on COMMON_CLK
+       select SND_SOC_MEDIATEK
+       select SND_SOC_MT6358
+       select MFD_SYSCON if SND_SOC_MT6358
+       help
+         This adds ASoC driver for Mediatek MT8186 boards
+         that can be used with other codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
+config SND_SOC_MT8186_MT6366_DA7219_MAX98357
+       tristate "ASoC Audio driver for MT8186 with DA7219 MAX98357A codec"
+       depends on I2C && GPIOLIB
+       depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
+       select SND_SOC_MT6358
+       select SND_SOC_MAX98357A
+       select SND_SOC_DA7219
+       select SND_SOC_BT_SCO
+       select SND_SOC_DMIC
+       select SND_SOC_HDMI_CODEC
+       help
+         This adds ASoC driver for Mediatek MT8186 boards
+         with the MT6366(MT6358) DA7219 MAX98357A codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
+config SND_SOC_MT8186_MT6366_RT1019_RT5682S
+       tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec"
+       depends on I2C && GPIOLIB
+       depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
+       select SND_SOC_MT6358
+       select SND_SOC_RT1015P
+       select SND_SOC_RT5682S
+       select SND_SOC_BT_SCO
+       select SND_SOC_DMIC
+       select SND_SOC_HDMI_CODEC
+       help
+         This adds ASoC driver for Mediatek MT8186 boards
+         with the MT6366(MT6358) RT1019 RT5682S codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
 config SND_SOC_MTK_BTCVSD
        tristate "ALSA BT SCO CVSD/MSBC Driver"
        help
index 34778ca12106fe5a38c0a77b0c9e999529588592..5571c640a288c1d800e52d60f490a7ea158d07c0 100644 (file)
@@ -4,5 +4,6 @@ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
 obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
+obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
 obj-$(CONFIG_SND_SOC_MT8192) += mt8192/
 obj-$(CONFIG_SND_SOC_MT8195) += mt8195/
index acbe01e9e9286d7a393966db391e27663017d91b..576deb7f8cce2c1cf869e76e64a206e9cf16a829 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # platform driver
-snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
+snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o mtk-dsp-sof-common.o
 obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
 
 obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o
diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
new file mode 100644 (file)
index 0000000..8b1b623
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mtk-dsp-sof-common.c  --  MediaTek dsp sof common ctrl
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chunxu Li <chunxu.li@mediatek.com>
+ */
+
+#include "mtk-dsp-sof-common.h"
+#include "mtk-soc-card.h"
+
+/* fixup the BE DAI link to match any values from topology */
+int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+                          struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+       struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+       int i, j, ret = 0;
+
+       for (i = 0; i < sof_priv->num_streams; i++) {
+               struct snd_soc_dai *cpu_dai;
+               struct snd_soc_pcm_runtime *runtime;
+               struct snd_soc_dai_link *sof_dai_link = NULL;
+               const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
+
+               if (strcmp(rtd->dai_link->name, conn->normal_link))
+                       continue;
+
+               for_each_card_rtds(card, runtime) {
+                       if (strcmp(runtime->dai_link->name, conn->sof_link))
+                               continue;
+
+                       for_each_rtd_cpu_dais(runtime, j, cpu_dai) {
+                               if (cpu_dai->stream_active[conn->stream_dir] > 0) {
+                                       sof_dai_link = runtime->dai_link;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+
+               if (sof_dai_link && sof_dai_link->be_hw_params_fixup)
+                       ret = sof_dai_link->be_hw_params_fixup(runtime, params);
+
+               break;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup);
+
+int mtk_sof_card_probe(struct snd_soc_card *card)
+{
+       int i;
+       struct snd_soc_dai_link *dai_link;
+
+       /* Set stream_name to help sof bind widgets */
+       for_each_card_prelinks(card, i, dai_link) {
+               if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name)
+                       dai_link->stream_name = dai_link->name;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_sof_card_probe);
+
+int mtk_sof_card_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_soc_component *sof_comp = NULL;
+       struct mtk_soc_card_data *soc_card_data =
+               snd_soc_card_get_drvdata(card);
+       struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv;
+       int i;
+
+       /* 1. find sof component */
+       for_each_card_rtds(card, rtd) {
+               sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component");
+               if (sof_comp)
+                       break;
+       }
+
+       if (!sof_comp) {
+               dev_info(card->dev, "probe without sof-audio-component\n");
+               return 0;
+       }
+
+       /* 2. add route path and fixup callback */
+       for (i = 0; i < sof_priv->num_streams; i++) {
+               const struct sof_conn_stream *conn = &sof_priv->conn_streams[i];
+               struct snd_soc_pcm_runtime *sof_rtd = NULL;
+               struct snd_soc_pcm_runtime *normal_rtd = NULL;
+
+               for_each_card_rtds(card, rtd) {
+                       if (!strcmp(rtd->dai_link->name, conn->sof_link)) {
+                               sof_rtd = rtd;
+                               continue;
+                       }
+                       if (!strcmp(rtd->dai_link->name, conn->normal_link)) {
+                               normal_rtd = rtd;
+                               continue;
+                       }
+                       if (normal_rtd && sof_rtd)
+                               break;
+               }
+               if (normal_rtd && sof_rtd) {
+                       int j;
+                       struct snd_soc_dai *cpu_dai;
+
+                       for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) {
+                               struct snd_soc_dapm_route route;
+                               struct snd_soc_dapm_path *p = NULL;
+                               struct snd_soc_dapm_widget *play_widget =
+                                       cpu_dai->playback_widget;
+                               struct snd_soc_dapm_widget *cap_widget =
+                                       cpu_dai->capture_widget;
+                               memset(&route, 0, sizeof(route));
+                               if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE &&
+                                   cap_widget) {
+                                       snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) {
+                                               route.source = conn->sof_dma;
+                                               route.sink = p->sink->name;
+                                               snd_soc_dapm_add_routes(&card->dapm, &route, 1);
+                                       }
+                               } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK &&
+                                               play_widget) {
+                                       snd_soc_dapm_widget_for_each_source_path(play_widget, p) {
+                                               route.source = p->source->name;
+                                               route.sink = conn->sof_dma;
+                                               snd_soc_dapm_add_routes(&card->dapm, &route, 1);
+                                       }
+                               } else {
+                                       dev_err(cpu_dai->dev, "stream dir and widget not pair\n");
+                               }
+                       }
+
+                       sof_rtd->dai_link->be_hw_params_fixup =
+                               sof_comp->driver->be_hw_params_fixup;
+                       if (sof_priv->sof_dai_link_fixup)
+                               normal_rtd->dai_link->be_hw_params_fixup =
+                                       sof_priv->sof_dai_link_fixup;
+                       else
+                               normal_rtd->dai_link->be_hw_params_fixup = mtk_sof_dai_link_fixup;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe);
+
+int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
+                            const char *propname, struct snd_soc_dai_link *pre_dai_links,
+                            int pre_num_links)
+{
+       struct device *dev = card->dev;
+       struct snd_soc_dai_link *parsed_dai_link;
+       const char *dai_name = NULL;
+       int i, j, ret, num_links, parsed_num_links = 0;
+
+       num_links = of_property_count_strings(np, "mediatek,dai-link");
+       if (num_links < 0 || num_links > card->num_links) {
+               dev_dbg(dev, "number of dai-link is invalid\n");
+               return -EINVAL;
+       }
+
+       parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL);
+       if (!parsed_dai_link)
+               return -ENOMEM;
+
+       for (i = 0; i < num_links; i++) {
+               ret = of_property_read_string_index(np, propname, i, &dai_name);
+               if (ret) {
+                       dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n",
+                               propname, i, ret);
+                       return ret;
+               }
+               dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name);
+               for (j = 0; j < pre_num_links; j++) {
+                       if (!strcmp(dai_name, pre_dai_links[j].name)) {
+                               memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j],
+                                      sizeof(struct snd_soc_dai_link));
+                               break;
+                       }
+               }
+       }
+
+       if (parsed_num_links != num_links)
+               return -EINVAL;
+
+       card->dai_link = parsed_dai_link;
+       card->num_links = parsed_num_links;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of);
diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.h b/sound/soc/mediatek/common/mtk-dsp-sof-common.h
new file mode 100644 (file)
index 0000000..dd38c4a
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtk-dsp-sof-common.h  --  MediaTek dsp sof common definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chunxu Li <chunxu.li@mediatek.com>
+ */
+
+#ifndef _MTK_DSP_SOF_COMMON_H_
+#define _MTK_DSP_SOF_COMMON_H_
+
+#include <sound/soc.h>
+
+struct sof_conn_stream {
+       const char *normal_link;
+       const char *sof_link;
+       const char *sof_dma;
+       int stream_dir;
+};
+
+struct mtk_sof_priv {
+       const struct sof_conn_stream *conn_streams;
+       int num_streams;
+       int (*sof_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd,
+                                 struct snd_pcm_hw_params *params);
+};
+
+int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+                          struct snd_pcm_hw_params *params);
+int mtk_sof_card_probe(struct snd_soc_card *card);
+int mtk_sof_card_late_probe(struct snd_soc_card *card);
+int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
+                            const char *propname, struct snd_soc_dai_link *pre_dai_links,
+                            int pre_num_links);
+
+#endif
diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h
new file mode 100644 (file)
index 0000000..eeda793
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mtk-soc-card.h  --  MediaTek soc card data definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chunxu Li <chunxu.li@mediatek.com>
+ */
+
+#ifndef _MTK_SOC_CARD_H_
+#define _MTK_SOC_CARD_H_
+
+struct mtk_soc_card_data {
+       void *mach_priv;
+       void *sof_priv;
+};
+
+#endif
index 496f32bcfb5e3b0db77a4f7f6310c45e0396baf8..d2f6213a6bfccffc764c9cd82754fa44039cf3b6 100644 (file)
@@ -217,7 +217,8 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev)
        if (!codec_node) {
                dev_err(&pdev->dev,
                        "Property 'audio-codec' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_platform_node;
        }
        for_each_card_prelinks(card, i, dai_link) {
                if (dai_link->codecs->name)
@@ -230,6 +231,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
                        __func__, ret);
 
+       of_node_put(codec_node);
+put_platform_node:
+       of_node_put(platform_node);
        return ret;
 }
 
index 31494930433f7fda5d2def43a64d170b2f9bc7a5..dcaeeeb8aac70f90aa0ba0d48e5e9801a65be0cc 100644 (file)
@@ -286,10 +286,8 @@ static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe,
 static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe,
                                         struct clk *m_ck, struct clk *b_ck)
 {
-       if (m_ck)
-               clk_disable_unprepare(m_ck);
-       if (b_ck)
-               clk_disable_unprepare(b_ck);
+       clk_disable_unprepare(m_ck);
+       clk_disable_unprepare(b_ck);
 }
 
 static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
index 70bf312e855f672e7e14b6a387fee25d06889b1c..8794720cea3a0a1ec4bcbaa094c05ee1d9cb4f5f 100644 (file)
@@ -256,14 +256,16 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
        if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
                dev_err(&pdev->dev,
                        "Property 'audio-codec' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_node;
        }
        mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
                of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
        if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
                dev_err(&pdev->dev,
                        "Property 'audio-codec' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_node;
        }
        mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =
                mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
@@ -276,13 +278,15 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
        if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
                dev_err(&pdev->dev,
                        "Property 'audio-codec' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_node;
        }
 
        card->dev = &pdev->dev;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
 
+put_node:
        of_node_put(platform_node);
        return ret;
 }
index d1c94acb451691c82fe227955ba267f388362172..e05f2b0231fe857daf9ae5f630c563ecf7d485ef 100644 (file)
@@ -280,7 +280,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
        if (!mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
                dev_err(&pdev->dev,
                        "Property 'audio-codec' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_platform_node;
        }
        mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
                mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node;
@@ -293,7 +294,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "%s codec_capture_dai name fail %d\n",
                                __func__, ret);
-                       return ret;
+                       goto put_platform_node;
                }
                mt8173_rt5650_dais[DAI_LINK_CODEC_I2S].codecs[1].dai_name =
                        codec_capture_dai;
@@ -315,12 +316,14 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
        if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
                dev_err(&pdev->dev,
                        "Property 'audio-codec' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_platform_node;
        }
        card->dev = &pdev->dev;
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
 
+put_platform_node:
        of_node_put(platform_node);
        return ret;
 }
diff --git a/sound/soc/mediatek/mt8186/Makefile b/sound/soc/mediatek/mt8186/Makefile
new file mode 100644 (file)
index 0000000..49b0026
--- /dev/null
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt8186-afe-objs := \
+       mt8186-afe-pcm.o \
+       mt8186-audsys-clk.o \
+       mt8186-afe-clk.o \
+       mt8186-afe-gpio.o \
+       mt8186-dai-adda.o \
+       mt8186-afe-control.o \
+       mt8186-dai-i2s.o \
+       mt8186-dai-hw-gain.o \
+       mt8186-dai-pcm.o \
+       mt8186-dai-src.o \
+       mt8186-dai-hostless.o \
+       mt8186-dai-tdm.o \
+       mt8186-misc-control.o \
+       mt8186-mt6366-common.o
+
+obj-$(CONFIG_SND_SOC_MT8186) += snd-soc-mt8186-afe.o
+obj-$(CONFIG_SND_SOC_MT8186_MT6366_DA7219_MAX98357) += mt8186-mt6366-da7219-max98357.o
+obj-$(CONFIG_SND_SOC_MT8186_MT6366_RT1019_RT5682S) += mt8186-mt6366-rt1019-rt5682s.o
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
new file mode 100644 (file)
index 0000000..a6b4f29
--- /dev/null
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-afe-clk.c  --  Mediatek 8186 afe clock ctrl
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-clk.h"
+#include "mt8186-audsys-clk.h"
+
+static DEFINE_MUTEX(mutex_request_dram);
+
+static const char *aud_clks[CLK_NUM] = {
+       [CLK_AFE] = "aud_afe_clk",
+       [CLK_DAC] = "aud_dac_clk",
+       [CLK_DAC_PREDIS] = "aud_dac_predis_clk",
+       [CLK_ADC] = "aud_adc_clk",
+       [CLK_TML] = "aud_tml_clk",
+       [CLK_APLL22M] = "aud_apll22m_clk",
+       [CLK_APLL24M] = "aud_apll24m_clk",
+       [CLK_APLL1_TUNER] = "aud_apll_tuner_clk",
+       [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk",
+       [CLK_TDM] = "aud_tdm_clk",
+       [CLK_NLE] = "aud_nle_clk",
+       [CLK_DAC_HIRES] = "aud_dac_hires_clk",
+       [CLK_ADC_HIRES] = "aud_adc_hires_clk",
+       [CLK_I2S1_BCLK] = "aud_i2s1_bclk",
+       [CLK_I2S2_BCLK] = "aud_i2s2_bclk",
+       [CLK_I2S3_BCLK] = "aud_i2s3_bclk",
+       [CLK_I2S4_BCLK] = "aud_i2s4_bclk",
+       [CLK_CONNSYS_I2S_ASRC] = "aud_connsys_i2s_asrc",
+       [CLK_GENERAL1_ASRC] = "aud_general1_asrc",
+       [CLK_GENERAL2_ASRC] = "aud_general2_asrc",
+       [CLK_ADC_HIRES_TML] = "aud_adc_hires_tml",
+       [CLK_ADDA6_ADC] = "aud_adda6_adc",
+       [CLK_ADDA6_ADC_HIRES] = "aud_adda6_adc_hires",
+       [CLK_3RD_DAC] = "aud_3rd_dac",
+       [CLK_3RD_DAC_PREDIS] = "aud_3rd_dac_predis",
+       [CLK_3RD_DAC_TML] = "aud_3rd_dac_tml",
+       [CLK_3RD_DAC_HIRES] = "aud_3rd_dac_hires",
+       [CLK_ETDM_IN1_BCLK] = "aud_etdm_in1_bclk",
+       [CLK_ETDM_OUT1_BCLK] = "aud_etdm_out1_bclk",
+       [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk",
+       [CLK_INFRA_AUDIO_26M] = "mtkaif_26m_clk",
+       [CLK_MUX_AUDIO] = "top_mux_audio",
+       [CLK_MUX_AUDIOINTBUS] = "top_mux_audio_int",
+       [CLK_TOP_MAINPLL_D2_D4] = "top_mainpll_d2_d4",
+       [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1",
+       [CLK_TOP_APLL1_CK] = "top_apll1_ck",
+       [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2",
+       [CLK_TOP_APLL2_CK] = "top_apll2_ck",
+       [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1",
+       [CLK_TOP_APLL1_D8] = "top_apll1_d8",
+       [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2",
+       [CLK_TOP_APLL2_D8] = "top_apll2_d8",
+       [CLK_TOP_MUX_AUDIO_H] = "top_mux_audio_h",
+       [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel",
+       [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel",
+       [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel",
+       [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel",
+       [CLK_TOP_TDM_M_SEL] = "top_tdm_m_sel",
+       [CLK_TOP_APLL12_DIV0] = "top_apll12_div0",
+       [CLK_TOP_APLL12_DIV1] = "top_apll12_div1",
+       [CLK_TOP_APLL12_DIV2] = "top_apll12_div2",
+       [CLK_TOP_APLL12_DIV4] = "top_apll12_div4",
+       [CLK_TOP_APLL12_DIV_TDM] = "top_apll12_div_tdm",
+       [CLK_CLK26M] = "top_clk26m_clk",
+};
+
+int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe,
+                                   int clk_id)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS],
+                            afe_priv->clk[clk_id]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIOINTBUS],
+                       aud_clks[clk_id], ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       if (enable) {
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret);
+                       return ret;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+                                    afe_priv->clk[CLK_TOP_APLL1_CK]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+                               aud_clks[CLK_TOP_APLL1_CK], ret);
+                       return ret;
+               }
+
+               /* 180.6336 / 8 = 22.5792MHz */
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret);
+                       return ret;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+                                    afe_priv->clk[CLK_TOP_APLL1_D8]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+                               aud_clks[CLK_TOP_APLL1_D8], ret);
+                       return ret;
+               }
+       } else {
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1],
+                               aud_clks[CLK_CLK26M], ret);
+                       return ret;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]);
+
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_1],
+                               aud_clks[CLK_CLK26M], ret);
+                       return ret;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]);
+       }
+
+       return 0;
+}
+
+static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       if (enable) {
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret);
+                       return ret;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+                                    afe_priv->clk[CLK_TOP_APLL2_CK]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+                               aud_clks[CLK_TOP_APLL2_CK], ret);
+                       return ret;
+               }
+
+               /* 196.608 / 8 = 24.576MHz */
+               ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret);
+                       return ret;
+               }
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+                                    afe_priv->clk[CLK_TOP_APLL2_D8]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+                               aud_clks[CLK_TOP_APLL2_D8], ret);
+                       return ret;
+               }
+       } else {
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2],
+                               aud_clks[CLK_CLK26M], ret);
+                       return ret;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]);
+
+               ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2],
+                                    afe_priv->clk[CLK_CLK26M]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[CLK_TOP_MUX_AUD_2],
+                               aud_clks[CLK_CLK26M], ret);
+                       return ret;
+               }
+               clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]);
+       }
+
+       return 0;
+}
+
+int mt8186_afe_enable_cgs(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret = 0;
+       int i;
+
+       for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++) {
+               ret = clk_prepare_enable(afe_priv->clk[i]);
+               if (ret) {
+                       dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[i], ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+void mt8186_afe_disable_cgs(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int i;
+
+       for (i = CLK_I2S1_BCLK; i <= CLK_ETDM_OUT1_BCLK; i++)
+               clk_disable_unprepare(afe_priv->clk[i]);
+}
+
+int mt8186_afe_enable_clock(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret = 0;
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret);
+               goto clk_infra_sys_audio_err;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_INFRA_AUDIO_26M], ret);
+               goto clk_infra_audio_26m_err;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIO], ret);
+               goto clk_mux_audio_err;
+       }
+       ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO],
+                            afe_priv->clk[CLK_CLK26M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIO],
+                       aud_clks[CLK_CLK26M], ret);
+               goto clk_mux_audio_err;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+               goto clk_mux_audio_intbus_err;
+       }
+       ret = mt8186_set_audio_int_bus_parent(afe,
+                                             CLK_TOP_MAINPLL_D2_D4);
+       if (ret)
+               goto clk_mux_audio_intbus_parent_err;
+
+       ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUDIO_H],
+                            afe_priv->clk[CLK_TOP_APLL2_CK]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+                       __func__, aud_clks[CLK_TOP_MUX_AUDIO_H],
+                       aud_clks[CLK_TOP_APLL2_CK], ret);
+               goto clk_mux_audio_h_parent_err;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_AFE], ret);
+               goto clk_afe_err;
+       }
+
+       return 0;
+
+clk_afe_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+clk_mux_audio_h_parent_err:
+clk_mux_audio_intbus_parent_err:
+       mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+clk_mux_audio_intbus_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+clk_mux_audio_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+clk_infra_sys_audio_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+clk_infra_audio_26m_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+
+       return ret;
+}
+
+void mt8186_afe_disable_clock(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       clk_disable_unprepare(afe_priv->clk[CLK_AFE]);
+       mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]);
+       clk_disable_unprepare(afe_priv->clk[CLK_INFRA_AUDIO_26M]);
+       clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
+}
+
+int mt8186_afe_suspend_clock(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       /* set audio int bus to 26M */
+       ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       if (ret) {
+               dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                        __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+               goto clk_mux_audio_intbus_err;
+       }
+       ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+       if (ret)
+               goto clk_mux_audio_intbus_parent_err;
+
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+
+       return 0;
+
+clk_mux_audio_intbus_parent_err:
+       mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4);
+clk_mux_audio_intbus_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       return ret;
+}
+
+int mt8186_afe_resume_clock(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       /* set audio int bus to normal working clock */
+       ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       if (ret) {
+               dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                        __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
+               goto clk_mux_audio_intbus_err;
+       }
+       ret = mt8186_set_audio_int_bus_parent(afe,
+                                             CLK_TOP_MAINPLL_D2_D4);
+       if (ret)
+               goto clk_mux_audio_intbus_parent_err;
+
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+
+       return 0;
+
+clk_mux_audio_intbus_parent_err:
+       mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
+clk_mux_audio_intbus_err:
+       clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
+       return ret;
+}
+
+int mt8186_apll1_enable(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       /* setting for APLL */
+       apll1_mux_setting(afe, true);
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL22M], ret);
+               goto err_clk_apll22m;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL1_TUNER], ret);
+               goto err_clk_apll1_tuner;
+       }
+
+       regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0xfff7, 0x832);
+       regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1);
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_22M_ON_MASK_SFT, BIT(AFE_22M_ON_SFT));
+
+       return 0;
+
+err_clk_apll1_tuner:
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+err_clk_apll22m:
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+
+       return ret;
+}
+
+void mt8186_apll1_disable(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_22M_ON_MASK_SFT, 0);
+
+       regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0);
+
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]);
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]);
+
+       apll1_mux_setting(afe, false);
+}
+
+int mt8186_apll2_enable(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       /* setting for APLL */
+       apll2_mux_setting(afe, true);
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL24M], ret);
+               goto err_clk_apll24m;
+       }
+
+       ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]);
+       if (ret) {
+               dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[CLK_APLL2_TUNER], ret);
+               goto err_clk_apll2_tuner;
+       }
+
+       regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0xfff7, 0x634);
+       regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1);
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_24M_ON_MASK_SFT, BIT(AFE_24M_ON_SFT));
+
+       return 0;
+
+err_clk_apll2_tuner:
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+err_clk_apll24m:
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+
+       return ret;
+}
+
+void mt8186_apll2_disable(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE,
+                          AFE_24M_ON_MASK_SFT, 0);
+
+       regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0);
+
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]);
+       clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]);
+
+       apll2_mux_setting(afe, false);
+}
+
+int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll)
+{
+       return (apll == MT8186_APLL1) ? 180633600 : 196608000;
+}
+
+int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
+{
+       return ((rate % 8000) == 0) ? MT8186_APLL2 : MT8186_APLL1;
+}
+
+int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
+{
+       if (strcmp(name, APLL1_W_NAME) == 0)
+               return MT8186_APLL1;
+
+       return MT8186_APLL2;
+}
+
+/* mck */
+struct mt8186_mck_div {
+       u32 m_sel_id;
+       u32 div_clk_id;
+};
+
+static const struct mt8186_mck_div mck_div[MT8186_MCK_NUM] = {
+       [MT8186_I2S0_MCK] = {
+               .m_sel_id = CLK_TOP_I2S0_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV0,
+       },
+       [MT8186_I2S1_MCK] = {
+               .m_sel_id = CLK_TOP_I2S1_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV1,
+       },
+       [MT8186_I2S2_MCK] = {
+               .m_sel_id = CLK_TOP_I2S2_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV2,
+       },
+       [MT8186_I2S4_MCK] = {
+               .m_sel_id = CLK_TOP_I2S4_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV4,
+       },
+       [MT8186_TDM_MCK] = {
+               .m_sel_id = CLK_TOP_TDM_M_SEL,
+               .div_clk_id = CLK_TOP_APLL12_DIV_TDM,
+       },
+};
+
+int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int apll = mt8186_get_apll_by_rate(afe, rate);
+       int apll_clk_id = apll == MT8186_APLL1 ?
+                         CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2;
+       int m_sel_id = mck_div[mck_id].m_sel_id;
+       int div_clk_id = mck_div[mck_id].div_clk_id;
+       int ret;
+
+       /* select apll */
+       if (m_sel_id >= 0) {
+               ret = clk_prepare_enable(afe_priv->clk[m_sel_id]);
+               if (ret) {
+                       dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+                               __func__, aud_clks[m_sel_id], ret);
+                       return ret;
+               }
+               ret = clk_set_parent(afe_priv->clk[m_sel_id],
+                                    afe_priv->clk[apll_clk_id]);
+               if (ret) {
+                       dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n",
+                               __func__, aud_clks[m_sel_id],
+                               aud_clks[apll_clk_id], ret);
+                       return ret;
+               }
+       }
+
+       /* enable div, set rate */
+       ret = clk_prepare_enable(afe_priv->clk[div_clk_id]);
+       if (ret) {
+               dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
+                       __func__, aud_clks[div_clk_id], ret);
+               return ret;
+       }
+       ret = clk_set_rate(afe_priv->clk[div_clk_id], rate);
+       if (ret) {
+               dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n",
+                       __func__, aud_clks[div_clk_id], rate, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int m_sel_id = mck_div[mck_id].m_sel_id;
+       int div_clk_id = mck_div[mck_id].div_clk_id;
+
+       clk_disable_unprepare(afe_priv->clk[div_clk_id]);
+       if (m_sel_id >= 0)
+               clk_disable_unprepare(afe_priv->clk[m_sel_id]);
+}
+
+int mt8186_init_clock(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct device_node *of_node = afe->dev->of_node;
+       int i = 0;
+
+       mt8186_audsys_clk_register(afe);
+
+       afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
+                                    GFP_KERNEL);
+       if (!afe_priv->clk)
+               return -ENOMEM;
+
+       for (i = 0; i < CLK_NUM; i++) {
+               afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
+               if (IS_ERR(afe_priv->clk[i])) {
+                       dev_err(afe->dev, "%s devm_clk_get %s fail, ret %ld\n",
+                               __func__,
+                               aud_clks[i], PTR_ERR(afe_priv->clk[i]));
+                       afe_priv->clk[i] = NULL;
+               }
+       }
+
+       afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node,
+                                                              "mediatek,apmixedsys");
+       if (IS_ERR(afe_priv->apmixedsys)) {
+               dev_err(afe->dev, "%s() Cannot find apmixedsys controller: %ld\n",
+                       __func__, PTR_ERR(afe_priv->apmixedsys));
+               return PTR_ERR(afe_priv->apmixedsys);
+       }
+
+       afe_priv->topckgen = syscon_regmap_lookup_by_phandle(of_node,
+                                                            "mediatek,topckgen");
+       if (IS_ERR(afe_priv->topckgen)) {
+               dev_err(afe->dev, "%s() Cannot find topckgen controller: %ld\n",
+                       __func__, PTR_ERR(afe_priv->topckgen));
+               return PTR_ERR(afe_priv->topckgen);
+       }
+
+       afe_priv->infracfg = syscon_regmap_lookup_by_phandle(of_node,
+                                                            "mediatek,infracfg");
+       if (IS_ERR(afe_priv->infracfg)) {
+               dev_err(afe->dev, "%s() Cannot find infracfg: %ld\n",
+                       __func__, PTR_ERR(afe_priv->infracfg));
+               return PTR_ERR(afe_priv->infracfg);
+       }
+
+       return 0;
+}
+
+void mt8186_deinit_clock(void *priv)
+{
+       struct mtk_base_afe *afe = priv;
+       mt8186_audsys_clk_unregister(afe);
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h
new file mode 100644 (file)
index 0000000..d598871
--- /dev/null
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-afe-clk.h  --  Mediatek 8186 afe clock ctrl definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_AFE_CLOCK_CTRL_H_
+#define _MT8186_AFE_CLOCK_CTRL_H_
+
+#define PERI_BUS_DCM_CTRL      0x74
+
+/* APLL */
+#define APLL1_W_NAME "APLL1"
+#define APLL2_W_NAME "APLL2"
+enum {
+       MT8186_APLL1 = 0,
+       MT8186_APLL2,
+};
+
+enum {
+       CLK_AFE = 0,
+       CLK_DAC,
+       CLK_DAC_PREDIS,
+       CLK_ADC,
+       CLK_TML,
+       CLK_APLL22M,
+       CLK_APLL24M,
+       CLK_APLL1_TUNER,
+       CLK_APLL2_TUNER,
+       CLK_TDM,
+       CLK_NLE,
+       CLK_DAC_HIRES,
+       CLK_ADC_HIRES,
+       CLK_I2S1_BCLK,
+       CLK_I2S2_BCLK,
+       CLK_I2S3_BCLK,
+       CLK_I2S4_BCLK,
+       CLK_CONNSYS_I2S_ASRC,
+       CLK_GENERAL1_ASRC,
+       CLK_GENERAL2_ASRC,
+       CLK_ADC_HIRES_TML,
+       CLK_ADDA6_ADC,
+       CLK_ADDA6_ADC_HIRES,
+       CLK_3RD_DAC,
+       CLK_3RD_DAC_PREDIS,
+       CLK_3RD_DAC_TML,
+       CLK_3RD_DAC_HIRES,
+       CLK_ETDM_IN1_BCLK,
+       CLK_ETDM_OUT1_BCLK,
+       CLK_INFRA_SYS_AUDIO,
+       CLK_INFRA_AUDIO_26M,
+       CLK_MUX_AUDIO,
+       CLK_MUX_AUDIOINTBUS,
+       CLK_TOP_MAINPLL_D2_D4,
+       /* apll related mux */
+       CLK_TOP_MUX_AUD_1,
+       CLK_TOP_APLL1_CK,
+       CLK_TOP_MUX_AUD_2,
+       CLK_TOP_APLL2_CK,
+       CLK_TOP_MUX_AUD_ENG1,
+       CLK_TOP_APLL1_D8,
+       CLK_TOP_MUX_AUD_ENG2,
+       CLK_TOP_APLL2_D8,
+       CLK_TOP_MUX_AUDIO_H,
+       CLK_TOP_I2S0_M_SEL,
+       CLK_TOP_I2S1_M_SEL,
+       CLK_TOP_I2S2_M_SEL,
+       CLK_TOP_I2S4_M_SEL,
+       CLK_TOP_TDM_M_SEL,
+       CLK_TOP_APLL12_DIV0,
+       CLK_TOP_APLL12_DIV1,
+       CLK_TOP_APLL12_DIV2,
+       CLK_TOP_APLL12_DIV4,
+       CLK_TOP_APLL12_DIV_TDM,
+       CLK_CLK26M,
+       CLK_NUM
+};
+
+struct mtk_base_afe;
+int mt8186_set_audio_int_bus_parent(struct mtk_base_afe *afe, int clk_id);
+int mt8186_init_clock(struct mtk_base_afe *afe);
+void mt8186_deinit_clock(void *priv);
+int mt8186_afe_enable_cgs(struct mtk_base_afe *afe);
+void mt8186_afe_disable_cgs(struct mtk_base_afe *afe);
+int mt8186_afe_enable_clock(struct mtk_base_afe *afe);
+void mt8186_afe_disable_clock(struct mtk_base_afe *afe);
+int mt8186_afe_suspend_clock(struct mtk_base_afe *afe);
+int mt8186_afe_resume_clock(struct mtk_base_afe *afe);
+
+int mt8186_apll1_enable(struct mtk_base_afe *afe);
+void mt8186_apll1_disable(struct mtk_base_afe *afe);
+
+int mt8186_apll2_enable(struct mtk_base_afe *afe);
+void mt8186_apll2_disable(struct mtk_base_afe *afe);
+
+int mt8186_get_apll_rate(struct mtk_base_afe *afe, int apll);
+int mt8186_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
+int mt8186_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
+
+/* these will be replaced by using CCF */
+int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate);
+void mt8186_mck_disable(struct mtk_base_afe *afe, int mck_id);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-common.h b/sound/soc/mediatek/mt8186/mt8186-afe-common.h
new file mode 100644 (file)
index 0000000..b8f03e1
--- /dev/null
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-afe-common.h  --  Mediatek 8186 audio driver definitions
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT_8186_AFE_COMMON_H_
+#define _MT_8186_AFE_COMMON_H_
+#include <sound/soc.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "mt8186-reg.h"
+#include "../common/mtk-base-afe.h"
+
+enum {
+       MT8186_MEMIF_DL1,
+       MT8186_MEMIF_DL12,
+       MT8186_MEMIF_DL2,
+       MT8186_MEMIF_DL3,
+       MT8186_MEMIF_DL4,
+       MT8186_MEMIF_DL5,
+       MT8186_MEMIF_DL6,
+       MT8186_MEMIF_DL7,
+       MT8186_MEMIF_DL8,
+       MT8186_MEMIF_VUL12,
+       MT8186_MEMIF_VUL2,
+       MT8186_MEMIF_VUL3,
+       MT8186_MEMIF_VUL4,
+       MT8186_MEMIF_VUL5,
+       MT8186_MEMIF_VUL6,
+       MT8186_MEMIF_AWB,
+       MT8186_MEMIF_AWB2,
+       MT8186_MEMIF_NUM,
+       MT8186_DAI_ADDA = MT8186_MEMIF_NUM,
+       MT8186_DAI_AP_DMIC,
+       MT8186_DAI_CONNSYS_I2S,
+       MT8186_DAI_I2S_0,
+       MT8186_DAI_I2S_1,
+       MT8186_DAI_I2S_2,
+       MT8186_DAI_I2S_3,
+       MT8186_DAI_HW_GAIN_1,
+       MT8186_DAI_HW_GAIN_2,
+       MT8186_DAI_SRC_1,
+       MT8186_DAI_SRC_2,
+       MT8186_DAI_PCM,
+       MT8186_DAI_TDM_IN,
+       MT8186_DAI_HOSTLESS_LPBK,
+       MT8186_DAI_HOSTLESS_FM,
+       MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO,
+       MT8186_DAI_HOSTLESS_SRC_AAUDIO,
+       MT8186_DAI_HOSTLESS_SRC_1,
+       MT8186_DAI_HOSTLESS_SRC_BARGEIN,
+       MT8186_DAI_HOSTLESS_UL1,
+       MT8186_DAI_HOSTLESS_UL2,
+       MT8186_DAI_HOSTLESS_UL3,
+       MT8186_DAI_HOSTLESS_UL5,
+       MT8186_DAI_HOSTLESS_UL6,
+       MT8186_DAI_NUM,
+};
+
+#define MT8186_RECORD_MEMIF MT8186_MEMIF_VUL12
+#define MT8186_ECHO_REF_MEMIF MT8186_MEMIF_AWB
+#define MT8186_PRIMARY_MEMIF MT8186_MEMIF_DL1
+#define MT8186_FAST_MEMIF MT8186_MEMIF_DL2
+#define MT8186_DEEP_MEMIF MT8186_MEMIF_DL3
+#define MT8186_VOIP_MEMIF MT8186_MEMIF_DL12
+#define MT8186_MMAP_DL_MEMIF MT8186_MEMIF_DL5
+#define MT8186_MMAP_UL_MEMIF MT8186_MEMIF_VUL5
+#define MT8186_BARGEIN_MEMIF MT8186_MEMIF_AWB
+
+enum {
+       MT8186_IRQ_0,
+       MT8186_IRQ_1,
+       MT8186_IRQ_2,
+       MT8186_IRQ_3,
+       MT8186_IRQ_4,
+       MT8186_IRQ_5,
+       MT8186_IRQ_6,
+       MT8186_IRQ_7,
+       MT8186_IRQ_8,
+       MT8186_IRQ_9,
+       MT8186_IRQ_10,
+       MT8186_IRQ_11,
+       MT8186_IRQ_12,
+       MT8186_IRQ_13,
+       MT8186_IRQ_14,
+       MT8186_IRQ_15,
+       MT8186_IRQ_16,
+       MT8186_IRQ_17,
+       MT8186_IRQ_18,
+       MT8186_IRQ_19,
+       MT8186_IRQ_20,
+       MT8186_IRQ_21,
+       MT8186_IRQ_22,
+       MT8186_IRQ_23,
+       MT8186_IRQ_24,
+       MT8186_IRQ_25,
+       MT8186_IRQ_26,
+       MT8186_IRQ_NUM,
+};
+
+enum {
+       MT8186_AFE_IRQ_DIR_MCU = 0,
+       MT8186_AFE_IRQ_DIR_DSP,
+       MT8186_AFE_IRQ_DIR_BOTH,
+};
+
+enum {
+       MTKAIF_PROTOCOL_1 = 0,
+       MTKAIF_PROTOCOL_2,
+       MTKAIF_PROTOCOL_2_CLK_P2,
+};
+
+enum {
+       MTK_AFE_ADDA_DL_GAIN_MUTE = 0,
+       MTK_AFE_ADDA_DL_GAIN_NORMAL = 0xf74f,
+       /* SA suggest apply -0.3db to audio/speech path */
+};
+
+#define MTK_SPK_I2S_0_STR "MTK_SPK_I2S_0"
+#define MTK_SPK_I2S_1_STR "MTK_SPK_I2S_1"
+#define MTK_SPK_I2S_2_STR "MTK_SPK_I2S_2"
+#define MTK_SPK_I2S_3_STR "MTK_SPK_I2S_3"
+
+/* MCLK */
+enum {
+       MT8186_I2S0_MCK = 0,
+       MT8186_I2S1_MCK,
+       MT8186_I2S2_MCK,
+       MT8186_I2S4_MCK,
+       MT8186_TDM_MCK,
+       MT8186_MCK_NUM,
+};
+
+struct snd_pcm_substream;
+struct mtk_base_irq_data;
+struct clk;
+
+struct mt8186_afe_private {
+       struct clk **clk;
+       struct clk_lookup **lookup;
+       struct regmap *topckgen;
+       struct regmap *apmixedsys;
+       struct regmap *infracfg;
+       int irq_cnt[MT8186_MEMIF_NUM];
+       int stf_positive_gain_db;
+       int pm_runtime_bypass_reg_ctl;
+       int sgen_mode;
+       int sgen_rate;
+       int sgen_amplitude;
+
+       /* xrun assert */
+       int xrun_assert[MT8186_MEMIF_NUM];
+
+       /* dai */
+       bool dai_on[MT8186_DAI_NUM];
+       void *dai_priv[MT8186_DAI_NUM];
+
+       /* adda */
+       bool mtkaif_calibration_ok;
+       int mtkaif_protocol;
+       int mtkaif_chosen_phase[4];
+       int mtkaif_phase_cycle[4];
+       int mtkaif_calibration_num_phase;
+       int mtkaif_dmic;
+       int mtkaif_looback0;
+       int mtkaif_looback1;
+
+       /* mck */
+       int mck_rate[MT8186_MCK_NUM];
+};
+
+int mt8186_dai_adda_register(struct mtk_base_afe *afe);
+int mt8186_dai_i2s_register(struct mtk_base_afe *afe);
+int mt8186_dai_tdm_register(struct mtk_base_afe *afe);
+int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe);
+int mt8186_dai_src_register(struct mtk_base_afe *afe);
+int mt8186_dai_pcm_register(struct mtk_base_afe *afe);
+int mt8186_dai_hostless_register(struct mtk_base_afe *afe);
+
+int mt8186_add_misc_control(struct snd_soc_component *component);
+
+unsigned int mt8186_general_rate_transform(struct device *dev,
+                                          unsigned int rate);
+unsigned int mt8186_rate_transform(struct device *dev,
+                                  unsigned int rate, int aud_blk);
+unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev,
+                                              unsigned int rate);
+
+int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id,
+                       int priv_size, const void *priv_data);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-control.c b/sound/soc/mediatek/mt8186/mt8186-afe-control.c
new file mode 100644 (file)
index 0000000..d714e96
--- /dev/null
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include "mt8186-afe-common.h"
+#include <linux/pm_runtime.h>
+
+enum {
+       MTK_AFE_RATE_8K = 0,
+       MTK_AFE_RATE_11K,
+       MTK_AFE_RATE_12K,
+       MTK_AFE_RATE_384K,
+       MTK_AFE_RATE_16K,
+       MTK_AFE_RATE_22K,
+       MTK_AFE_RATE_24K,
+       MTK_AFE_RATE_352K,
+       MTK_AFE_RATE_32K,
+       MTK_AFE_RATE_44K,
+       MTK_AFE_RATE_48K,
+       MTK_AFE_RATE_88K,
+       MTK_AFE_RATE_96K,
+       MTK_AFE_RATE_176K,
+       MTK_AFE_RATE_192K,
+       MTK_AFE_RATE_260K,
+};
+
+enum {
+       MTK_AFE_PCM_RATE_8K = 0,
+       MTK_AFE_PCM_RATE_16K,
+       MTK_AFE_PCM_RATE_32K,
+       MTK_AFE_PCM_RATE_48K,
+};
+
+enum {
+       MTK_AFE_TDM_RATE_8K = 0,
+       MTK_AFE_TDM_RATE_12K,
+       MTK_AFE_TDM_RATE_16K,
+       MTK_AFE_TDM_RATE_24K,
+       MTK_AFE_TDM_RATE_32K,
+       MTK_AFE_TDM_RATE_48K,
+       MTK_AFE_TDM_RATE_64K,
+       MTK_AFE_TDM_RATE_96K,
+       MTK_AFE_TDM_RATE_128K,
+       MTK_AFE_TDM_RATE_192K,
+       MTK_AFE_TDM_RATE_256K,
+       MTK_AFE_TDM_RATE_384K,
+       MTK_AFE_TDM_RATE_11K,
+       MTK_AFE_TDM_RATE_22K,
+       MTK_AFE_TDM_RATE_44K,
+       MTK_AFE_TDM_RATE_88K,
+       MTK_AFE_TDM_RATE_176K,
+       MTK_AFE_TDM_RATE_352K,
+};
+
+enum {
+       MTK_AFE_TDM_RELATCH_RATE_8K = 0,
+       MTK_AFE_TDM_RELATCH_RATE_11K,
+       MTK_AFE_TDM_RELATCH_RATE_12K,
+       MTK_AFE_TDM_RELATCH_RATE_16K,
+       MTK_AFE_TDM_RELATCH_RATE_22K,
+       MTK_AFE_TDM_RELATCH_RATE_24K,
+       MTK_AFE_TDM_RELATCH_RATE_32K,
+       MTK_AFE_TDM_RELATCH_RATE_44K,
+       MTK_AFE_TDM_RELATCH_RATE_48K,
+       MTK_AFE_TDM_RELATCH_RATE_88K,
+       MTK_AFE_TDM_RELATCH_RATE_96K,
+       MTK_AFE_TDM_RELATCH_RATE_176K,
+       MTK_AFE_TDM_RELATCH_RATE_192K,
+       MTK_AFE_TDM_RELATCH_RATE_352K,
+       MTK_AFE_TDM_RELATCH_RATE_384K,
+};
+
+unsigned int mt8186_general_rate_transform(struct device *dev, unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_RATE_8K;
+       case 11025:
+               return MTK_AFE_RATE_11K;
+       case 12000:
+               return MTK_AFE_RATE_12K;
+       case 16000:
+               return MTK_AFE_RATE_16K;
+       case 22050:
+               return MTK_AFE_RATE_22K;
+       case 24000:
+               return MTK_AFE_RATE_24K;
+       case 32000:
+               return MTK_AFE_RATE_32K;
+       case 44100:
+               return MTK_AFE_RATE_44K;
+       case 48000:
+               return MTK_AFE_RATE_48K;
+       case 88200:
+               return MTK_AFE_RATE_88K;
+       case 96000:
+               return MTK_AFE_RATE_96K;
+       case 176400:
+               return MTK_AFE_RATE_176K;
+       case 192000:
+               return MTK_AFE_RATE_192K;
+       case 260000:
+               return MTK_AFE_RATE_260K;
+       case 352800:
+               return MTK_AFE_RATE_352K;
+       case 384000:
+               return MTK_AFE_RATE_384K;
+       default:
+               dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
+                       __func__, rate, MTK_AFE_RATE_48K);
+       }
+
+       return MTK_AFE_RATE_48K;
+}
+
+static unsigned int tdm_rate_transform(struct device *dev, unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_TDM_RATE_8K;
+       case 11025:
+               return MTK_AFE_TDM_RATE_11K;
+       case 12000:
+               return MTK_AFE_TDM_RATE_12K;
+       case 16000:
+               return MTK_AFE_TDM_RATE_16K;
+       case 22050:
+               return MTK_AFE_TDM_RATE_22K;
+       case 24000:
+               return MTK_AFE_TDM_RATE_24K;
+       case 32000:
+               return MTK_AFE_TDM_RATE_32K;
+       case 44100:
+               return MTK_AFE_TDM_RATE_44K;
+       case 48000:
+               return MTK_AFE_TDM_RATE_48K;
+       case 64000:
+               return MTK_AFE_TDM_RATE_64K;
+       case 88200:
+               return MTK_AFE_TDM_RATE_88K;
+       case 96000:
+               return MTK_AFE_TDM_RATE_96K;
+       case 128000:
+               return MTK_AFE_TDM_RATE_128K;
+       case 176400:
+               return MTK_AFE_TDM_RATE_176K;
+       case 192000:
+               return MTK_AFE_TDM_RATE_192K;
+       case 256000:
+               return MTK_AFE_TDM_RATE_256K;
+       case 352800:
+               return MTK_AFE_TDM_RATE_352K;
+       case 384000:
+               return MTK_AFE_TDM_RATE_384K;
+       default:
+               dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
+                       __func__, rate, MTK_AFE_TDM_RATE_48K);
+       }
+
+       return MTK_AFE_TDM_RATE_48K;
+}
+
+static unsigned int pcm_rate_transform(struct device *dev, unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_PCM_RATE_8K;
+       case 16000:
+               return MTK_AFE_PCM_RATE_16K;
+       case 32000:
+               return MTK_AFE_PCM_RATE_32K;
+       case 48000:
+               return MTK_AFE_PCM_RATE_48K;
+       default:
+               dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
+                       __func__, rate, MTK_AFE_PCM_RATE_48K);
+       }
+
+       return MTK_AFE_PCM_RATE_48K;
+}
+
+unsigned int mt8186_tdm_relatch_rate_transform(struct device *dev, unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_TDM_RELATCH_RATE_8K;
+       case 11025:
+               return MTK_AFE_TDM_RELATCH_RATE_11K;
+       case 12000:
+               return MTK_AFE_TDM_RELATCH_RATE_12K;
+       case 16000:
+               return MTK_AFE_TDM_RELATCH_RATE_16K;
+       case 22050:
+               return MTK_AFE_TDM_RELATCH_RATE_22K;
+       case 24000:
+               return MTK_AFE_TDM_RELATCH_RATE_24K;
+       case 32000:
+               return MTK_AFE_TDM_RELATCH_RATE_32K;
+       case 44100:
+               return MTK_AFE_TDM_RELATCH_RATE_44K;
+       case 48000:
+               return MTK_AFE_TDM_RELATCH_RATE_48K;
+       case 88200:
+               return MTK_AFE_TDM_RELATCH_RATE_88K;
+       case 96000:
+               return MTK_AFE_TDM_RELATCH_RATE_96K;
+       case 176400:
+               return MTK_AFE_TDM_RELATCH_RATE_176K;
+       case 192000:
+               return MTK_AFE_TDM_RELATCH_RATE_192K;
+       case 352800:
+               return MTK_AFE_TDM_RELATCH_RATE_352K;
+       case 384000:
+               return MTK_AFE_TDM_RELATCH_RATE_384K;
+       default:
+               dev_err(dev, "%s(), rate %u invalid, use %d!!!\n",
+                       __func__, rate, MTK_AFE_TDM_RELATCH_RATE_48K);
+       }
+
+       return MTK_AFE_TDM_RELATCH_RATE_48K;
+}
+
+unsigned int mt8186_rate_transform(struct device *dev, unsigned int rate, int aud_blk)
+{
+       switch (aud_blk) {
+       case MT8186_DAI_PCM:
+               return pcm_rate_transform(dev, rate);
+       case MT8186_DAI_TDM_IN:
+               return tdm_rate_transform(dev, rate);
+       default:
+               return mt8186_general_rate_transform(dev, rate);
+       }
+}
+
+int mt8186_dai_set_priv(struct mtk_base_afe *afe, int id, int priv_size, const void *priv_data)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       void *temp_data;
+
+       temp_data = devm_kzalloc(afe->dev,
+                                priv_size,
+                                GFP_KERNEL);
+       if (!temp_data)
+               return -ENOMEM;
+
+       if (priv_data)
+               memcpy(temp_data, priv_data, priv_size);
+
+       afe_priv->dai_priv[id] = temp_data;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.c
new file mode 100644 (file)
index 0000000..274c0c8
--- /dev/null
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-afe-gpio.c  --  Mediatek 8186 afe gpio ctrl
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+
+struct pinctrl *aud_pinctrl;
+
+enum mt8186_afe_gpio {
+       MT8186_AFE_GPIO_CLK_MOSI_OFF,
+       MT8186_AFE_GPIO_CLK_MOSI_ON,
+       MT8186_AFE_GPIO_CLK_MISO_OFF,
+       MT8186_AFE_GPIO_CLK_MISO_ON,
+       MT8186_AFE_GPIO_DAT_MISO_OFF,
+       MT8186_AFE_GPIO_DAT_MISO_ON,
+       MT8186_AFE_GPIO_DAT_MOSI_OFF,
+       MT8186_AFE_GPIO_DAT_MOSI_ON,
+       MT8186_AFE_GPIO_I2S0_OFF,
+       MT8186_AFE_GPIO_I2S0_ON,
+       MT8186_AFE_GPIO_I2S1_OFF,
+       MT8186_AFE_GPIO_I2S1_ON,
+       MT8186_AFE_GPIO_I2S2_OFF,
+       MT8186_AFE_GPIO_I2S2_ON,
+       MT8186_AFE_GPIO_I2S3_OFF,
+       MT8186_AFE_GPIO_I2S3_ON,
+       MT8186_AFE_GPIO_TDM_OFF,
+       MT8186_AFE_GPIO_TDM_ON,
+       MT8186_AFE_GPIO_PCM_OFF,
+       MT8186_AFE_GPIO_PCM_ON,
+       MT8186_AFE_GPIO_GPIO_NUM
+};
+
+struct audio_gpio_attr {
+       const char *name;
+       bool gpio_prepare;
+       struct pinctrl_state *gpioctrl;
+};
+
+static struct audio_gpio_attr aud_gpios[MT8186_AFE_GPIO_GPIO_NUM] = {
+       [MT8186_AFE_GPIO_CLK_MOSI_OFF] = {"aud_clk_mosi_off", false, NULL},
+       [MT8186_AFE_GPIO_CLK_MOSI_ON] = {"aud_clk_mosi_on", false, NULL},
+       [MT8186_AFE_GPIO_CLK_MISO_OFF] = {"aud_clk_miso_off", false, NULL},
+       [MT8186_AFE_GPIO_CLK_MISO_ON] = {"aud_clk_miso_on", false, NULL},
+       [MT8186_AFE_GPIO_DAT_MISO_OFF] = {"aud_dat_miso_off", false, NULL},
+       [MT8186_AFE_GPIO_DAT_MISO_ON] = {"aud_dat_miso_on", false, NULL},
+       [MT8186_AFE_GPIO_DAT_MOSI_OFF] = {"aud_dat_mosi_off", false, NULL},
+       [MT8186_AFE_GPIO_DAT_MOSI_ON] = {"aud_dat_mosi_on", false, NULL},
+       [MT8186_AFE_GPIO_I2S0_OFF] = {"aud_gpio_i2s0_off", false, NULL},
+       [MT8186_AFE_GPIO_I2S0_ON] = {"aud_gpio_i2s0_on", false, NULL},
+       [MT8186_AFE_GPIO_I2S1_OFF] = {"aud_gpio_i2s1_off", false, NULL},
+       [MT8186_AFE_GPIO_I2S1_ON] = {"aud_gpio_i2s1_on", false, NULL},
+       [MT8186_AFE_GPIO_I2S2_OFF] = {"aud_gpio_i2s2_off", false, NULL},
+       [MT8186_AFE_GPIO_I2S2_ON] = {"aud_gpio_i2s2_on", false, NULL},
+       [MT8186_AFE_GPIO_I2S3_OFF] = {"aud_gpio_i2s3_off", false, NULL},
+       [MT8186_AFE_GPIO_I2S3_ON] = {"aud_gpio_i2s3_on", false, NULL},
+       [MT8186_AFE_GPIO_TDM_OFF] = {"aud_gpio_tdm_off", false, NULL},
+       [MT8186_AFE_GPIO_TDM_ON] = {"aud_gpio_tdm_on", false, NULL},
+       [MT8186_AFE_GPIO_PCM_OFF] = {"aud_gpio_pcm_off", false, NULL},
+       [MT8186_AFE_GPIO_PCM_ON] = {"aud_gpio_pcm_on", false, NULL},
+};
+
+static DEFINE_MUTEX(gpio_request_mutex);
+
+int mt8186_afe_gpio_init(struct device *dev)
+{
+       int i, j, ret;
+
+       aud_pinctrl = devm_pinctrl_get(dev);
+       if (IS_ERR(aud_pinctrl)) {
+               ret = PTR_ERR(aud_pinctrl);
+               dev_err(dev, "%s(), ret %d, cannot get aud_pinctrl!\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(aud_gpios); i++) {
+               aud_gpios[i].gpioctrl = pinctrl_lookup_state(aud_pinctrl,
+                                                            aud_gpios[i].name);
+               if (IS_ERR(aud_gpios[i].gpioctrl)) {
+                       ret = PTR_ERR(aud_gpios[i].gpioctrl);
+                       dev_info(dev, "%s(), pinctrl_lookup_state %s fail, ret %d\n",
+                                __func__, aud_gpios[i].name, ret);
+               } else {
+                       aud_gpios[i].gpio_prepare = true;
+               }
+       }
+
+       /* gpio status init */
+       for (i = MT8186_DAI_ADDA; i <= MT8186_DAI_TDM_IN; i++) {
+               for (j = 0; j <= 1; j++)
+                       mt8186_afe_gpio_request(dev, false, i, j);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mt8186_afe_gpio_init);
+
+static int mt8186_afe_gpio_select(struct device *dev,
+                                 enum mt8186_afe_gpio type)
+{
+       int ret = 0;
+
+       if (type < 0 || type >= MT8186_AFE_GPIO_GPIO_NUM) {
+               dev_err(dev, "%s(), error, invalid gpio type %d\n",
+                       __func__, type);
+               return -EINVAL;
+       }
+
+       if (!aud_gpios[type].gpio_prepare) {
+               dev_err(dev, "%s(), error, gpio type %d not prepared\n",
+                       __func__, type);
+               return -EIO;
+       }
+
+       ret = pinctrl_select_state(aud_pinctrl,
+                                  aud_gpios[type].gpioctrl);
+       if (ret) {
+               dev_err(dev, "%s(), error, can not set gpio type %d\n",
+                       __func__, type);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mt8186_afe_gpio_adda_dl(struct device *dev, bool enable)
+{
+       int ret;
+
+       if (enable) {
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_ON);
+               if (ret) {
+                       dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
+                       return ret;
+               }
+
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_ON);
+               if (ret) {
+                       dev_err(dev, "%s(), MOSI DAT ON select fail!\n", __func__);
+                       return ret;
+               }
+       } else {
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MOSI_OFF);
+               if (ret) {
+                       dev_err(dev, "%s(), MOSI DAT OFF select fail!\n", __func__);
+                       return ret;
+               }
+
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MOSI_OFF);
+               if (ret) {
+                       dev_err(dev, "%s(), MOSI CLK ON select fail!\n", __func__);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int mt8186_afe_gpio_adda_ul(struct device *dev, bool enable)
+{
+       int ret;
+
+       if (enable) {
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_ON);
+               if (ret) {
+                       dev_err(dev, "%s(), MISO CLK ON slect fail!\n", __func__);
+                       return ret;
+               }
+
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_ON);
+               if (ret) {
+                       dev_err(dev, "%s(), MISO DAT ON slect fail!\n", __func__);
+                       return ret;
+               }
+       } else {
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_DAT_MISO_OFF);
+               if (ret) {
+                       dev_err(dev, "%s(), MISO DAT OFF slect fail!\n", __func__);
+                       return ret;
+               }
+
+               ret = mt8186_afe_gpio_select(dev, MT8186_AFE_GPIO_CLK_MISO_OFF);
+               if (ret) {
+                       dev_err(dev, "%s(), MISO CLK OFF slect fail!\n", __func__);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+int mt8186_afe_gpio_request(struct device *dev, bool enable,
+                           int dai, int uplink)
+{
+       enum mt8186_afe_gpio sel;
+       int ret = -EINVAL;
+
+       mutex_lock(&gpio_request_mutex);
+
+       switch (dai) {
+       case MT8186_DAI_ADDA:
+               if (uplink)
+                       ret = mt8186_afe_gpio_adda_ul(dev, enable);
+               else
+                       ret = mt8186_afe_gpio_adda_dl(dev, enable);
+               goto unlock;
+       case MT8186_DAI_I2S_0:
+               sel = enable ? MT8186_AFE_GPIO_I2S0_ON : MT8186_AFE_GPIO_I2S0_OFF;
+               break;
+       case MT8186_DAI_I2S_1:
+               sel = enable ? MT8186_AFE_GPIO_I2S1_ON : MT8186_AFE_GPIO_I2S1_OFF;
+               break;
+       case MT8186_DAI_I2S_2:
+               sel = enable ? MT8186_AFE_GPIO_I2S2_ON : MT8186_AFE_GPIO_I2S2_OFF;
+               break;
+       case MT8186_DAI_I2S_3:
+               sel = enable ? MT8186_AFE_GPIO_I2S3_ON : MT8186_AFE_GPIO_I2S3_OFF;
+               break;
+       case MT8186_DAI_TDM_IN:
+               sel = enable ? MT8186_AFE_GPIO_TDM_ON : MT8186_AFE_GPIO_TDM_OFF;
+               break;
+       case MT8186_DAI_PCM:
+               sel = enable ? MT8186_AFE_GPIO_PCM_ON : MT8186_AFE_GPIO_PCM_OFF;
+               break;
+       default:
+               dev_err(dev, "%s(), invalid dai %d\n", __func__, dai);
+               goto unlock;
+       }
+
+       ret = mt8186_afe_gpio_select(dev, sel);
+
+unlock:
+       mutex_unlock(&gpio_request_mutex);
+
+       return ret;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h b/sound/soc/mediatek/mt8186/mt8186-afe-gpio.h
new file mode 100644 (file)
index 0000000..1ddc278
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt6833-afe-gpio.h  --  Mediatek 6833 afe gpio ctrl definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_AFE_GPIO_H_
+#define _MT8186_AFE_GPIO_H_
+
+struct mtk_base_afe;
+
+int mt8186_afe_gpio_init(struct device *dev);
+
+int mt8186_afe_gpio_request(struct device *dev, bool enable,
+                           int dai, int uplink);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
new file mode 100644 (file)
index 0000000..eb729ab
--- /dev/null
@@ -0,0 +1,3000 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek ALSA SoC AFE platform driver for 8186
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <sound/soc.h>
+
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+static const struct snd_pcm_hardware mt8186_afe_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+                   SNDRV_PCM_FMTBIT_S24_LE |
+                   SNDRV_PCM_FMTBIT_S32_LE),
+       .period_bytes_min = 96,
+       .period_bytes_max = 4 * 48 * 1024,
+       .periods_min = 2,
+       .periods_max = 256,
+       .buffer_bytes_max = 4 * 48 * 1024,
+       .fifo_size = 0,
+};
+
+static int mt8186_fe_startup(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+       struct mtk_base_afe_memif *memif = &afe->memif[id];
+       const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
+       int ret;
+
+       memif->substream = substream;
+
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+
+       snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+               return ret;
+       }
+
+       /* dynamic allocate irq to memif */
+       if (memif->irq_usage < 0) {
+               int irq_id = mtk_dynamic_irq_acquire(afe);
+
+               if (irq_id != afe->irqs_size) {
+                       /* link */
+                       memif->irq_usage = irq_id;
+               } else {
+                       dev_err(afe->dev, "%s() error: no more asys irq\n",
+                               __func__);
+                       return -EBUSY;
+               }
+       }
+
+       return 0;
+}
+
+static void mt8186_fe_shutdown(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+       struct mtk_base_afe_memif *memif = &afe->memif[id];
+       int irq_id = memif->irq_usage;
+
+       memif->substream = NULL;
+       afe_priv->irq_cnt[id] = 0;
+       afe_priv->xrun_assert[id] = 0;
+
+       if (!memif->const_irq) {
+               mtk_dynamic_irq_release(afe, irq_id);
+               memif->irq_usage = -1;
+               memif->substream = NULL;
+       }
+}
+
+static int mt8186_fe_hw_params(struct snd_pcm_substream *substream,
+                              struct snd_pcm_hw_params *params,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+       unsigned int channels = params_channels(params);
+       unsigned int rate = params_rate(params);
+       int ret;
+
+       ret = mtk_afe_fe_hw_params(substream, params, dai);
+       if (ret)
+               return ret;
+
+       /* channel merge configuration, enable control is in UL5_IN_MUX */
+       if (id == MT8186_MEMIF_VUL3) {
+               int update_cnt = 8;
+               unsigned int val = 0;
+               unsigned int mask = 0;
+               int fs_mode = mt8186_rate_transform(afe->dev, rate, id);
+
+               /* set rate, channel, update cnt, disable sgen */
+               val = fs_mode << CM1_FS_SELECT_SFT |
+                       (channels - 1) << CHANNEL_MERGE0_CHNUM_SFT |
+                       update_cnt << CHANNEL_MERGE0_UPDATE_CNT_SFT;
+               mask = CM1_FS_SELECT_MASK_SFT |
+                       CHANNEL_MERGE0_CHNUM_MASK_SFT |
+                       CHANNEL_MERGE0_UPDATE_CNT_MASK_SFT;
+               regmap_update_bits(afe->regmap, AFE_CM1_CON, mask, val);
+       }
+
+       return 0;
+}
+
+static int mt8186_fe_hw_free(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       int ret;
+
+       ret = mtk_afe_fe_hw_free(substream, dai);
+       if (ret) {
+               dev_err(afe->dev, "%s failed\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mt8186_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime * const runtime = substream->runtime;
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+       struct mtk_base_afe_memif *memif = &afe->memif[id];
+       int irq_id = memif->irq_usage;
+       struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
+       const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+       unsigned int rate = runtime->rate;
+       unsigned int counter;
+       int fs;
+       int ret;
+
+       dev_dbg(afe->dev, "%s(), %s cmd %d, irq_id %d\n",
+               __func__, memif->data->name, cmd, irq_id);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               ret = mtk_memif_set_enable(afe, id);
+               if (ret) {
+                       dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+                               __func__, id, ret);
+                       return ret;
+               }
+
+               /*
+                * for small latency record
+                * ul memif need read some data before irq enable
+                */
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+                   ((runtime->period_size * 1000) / rate <= 10))
+                       udelay(300);
+
+               /* set irq counter */
+               if (afe_priv->irq_cnt[id] > 0)
+                       counter = afe_priv->irq_cnt[id];
+               else
+                       counter = runtime->period_size;
+
+               regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+                                  irq_data->irq_cnt_maskbit
+                                  << irq_data->irq_cnt_shift,
+                                  counter << irq_data->irq_cnt_shift);
+
+               /* set irq fs */
+               fs = afe->irq_fs(substream, runtime->rate);
+               if (fs < 0)
+                       return -EINVAL;
+
+               regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
+                                  irq_data->irq_fs_maskbit
+                                  << irq_data->irq_fs_shift,
+                                  fs << irq_data->irq_fs_shift);
+
+               /* enable interrupt */
+               if (runtime->stop_threshold != ~(0U))
+                       regmap_update_bits(afe->regmap,
+                                          irq_data->irq_en_reg,
+                                          1 << irq_data->irq_en_shift,
+                                          1 << irq_data->irq_en_shift);
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               if (afe_priv->xrun_assert[id] > 0) {
+                       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                               int avail = snd_pcm_capture_avail(runtime);
+                               /* alsa can trigger stop/start when occur xrun */
+                               if (avail >= runtime->buffer_size)
+                                       dev_dbg(afe->dev, "%s(), id %d, xrun assert\n",
+                                               __func__, id);
+                       }
+               }
+
+               ret = mtk_memif_set_disable(afe, id);
+               if (ret)
+                       dev_err(afe->dev, "%s(), error, id %d, memif enable, ret %d\n",
+                               __func__, id, ret);
+
+               /* disable interrupt */
+               if (runtime->stop_threshold != ~(0U))
+                       regmap_update_bits(afe->regmap,
+                                          irq_data->irq_en_reg,
+                                          1 << irq_data->irq_en_shift,
+                                          0 << irq_data->irq_en_shift);
+
+               /* clear pending IRQ */
+               regmap_write(afe->regmap, irq_data->irq_clr_reg,
+                            1 << irq_data->irq_clr_shift);
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mt8186_memif_fs(struct snd_pcm_substream *substream,
+                          unsigned int rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+
+       return mt8186_rate_transform(afe->dev, rate, id);
+}
+
+static int mt8186_get_dai_fs(struct mtk_base_afe *afe,
+                            int dai_id, unsigned int rate)
+{
+       return mt8186_rate_transform(afe->dev, rate, dai_id);
+}
+
+static int mt8186_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+       return mt8186_general_rate_transform(afe->dev, rate);
+}
+
+static int mt8186_get_memif_pbuf_size(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if ((runtime->period_size * 1000) / runtime->rate > 10)
+               return MT8186_MEMIF_PBUF_SIZE_256_BYTES;
+
+       return MT8186_MEMIF_PBUF_SIZE_32_BYTES;
+}
+
+static int mt8186_fe_prepare(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime * const runtime = substream->runtime;
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       int id = asoc_rtd_to_cpu(rtd, 0)->id;
+       struct mtk_base_afe_memif *memif = &afe->memif[id];
+       int irq_id = memif->irq_usage;
+       struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
+       const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+       unsigned int counter = runtime->period_size;
+       int fs;
+       int ret;
+
+       ret = mtk_afe_fe_prepare(substream, dai);
+       if (ret)
+               return ret;
+
+       /* set irq counter */
+       regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+                          irq_data->irq_cnt_maskbit
+                          << irq_data->irq_cnt_shift,
+                          counter << irq_data->irq_cnt_shift);
+
+       /* set irq fs */
+       fs = afe->irq_fs(substream, runtime->rate);
+
+       if (fs < 0)
+               return -EINVAL;
+
+       regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
+                          irq_data->irq_fs_maskbit
+                          << irq_data->irq_fs_shift,
+                          fs << irq_data->irq_fs_shift);
+
+       return 0;
+}
+
+/* FE DAIs */
+static const struct snd_soc_dai_ops mt8186_memif_dai_ops = {
+       .startup        = mt8186_fe_startup,
+       .shutdown       = mt8186_fe_shutdown,
+       .hw_params      = mt8186_fe_hw_params,
+       .hw_free        = mt8186_fe_hw_free,
+       .prepare        = mt8186_fe_prepare,
+       .trigger        = mt8186_fe_trigger,
+};
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\
+                          SNDRV_PCM_RATE_16000 |\
+                          SNDRV_PCM_RATE_32000 |\
+                          SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt8186_memif_dai_driver[] = {
+       /* FE DAIs: memory intefaces to CPU */
+       {
+               .name = "DL1",
+               .id = MT8186_MEMIF_DL1,
+               .playback = {
+                       .stream_name = "DL1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL12",
+               .id = MT8186_MEMIF_DL12,
+               .playback = {
+                       .stream_name = "DL12",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL2",
+               .id = MT8186_MEMIF_DL2,
+               .playback = {
+                       .stream_name = "DL2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL3",
+               .id = MT8186_MEMIF_DL3,
+               .playback = {
+                       .stream_name = "DL3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL4",
+               .id = MT8186_MEMIF_DL4,
+               .playback = {
+                       .stream_name = "DL4",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL5",
+               .id = MT8186_MEMIF_DL5,
+               .playback = {
+                       .stream_name = "DL5",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL6",
+               .id = MT8186_MEMIF_DL6,
+               .playback = {
+                       .stream_name = "DL6",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL7",
+               .id = MT8186_MEMIF_DL7,
+               .playback = {
+                       .stream_name = "DL7",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "DL8",
+               .id = MT8186_MEMIF_DL8,
+               .playback = {
+                       .stream_name = "DL8",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL1",
+               .id = MT8186_MEMIF_VUL12,
+               .capture = {
+                       .stream_name = "UL1",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL2",
+               .id = MT8186_MEMIF_AWB,
+               .capture = {
+                       .stream_name = "UL2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL3",
+               .id = MT8186_MEMIF_VUL2,
+               .capture = {
+                       .stream_name = "UL3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL4",
+               .id = MT8186_MEMIF_AWB2,
+               .capture = {
+                       .stream_name = "UL4",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL5",
+               .id = MT8186_MEMIF_VUL3,
+               .capture = {
+                       .stream_name = "UL5",
+                       .channels_min = 1,
+                       .channels_max = 12,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL6",
+               .id = MT8186_MEMIF_VUL4,
+               .capture = {
+                       .stream_name = "UL6",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL7",
+               .id = MT8186_MEMIF_VUL5,
+               .capture = {
+                       .stream_name = "UL7",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       },
+       {
+               .name = "UL8",
+               .id = MT8186_MEMIF_VUL6,
+               .capture = {
+                       .stream_name = "UL8",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mt8186_memif_dai_ops,
+       }
+};
+
+/* kcontrol */
+static int mt8186_irq_cnt1_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] =
+               afe_priv->irq_cnt[MT8186_PRIMARY_MEMIF];
+
+       return 0;
+}
+
+static int mt8186_irq_cnt1_set(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int memif_num = MT8186_PRIMARY_MEMIF;
+       struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+       int irq_id = memif->irq_usage;
+       int irq_cnt = afe_priv->irq_cnt[memif_num];
+
+       dev_dbg(afe->dev, "%s(), irq_id %d, irq_cnt = %d, value = %ld\n",
+               __func__, irq_id, irq_cnt, ucontrol->value.integer.value[0]);
+
+       if (irq_cnt == ucontrol->value.integer.value[0])
+               return 0;
+
+       irq_cnt = ucontrol->value.integer.value[0];
+       afe_priv->irq_cnt[memif_num] = irq_cnt;
+
+       if (!pm_runtime_status_suspended(afe->dev) && irq_id >= 0) {
+               struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
+               const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+
+               regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+                                  irq_data->irq_cnt_maskbit
+                                  << irq_data->irq_cnt_shift,
+                                  irq_cnt << irq_data->irq_cnt_shift);
+       } else {
+               dev_dbg(afe->dev, "%s(), suspended || irq_id %d, not set\n",
+                       __func__, irq_id);
+       }
+
+       return 1;
+}
+
+static int mt8186_irq_cnt2_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] =
+               afe_priv->irq_cnt[MT8186_RECORD_MEMIF];
+
+       return 0;
+}
+
+static int mt8186_irq_cnt2_set(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int memif_num = MT8186_RECORD_MEMIF;
+       struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+       int irq_id = memif->irq_usage;
+       int irq_cnt = afe_priv->irq_cnt[memif_num];
+
+       dev_dbg(afe->dev, "%s(), irq_id %d, irq_cnt = %d, value = %ld\n",
+               __func__, irq_id, irq_cnt, ucontrol->value.integer.value[0]);
+
+       if (irq_cnt == ucontrol->value.integer.value[0])
+               return 0;
+
+       irq_cnt = ucontrol->value.integer.value[0];
+       afe_priv->irq_cnt[memif_num] = irq_cnt;
+
+       if (!pm_runtime_status_suspended(afe->dev) && irq_id >= 0) {
+               struct mtk_base_afe_irq *irqs = &afe->irqs[irq_id];
+               const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+
+               regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+                                  irq_data->irq_cnt_maskbit
+                                  << irq_data->irq_cnt_shift,
+                                  irq_cnt << irq_data->irq_cnt_shift);
+       } else {
+               dev_dbg(afe->dev, "%s(), suspended || irq_id %d, not set\n",
+                       __func__, irq_id);
+       }
+
+       return 1;
+}
+
+static int mt8186_record_xrun_assert_get(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int xrun_assert = afe_priv->xrun_assert[MT8186_RECORD_MEMIF];
+
+       ucontrol->value.integer.value[0] = xrun_assert;
+
+       return 0;
+}
+
+static int mt8186_record_xrun_assert_set(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int xrun_assert = ucontrol->value.integer.value[0];
+
+       dev_dbg(afe->dev, "%s(), xrun_assert %d\n", __func__, xrun_assert);
+
+       if (xrun_assert == afe_priv->xrun_assert[MT8186_RECORD_MEMIF])
+               return 0;
+
+       afe_priv->xrun_assert[MT8186_RECORD_MEMIF] = xrun_assert;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new mt8186_pcm_kcontrols[] = {
+       SOC_SINGLE_EXT("Audio IRQ1 CNT", SND_SOC_NOPM, 0, 0x3ffff, 0,
+                      mt8186_irq_cnt1_get, mt8186_irq_cnt1_set),
+       SOC_SINGLE_EXT("Audio IRQ2 CNT", SND_SOC_NOPM, 0, 0x3ffff, 0,
+                      mt8186_irq_cnt2_get, mt8186_irq_cnt2_set),
+       SOC_SINGLE_EXT("record_xrun_assert", SND_SOC_NOPM, 0, 0x1, 0,
+                      mt8186_record_xrun_assert_get,
+                      mt8186_record_xrun_assert_set),
+};
+
+/* dma widget & routes*/
+static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN21,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN21,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN21,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH1 Switch", AFE_CONN21_1,
+                                   I_TDM_IN_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN22,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN22,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN22,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4 Switch", AFE_CONN22,
+                                   I_ADDA_UL_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH2 Switch", AFE_CONN22_1,
+                                   I_TDM_IN_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch3_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN9,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN9,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN9,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH3 Switch", AFE_CONN9_1,
+                                   I_TDM_IN_CH3, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul1_ch4_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN10,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN10,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN10,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH4 Switch", AFE_CONN10,
+                                   I_ADDA_UL_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH4 Switch", AFE_CONN10_1,
+                                   I_TDM_IN_CH4, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN5,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN5,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN5,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN5,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN5,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN5_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN5_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN5_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN5,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN5,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN5_1,
+                                   I_CONNSYS_I2S_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN5_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN6,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN6,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN6,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN6,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN6,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN6_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN6_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN6_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN6,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN6,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN6_1,
+                                   I_CONNSYS_I2S_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN6_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN32_1,
+                                   I_CONNSYS_I2S_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN32,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN32,
+                                   I_DL2_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN33_1,
+                                   I_CONNSYS_I2S_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN38,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN38,
+                                   I_I2S0_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN39,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN39,
+                                   I_I2S0_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN44,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul5_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN45,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN46,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN46,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN46,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN46_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN46,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN46,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN46_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN46,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN46,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul6_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN47,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN47,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN47,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN47_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN47,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN47,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN47_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN47,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN47,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN48,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch", AFE_CONN48,
+                                   I_GAIN2_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH1 Switch", AFE_CONN48_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul7_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN49,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch", AFE_CONN49,
+                                   I_GAIN2_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC_2_OUT_CH2 Switch", AFE_CONN49_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN50,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new memif_ul8_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN51,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH1 Switch", AFE_CONN58_1,
+                                   I_TDM_IN_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN58,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN58,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN58,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN58,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN58,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN58,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN58,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN58,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN58_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN58_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN58_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN58_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH2 Switch", AFE_CONN59_1,
+                                   I_TDM_IN_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN59,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN59,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN59,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN59,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN59,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN59,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN59,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN59,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN59_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN59_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN59_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN59_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch3_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH3 Switch", AFE_CONN60_1,
+                                   I_TDM_IN_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN60,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN60,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN60,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN60,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN60,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN60,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN60,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN60,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN60_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN60_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN60_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN60_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch4_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH4 Switch", AFE_CONN61_1,
+                                   I_TDM_IN_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN61,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN61,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN61,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN61,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN61,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN61,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN61,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN61,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN61_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN61_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN61_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN61_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch5_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH5 Switch", AFE_CONN62_1,
+                                   I_TDM_IN_CH5, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN62,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN62,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN62,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN62,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN62,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN62,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN62,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN62,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN62_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN62_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN62_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN62_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch6_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH6 Switch", AFE_CONN63_1,
+                                   I_TDM_IN_CH6, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN63,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN63,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN63,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN63,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN63,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN63,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN63,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN63,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN63_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN63_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN63_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN63_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch7_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH7 Switch", AFE_CONN64_1,
+                                   I_TDM_IN_CH7, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN64,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN64,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN64,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN64,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1v", AFE_CONN64,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN64,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN64,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN64,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN64_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN64_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN64_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN64_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch8_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("TDM_IN_CH8 Switch", AFE_CONN65_1,
+                                   I_TDM_IN_CH8, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN65,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN65,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN65,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN65,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN65,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN65,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN65,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN65,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN65_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN65_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN65_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN65_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch9_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN66,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN66,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN66,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN66,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN66,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN66,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN66,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN66,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN66_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN66_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN66_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN66_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch10_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN67,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN67,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN67,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN67,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN67,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN67,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN67,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN67,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN67_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN67_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN67_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN67_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch11_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN68,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1 Switch", AFE_CONN68,
+                                   I_I2S2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN68,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN68,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN68,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN68,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN68,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN68,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN68_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN68_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH1 Switch", AFE_CONN68_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH1 Switch", AFE_CONN68_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new hw_cm1_ch12_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN69,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2 Switch", AFE_CONN69,
+                                   I_I2S2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN69,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN69,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN69,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN69,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN69,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN69,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN69_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN69_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC1_OUT_CH2 Switch", AFE_CONN69_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_SRC2_OUT_CH2 Switch", AFE_CONN69_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+/* ADDA UL MUX */
+enum {
+       UL5_IN_MUX_CM1 = 0,
+       UL5_IN_MUX_NORMAL,
+       UL5_IN_MUX_MASK = 0x1,
+};
+
+static const char * const ul5_in_mux_map[] = {
+       "UL5_IN_FROM_CM1", "UL5_IN_FROM_Normal"
+};
+
+static int ul5_in_map_value[] = {
+       UL5_IN_MUX_CM1,
+       UL5_IN_MUX_NORMAL,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(ul5_in_mux_map_enum,
+                                 AFE_CM1_CON,
+                                 VUL3_BYPASS_CM_SFT,
+                                 VUL3_BYPASS_CM_MASK,
+                                 ul5_in_mux_map,
+                                 ul5_in_map_value);
+
+static const struct snd_kcontrol_new ul5_in_mux_control =
+       SOC_DAPM_ENUM("UL5_IN_MUX Select", ul5_in_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mt8186_memif_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)),
+       SND_SOC_DAPM_MIXER("UL1_CH3", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch3_mix, ARRAY_SIZE(memif_ul1_ch3_mix)),
+       SND_SOC_DAPM_MIXER("UL1_CH4", SND_SOC_NOPM, 0, 0,
+                          memif_ul1_ch4_mix, ARRAY_SIZE(memif_ul1_ch4_mix)),
+
+       SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL5_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul5_ch1_mix, ARRAY_SIZE(memif_ul5_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL5_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul5_ch2_mix, ARRAY_SIZE(memif_ul5_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL6_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul6_ch1_mix, ARRAY_SIZE(memif_ul6_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL6_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul6_ch2_mix, ARRAY_SIZE(memif_ul6_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL7_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul7_ch1_mix, ARRAY_SIZE(memif_ul7_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL7_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul7_ch2_mix, ARRAY_SIZE(memif_ul7_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL8_CH1", SND_SOC_NOPM, 0, 0,
+                          memif_ul8_ch1_mix, ARRAY_SIZE(memif_ul8_ch1_mix)),
+       SND_SOC_DAPM_MIXER("UL8_CH2", SND_SOC_NOPM, 0, 0,
+                          memif_ul8_ch2_mix, ARRAY_SIZE(memif_ul8_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("UL5_2CH", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MIXER("HW_CM1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* CM1 en*/
+       SND_SOC_DAPM_SUPPLY_S("CM1_EN", 0, AFE_CM1_CON,
+                             CHANNEL_MERGE0_EN_SFT, 0, NULL,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER("HW_CM1_CH1", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch1_mix, ARRAY_SIZE(hw_cm1_ch1_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH2", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch2_mix, ARRAY_SIZE(hw_cm1_ch2_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH3", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch3_mix, ARRAY_SIZE(hw_cm1_ch3_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH4", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch4_mix, ARRAY_SIZE(hw_cm1_ch4_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH5", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch5_mix, ARRAY_SIZE(hw_cm1_ch5_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH6", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch6_mix, ARRAY_SIZE(hw_cm1_ch6_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH7", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch7_mix, ARRAY_SIZE(hw_cm1_ch7_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH8", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch8_mix, ARRAY_SIZE(hw_cm1_ch8_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH9", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch9_mix, ARRAY_SIZE(hw_cm1_ch9_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH10", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch10_mix, ARRAY_SIZE(hw_cm1_ch10_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH11", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch11_mix, ARRAY_SIZE(hw_cm1_ch11_mix)),
+       SND_SOC_DAPM_MIXER("HW_CM1_CH12", SND_SOC_NOPM, 0, 0,
+                          hw_cm1_ch12_mix, ARRAY_SIZE(hw_cm1_ch12_mix)),
+
+       SND_SOC_DAPM_MUX("UL5_IN_MUX", SND_SOC_NOPM, 0, 0,
+                        &ul5_in_mux_control),
+
+       SND_SOC_DAPM_INPUT("UL1_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL2_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL3_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL4_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL5_VIRTUAL_INPUT"),
+       SND_SOC_DAPM_INPUT("UL6_VIRTUAL_INPUT"),
+};
+
+static const struct snd_soc_dapm_route mt8186_memif_routes[] = {
+       {"UL1", NULL, "UL1_CH1"},
+       {"UL1", NULL, "UL1_CH2"},
+       {"UL1", NULL, "UL1_CH3"},
+       {"UL1", NULL, "UL1_CH4"},
+       {"UL1_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH1", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH2", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH3", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH3", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH4", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH4", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL1_CH1", "TDM_IN_CH1 Switch", "TDM IN"},
+       {"UL1_CH2", "TDM_IN_CH2 Switch", "TDM IN"},
+       {"UL1_CH3", "TDM_IN_CH3 Switch", "TDM IN"},
+       {"UL1_CH4", "TDM_IN_CH4 Switch", "TDM IN"},
+
+       {"UL2", NULL, "UL2_CH1"},
+       {"UL2", NULL, "UL2_CH2"},
+
+       /* cannot connect FE to FE directly */
+       {"UL2_CH1", "DL1_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL1_CH2 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH1", "DL12_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL12_CH2 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH1", "DL6_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL6_CH2 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH1", "DL2_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL2_CH2 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH1", "DL3_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL3_CH2 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH1", "DL4_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL4_CH2 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH1", "DL5_CH1 Switch", "Hostless_UL2 UL"},
+       {"UL2_CH2", "DL5_CH2 Switch", "Hostless_UL2 UL"},
+
+       {"Hostless_UL2 UL", NULL, "UL2_VIRTUAL_INPUT"},
+
+       {"UL2_CH1", "I2S0_CH1 Switch", "I2S0"},
+       {"UL2_CH2", "I2S0_CH2 Switch", "I2S0"},
+       {"UL2_CH1", "I2S2_CH1 Switch", "I2S2"},
+       {"UL2_CH2", "I2S2_CH2 Switch", "I2S2"},
+
+       {"UL2_CH1", "PCM_1_CAP_CH1 Switch", "PCM 1 Capture"},
+       {"UL2_CH2", "PCM_1_CAP_CH2 Switch", "PCM 1 Capture"},
+
+       {"UL2_CH1", "CONNSYS_I2S_CH1 Switch", "Connsys I2S"},
+       {"UL2_CH2", "CONNSYS_I2S_CH2 Switch", "Connsys I2S"},
+
+       {"UL2_CH1", "SRC_1_OUT_CH1 Switch", "HW_SRC_1_Out"},
+       {"UL2_CH2", "SRC_1_OUT_CH2 Switch", "HW_SRC_1_Out"},
+
+       {"UL3", NULL, "UL3_CH1"},
+       {"UL3", NULL, "UL3_CH2"},
+       {"UL3_CH1", "CONNSYS_I2S_CH1 Switch", "Connsys I2S"},
+       {"UL3_CH2", "CONNSYS_I2S_CH2 Switch", "Connsys I2S"},
+
+       {"UL4", NULL, "UL4_CH1"},
+       {"UL4", NULL, "UL4_CH2"},
+       {"UL4_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL4_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL4_CH1", "I2S0_CH1 Switch", "I2S0"},
+       {"UL4_CH2", "I2S0_CH2 Switch", "I2S0"},
+
+       {"UL5", NULL, "UL5_IN_MUX"},
+       {"UL5_IN_MUX", "UL5_IN_FROM_Normal", "UL5_2CH"},
+       {"UL5_IN_MUX", "UL5_IN_FROM_CM1", "HW_CM1"},
+       {"UL5_2CH", NULL, "UL5_CH1"},
+       {"UL5_2CH", NULL, "UL5_CH2"},
+       {"UL5_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL5_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"HW_CM1", NULL, "CM1_EN"},
+       {"HW_CM1", NULL, "HW_CM1_CH1"},
+       {"HW_CM1", NULL, "HW_CM1_CH2"},
+       {"HW_CM1", NULL, "HW_CM1_CH3"},
+       {"HW_CM1", NULL, "HW_CM1_CH4"},
+       {"HW_CM1", NULL, "HW_CM1_CH5"},
+       {"HW_CM1", NULL, "HW_CM1_CH6"},
+       {"HW_CM1", NULL, "HW_CM1_CH7"},
+       {"HW_CM1", NULL, "HW_CM1_CH8"},
+       {"HW_CM1", NULL, "HW_CM1_CH9"},
+       {"HW_CM1", NULL, "HW_CM1_CH10"},
+       {"HW_CM1", NULL, "HW_CM1_CH11"},
+       {"HW_CM1", NULL, "HW_CM1_CH12"},
+       {"HW_CM1_CH1", "TDM_IN_CH1 Switch", "TDM IN"},
+       {"HW_CM1_CH2", "TDM_IN_CH2 Switch", "TDM IN"},
+       {"HW_CM1_CH3", "TDM_IN_CH3 Switch", "TDM IN"},
+       {"HW_CM1_CH4", "TDM_IN_CH4 Switch", "TDM IN"},
+       {"HW_CM1_CH5", "TDM_IN_CH5 Switch", "TDM IN"},
+       {"HW_CM1_CH6", "TDM_IN_CH6 Switch", "TDM IN"},
+       {"HW_CM1_CH7", "TDM_IN_CH7 Switch", "TDM IN"},
+       {"HW_CM1_CH8", "TDM_IN_CH8 Switch", "TDM IN"},
+       {"HW_CM1_CH9", "DL1_CH1 Switch", "Hostless_UL5 UL"},
+       {"HW_CM1_CH10", "DL1_CH2 Switch", "Hostless_UL5 UL"},
+
+       {"HW_CM1_CH3", "DL1_CH1 Switch", "Hostless_UL5 UL"},
+       {"HW_CM1_CH4", "DL1_CH2 Switch", "Hostless_UL5 UL"},
+
+       {"HW_CM1_CH3", "DL3_CH1 Switch", "Hostless_UL5 UL"},
+       {"HW_CM1_CH4", "DL3_CH2 Switch", "Hostless_UL5 UL"},
+
+       {"HW_CM1_CH5", "HW_SRC1_OUT_CH1 Switch", "HW_SRC_1_Out"},
+       {"HW_CM1_CH6", "HW_SRC1_OUT_CH2 Switch", "HW_SRC_1_Out"},
+
+       {"HW_CM1_CH9", "DL12_CH1 Switch", "Hostless_UL5 UL"},
+       {"HW_CM1_CH10", "DL12_CH2 Switch", "Hostless_UL5 UL"},
+       {"HW_CM1_CH11", "DL12_CH3 Switch", "Hostless_UL5 UL"},
+       {"HW_CM1_CH12", "DL12_CH4 Switch", "Hostless_UL5 UL"},
+
+       {"Hostless_UL5 UL", NULL, "UL5_VIRTUAL_INPUT"},
+
+       {"UL6", NULL, "UL6_CH1"},
+       {"UL6", NULL, "UL6_CH2"},
+
+       {"UL6_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL6_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL6_CH1", "DL1_CH1 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH2", "DL1_CH2 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH1", "DL2_CH1 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH2", "DL2_CH2 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH1", "DL12_CH1 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH2", "DL12_CH2 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH1", "DL6_CH1 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH2", "DL6_CH2 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH1", "DL3_CH1 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH2", "DL3_CH2 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH1", "DL4_CH1 Switch", "Hostless_UL6 UL"},
+       {"UL6_CH2", "DL4_CH2 Switch", "Hostless_UL6 UL"},
+       {"Hostless_UL6 UL", NULL, "UL6_VIRTUAL_INPUT"},
+       {"UL6_CH1", "PCM_1_CAP_CH1 Switch", "PCM 1 Capture"},
+       {"UL6_CH2", "PCM_1_CAP_CH2 Switch", "PCM 1 Capture"},
+       {"UL6_CH1", "GAIN1_OUT_CH1 Switch", "HW Gain 1 Out"},
+       {"UL6_CH2", "GAIN1_OUT_CH2 Switch", "HW Gain 1 Out"},
+
+       {"UL7", NULL, "UL7_CH1"},
+       {"UL7", NULL, "UL7_CH2"},
+       {"UL7_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL7_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+       {"UL7_CH1", "HW_GAIN2_OUT_CH1 Switch", "HW Gain 2 Out"},
+       {"UL7_CH2", "HW_GAIN2_OUT_CH2 Switch", "HW Gain 2 Out"},
+       {"UL7_CH1", "HW_SRC_2_OUT_CH1 Switch", "HW_SRC_2_Out"},
+       {"UL7_CH2", "HW_SRC_2_OUT_CH2 Switch", "HW_SRC_2_Out"},
+
+       {"UL8", NULL, "UL8_CH1"},
+       {"UL8", NULL, "UL8_CH2"},
+       {"UL8_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"UL8_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+
+       {"HW_GAIN2_IN_CH1", "ADDA_UL_CH1 Switch", "ADDA_UL_Mux"},
+       {"HW_GAIN2_IN_CH2", "ADDA_UL_CH2 Switch", "ADDA_UL_Mux"},
+};
+
+static const struct mtk_base_memif_data memif_data[MT8186_MEMIF_NUM] = {
+       [MT8186_MEMIF_DL1] = {
+               .name = "DL1",
+               .id = MT8186_MEMIF_DL1,
+               .reg_ofs_base = AFE_DL1_BASE,
+               .reg_ofs_cur = AFE_DL1_CUR,
+               .reg_ofs_end = AFE_DL1_END,
+               .reg_ofs_base_msb = AFE_DL1_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL1_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL1_END_MSB,
+               .fs_reg = AFE_DL1_CON0,
+               .fs_shift = DL1_MODE_SFT,
+               .fs_maskbit = DL1_MODE_MASK,
+               .mono_reg = AFE_DL1_CON0,
+               .mono_shift = DL1_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL1_ON_SFT,
+               .hd_reg = AFE_DL1_CON0,
+               .hd_shift = DL1_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL1_CON0,
+               .hd_align_mshift = DL1_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL1_CON0,
+               .pbuf_mask = DL1_PBUF_SIZE_MASK,
+               .pbuf_shift = DL1_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL1_CON0,
+               .minlen_mask = DL1_MINLEN_MASK,
+               .minlen_shift = DL1_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL12] = {
+               .name = "DL12",
+               .id = MT8186_MEMIF_DL12,
+               .reg_ofs_base = AFE_DL12_BASE,
+               .reg_ofs_cur = AFE_DL12_CUR,
+               .reg_ofs_end = AFE_DL12_END,
+               .reg_ofs_base_msb = AFE_DL12_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL12_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL12_END_MSB,
+               .fs_reg = AFE_DL12_CON0,
+               .fs_shift = DL12_MODE_SFT,
+               .fs_maskbit = DL12_MODE_MASK,
+               .mono_reg = AFE_DL12_CON0,
+               .mono_shift = DL12_MONO_SFT,
+               .quad_ch_reg = AFE_DL12_CON0,
+               .quad_ch_mask = DL12_4CH_EN_MASK,
+               .quad_ch_shift = DL12_4CH_EN_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL12_ON_SFT,
+               .hd_reg = AFE_DL12_CON0,
+               .hd_shift = DL12_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL12_CON0,
+               .hd_align_mshift = DL12_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL12_CON0,
+               .pbuf_mask = DL12_PBUF_SIZE_MASK,
+               .pbuf_shift = DL12_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL12_CON0,
+               .minlen_mask = DL12_MINLEN_MASK,
+               .minlen_shift = DL12_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL2] = {
+               .name = "DL2",
+               .id = MT8186_MEMIF_DL2,
+               .reg_ofs_base = AFE_DL2_BASE,
+               .reg_ofs_cur = AFE_DL2_CUR,
+               .reg_ofs_end = AFE_DL2_END,
+               .reg_ofs_base_msb = AFE_DL2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL2_END_MSB,
+               .fs_reg = AFE_DL2_CON0,
+               .fs_shift = DL2_MODE_SFT,
+               .fs_maskbit = DL2_MODE_MASK,
+               .mono_reg = AFE_DL2_CON0,
+               .mono_shift = DL2_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL2_ON_SFT,
+               .hd_reg = AFE_DL2_CON0,
+               .hd_shift = DL2_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL2_CON0,
+               .hd_align_mshift = DL2_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL2_CON0,
+               .pbuf_mask = DL2_PBUF_SIZE_MASK,
+               .pbuf_shift = DL2_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL2_CON0,
+               .minlen_mask = DL2_MINLEN_MASK,
+               .minlen_shift = DL2_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL3] = {
+               .name = "DL3",
+               .id = MT8186_MEMIF_DL3,
+               .reg_ofs_base = AFE_DL3_BASE,
+               .reg_ofs_cur = AFE_DL3_CUR,
+               .reg_ofs_end = AFE_DL3_END,
+               .reg_ofs_base_msb = AFE_DL3_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL3_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL3_END_MSB,
+               .fs_reg = AFE_DL3_CON0,
+               .fs_shift = DL3_MODE_SFT,
+               .fs_maskbit = DL3_MODE_MASK,
+               .mono_reg = AFE_DL3_CON0,
+               .mono_shift = DL3_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL3_ON_SFT,
+               .hd_reg = AFE_DL3_CON0,
+               .hd_shift = DL3_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL3_CON0,
+               .hd_align_mshift = DL3_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL3_CON0,
+               .pbuf_mask = DL3_PBUF_SIZE_MASK,
+               .pbuf_shift = DL3_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL3_CON0,
+               .minlen_mask = DL3_MINLEN_MASK,
+               .minlen_shift = DL3_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL4] = {
+               .name = "DL4",
+               .id = MT8186_MEMIF_DL4,
+               .reg_ofs_base = AFE_DL4_BASE,
+               .reg_ofs_cur = AFE_DL4_CUR,
+               .reg_ofs_end = AFE_DL4_END,
+               .reg_ofs_base_msb = AFE_DL4_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL4_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL4_END_MSB,
+               .fs_reg = AFE_DL4_CON0,
+               .fs_shift = DL4_MODE_SFT,
+               .fs_maskbit = DL4_MODE_MASK,
+               .mono_reg = AFE_DL4_CON0,
+               .mono_shift = DL4_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL4_ON_SFT,
+               .hd_reg = AFE_DL4_CON0,
+               .hd_shift = DL4_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL4_CON0,
+               .hd_align_mshift = DL4_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL4_CON0,
+               .pbuf_mask = DL4_PBUF_SIZE_MASK,
+               .pbuf_shift = DL4_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL4_CON0,
+               .minlen_mask = DL4_MINLEN_MASK,
+               .minlen_shift = DL4_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL5] = {
+               .name = "DL5",
+               .id = MT8186_MEMIF_DL5,
+               .reg_ofs_base = AFE_DL5_BASE,
+               .reg_ofs_cur = AFE_DL5_CUR,
+               .reg_ofs_end = AFE_DL5_END,
+               .reg_ofs_base_msb = AFE_DL5_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL5_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL5_END_MSB,
+               .fs_reg = AFE_DL5_CON0,
+               .fs_shift = DL5_MODE_SFT,
+               .fs_maskbit = DL5_MODE_MASK,
+               .mono_reg = AFE_DL5_CON0,
+               .mono_shift = DL5_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL5_ON_SFT,
+               .hd_reg = AFE_DL5_CON0,
+               .hd_shift = DL5_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL5_CON0,
+               .hd_align_mshift = DL5_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL5_CON0,
+               .pbuf_mask = DL5_PBUF_SIZE_MASK,
+               .pbuf_shift = DL5_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL5_CON0,
+               .minlen_mask = DL5_MINLEN_MASK,
+               .minlen_shift = DL5_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL6] = {
+               .name = "DL6",
+               .id = MT8186_MEMIF_DL6,
+               .reg_ofs_base = AFE_DL6_BASE,
+               .reg_ofs_cur = AFE_DL6_CUR,
+               .reg_ofs_end = AFE_DL6_END,
+               .reg_ofs_base_msb = AFE_DL6_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL6_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL6_END_MSB,
+               .fs_reg = AFE_DL6_CON0,
+               .fs_shift = DL6_MODE_SFT,
+               .fs_maskbit = DL6_MODE_MASK,
+               .mono_reg = AFE_DL6_CON0,
+               .mono_shift = DL6_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL6_ON_SFT,
+               .hd_reg = AFE_DL6_CON0,
+               .hd_shift = DL6_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL6_CON0,
+               .hd_align_mshift = DL6_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL6_CON0,
+               .pbuf_mask = DL6_PBUF_SIZE_MASK,
+               .pbuf_shift = DL6_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL6_CON0,
+               .minlen_mask = DL6_MINLEN_MASK,
+               .minlen_shift = DL6_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL7] = {
+               .name = "DL7",
+               .id = MT8186_MEMIF_DL7,
+               .reg_ofs_base = AFE_DL7_BASE,
+               .reg_ofs_cur = AFE_DL7_CUR,
+               .reg_ofs_end = AFE_DL7_END,
+               .reg_ofs_base_msb = AFE_DL7_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL7_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL7_END_MSB,
+               .fs_reg = AFE_DL7_CON0,
+               .fs_shift = DL7_MODE_SFT,
+               .fs_maskbit = DL7_MODE_MASK,
+               .mono_reg = AFE_DL7_CON0,
+               .mono_shift = DL7_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL7_ON_SFT,
+               .hd_reg = AFE_DL7_CON0,
+               .hd_shift = DL7_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL7_CON0,
+               .hd_align_mshift = DL7_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL7_CON0,
+               .pbuf_mask = DL7_PBUF_SIZE_MASK,
+               .pbuf_shift = DL7_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL7_CON0,
+               .minlen_mask = DL7_MINLEN_MASK,
+               .minlen_shift = DL7_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_DL8] = {
+               .name = "DL8",
+               .id = MT8186_MEMIF_DL8,
+               .reg_ofs_base = AFE_DL8_BASE,
+               .reg_ofs_cur = AFE_DL8_CUR,
+               .reg_ofs_end = AFE_DL8_END,
+               .reg_ofs_base_msb = AFE_DL8_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL8_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL8_END_MSB,
+               .fs_reg = AFE_DL8_CON0,
+               .fs_shift = DL8_MODE_SFT,
+               .fs_maskbit = DL8_MODE_MASK,
+               .mono_reg = AFE_DL8_CON0,
+               .mono_shift = DL8_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = DL8_ON_SFT,
+               .hd_reg = AFE_DL8_CON0,
+               .hd_shift = DL8_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL8_CON0,
+               .hd_align_mshift = DL8_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+               .pbuf_reg = AFE_DL8_CON0,
+               .pbuf_mask = DL8_PBUF_SIZE_MASK,
+               .pbuf_shift = DL8_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL8_CON0,
+               .minlen_mask = DL8_MINLEN_MASK,
+               .minlen_shift = DL8_MINLEN_SFT,
+       },
+       [MT8186_MEMIF_VUL12] = {
+               .name = "VUL12",
+               .id = MT8186_MEMIF_VUL12,
+               .reg_ofs_base = AFE_VUL12_BASE,
+               .reg_ofs_cur = AFE_VUL12_CUR,
+               .reg_ofs_end = AFE_VUL12_END,
+               .reg_ofs_base_msb = AFE_VUL12_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL12_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL12_END_MSB,
+               .fs_reg = AFE_VUL12_CON0,
+               .fs_shift = VUL12_MODE_SFT,
+               .fs_maskbit = VUL12_MODE_MASK,
+               .mono_reg = AFE_VUL12_CON0,
+               .mono_shift = VUL12_MONO_SFT,
+               .quad_ch_reg = AFE_VUL12_CON0,
+               .quad_ch_mask = VUL12_4CH_EN_MASK,
+               .quad_ch_shift = VUL12_4CH_EN_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL12_ON_SFT,
+               .hd_reg = AFE_VUL12_CON0,
+               .hd_shift = VUL12_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL12_CON0,
+               .hd_align_mshift = VUL12_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_VUL2] = {
+               .name = "VUL2",
+               .id = MT8186_MEMIF_VUL2,
+               .reg_ofs_base = AFE_VUL2_BASE,
+               .reg_ofs_cur = AFE_VUL2_CUR,
+               .reg_ofs_end = AFE_VUL2_END,
+               .reg_ofs_base_msb = AFE_VUL2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL2_END_MSB,
+               .fs_reg = AFE_VUL2_CON0,
+               .fs_shift = VUL2_MODE_SFT,
+               .fs_maskbit = VUL2_MODE_MASK,
+               .mono_reg = AFE_VUL2_CON0,
+               .mono_shift = VUL2_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL2_ON_SFT,
+               .hd_reg = AFE_VUL2_CON0,
+               .hd_shift = VUL2_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL2_CON0,
+               .hd_align_mshift = VUL2_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_AWB] = {
+               .name = "AWB",
+               .id = MT8186_MEMIF_AWB,
+               .reg_ofs_base = AFE_AWB_BASE,
+               .reg_ofs_cur = AFE_AWB_CUR,
+               .reg_ofs_end = AFE_AWB_END,
+               .reg_ofs_base_msb = AFE_AWB_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_AWB_CUR_MSB,
+               .reg_ofs_end_msb = AFE_AWB_END_MSB,
+               .fs_reg = AFE_AWB_CON0,
+               .fs_shift = AWB_MODE_SFT,
+               .fs_maskbit = AWB_MODE_MASK,
+               .mono_reg = AFE_AWB_CON0,
+               .mono_shift = AWB_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = AWB_ON_SFT,
+               .hd_reg = AFE_AWB_CON0,
+               .hd_shift = AWB_HD_MODE_SFT,
+               .hd_align_reg = AFE_AWB_CON0,
+               .hd_align_mshift = AWB_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_AWB2] = {
+               .name = "AWB2",
+               .id = MT8186_MEMIF_AWB2,
+               .reg_ofs_base = AFE_AWB2_BASE,
+               .reg_ofs_cur = AFE_AWB2_CUR,
+               .reg_ofs_end = AFE_AWB2_END,
+               .reg_ofs_base_msb = AFE_AWB2_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_AWB2_CUR_MSB,
+               .reg_ofs_end_msb = AFE_AWB2_END_MSB,
+               .fs_reg = AFE_AWB2_CON0,
+               .fs_shift = AWB2_MODE_SFT,
+               .fs_maskbit = AWB2_MODE_MASK,
+               .mono_reg = AFE_AWB2_CON0,
+               .mono_shift = AWB2_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = AWB2_ON_SFT,
+               .hd_reg = AFE_AWB2_CON0,
+               .hd_shift = AWB2_HD_MODE_SFT,
+               .hd_align_reg = AFE_AWB2_CON0,
+               .hd_align_mshift = AWB2_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_VUL3] = {
+               .name = "VUL3",
+               .id = MT8186_MEMIF_VUL3,
+               .reg_ofs_base = AFE_VUL3_BASE,
+               .reg_ofs_cur = AFE_VUL3_CUR,
+               .reg_ofs_end = AFE_VUL3_END,
+               .reg_ofs_base_msb = AFE_VUL3_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL3_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL3_END_MSB,
+               .fs_reg = AFE_VUL3_CON0,
+               .fs_shift = VUL3_MODE_SFT,
+               .fs_maskbit = VUL3_MODE_MASK,
+               .mono_reg = AFE_VUL3_CON0,
+               .mono_shift = VUL3_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL3_ON_SFT,
+               .hd_reg = AFE_VUL3_CON0,
+               .hd_shift = VUL3_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL3_CON0,
+               .hd_align_mshift = VUL3_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_VUL4] = {
+               .name = "VUL4",
+               .id = MT8186_MEMIF_VUL4,
+               .reg_ofs_base = AFE_VUL4_BASE,
+               .reg_ofs_cur = AFE_VUL4_CUR,
+               .reg_ofs_end = AFE_VUL4_END,
+               .reg_ofs_base_msb = AFE_VUL4_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL4_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL4_END_MSB,
+               .fs_reg = AFE_VUL4_CON0,
+               .fs_shift = VUL4_MODE_SFT,
+               .fs_maskbit = VUL4_MODE_MASK,
+               .mono_reg = AFE_VUL4_CON0,
+               .mono_shift = VUL4_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL4_ON_SFT,
+               .hd_reg = AFE_VUL4_CON0,
+               .hd_shift = VUL4_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL4_CON0,
+               .hd_align_mshift = VUL4_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_VUL5] = {
+               .name = "VUL5",
+               .id = MT8186_MEMIF_VUL5,
+               .reg_ofs_base = AFE_VUL5_BASE,
+               .reg_ofs_cur = AFE_VUL5_CUR,
+               .reg_ofs_end = AFE_VUL5_END,
+               .reg_ofs_base_msb = AFE_VUL5_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL5_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL5_END_MSB,
+               .fs_reg = AFE_VUL5_CON0,
+               .fs_shift = VUL5_MODE_SFT,
+               .fs_maskbit = VUL5_MODE_MASK,
+               .mono_reg = AFE_VUL5_CON0,
+               .mono_shift = VUL5_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL5_ON_SFT,
+               .hd_reg = AFE_VUL5_CON0,
+               .hd_shift = VUL5_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL5_CON0,
+               .hd_align_mshift = VUL5_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+       [MT8186_MEMIF_VUL6] = {
+               .name = "VUL6",
+               .id = MT8186_MEMIF_VUL6,
+               .reg_ofs_base = AFE_VUL6_BASE,
+               .reg_ofs_cur = AFE_VUL6_CUR,
+               .reg_ofs_end = AFE_VUL6_END,
+               .reg_ofs_base_msb = AFE_VUL6_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL6_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL6_END_MSB,
+               .fs_reg = AFE_VUL6_CON0,
+               .fs_shift = VUL6_MODE_SFT,
+               .fs_maskbit = VUL6_MODE_MASK,
+               .mono_reg = AFE_VUL6_CON0,
+               .mono_shift = VUL6_MONO_SFT,
+               .enable_reg = AFE_DAC_CON0,
+               .enable_shift = VUL6_ON_SFT,
+               .hd_reg = AFE_VUL6_CON0,
+               .hd_shift = VUL6_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL6_CON0,
+               .hd_align_mshift = VUL6_HALIGN_SFT,
+               .agent_disable_reg = -1,
+               .agent_disable_shift = -1,
+               .msb_reg = -1,
+               .msb_shift = -1,
+       },
+};
+
+static const struct mtk_base_irq_data irq_data[MT8186_IRQ_NUM] = {
+       [MT8186_IRQ_0] = {
+               .id = MT8186_IRQ_0,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT0,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ0_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ0_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ0_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ0_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_1] = {
+               .id = MT8186_IRQ_1,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT1,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ1_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ1_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ1_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_2] = {
+               .id = MT8186_IRQ_2,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT2,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ2_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ2_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ2_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_3] = {
+               .id = MT8186_IRQ_3,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT3,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ3_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ3_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ3_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ3_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_4] = {
+               .id = MT8186_IRQ_4,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT4,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ4_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ4_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ4_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ4_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_5] = {
+               .id = MT8186_IRQ_5,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT5,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ5_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ5_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ5_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ5_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_6] = {
+               .id = MT8186_IRQ_6,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT6,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ6_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ6_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ6_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ6_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_7] = {
+               .id = MT8186_IRQ_7,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT7,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON1,
+               .irq_fs_shift = IRQ7_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ7_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ7_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ7_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_8] = {
+               .id = MT8186_IRQ_8,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT8,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ8_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ8_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ8_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ8_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_9] = {
+               .id = MT8186_IRQ_9,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT9,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ9_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ9_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ9_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ9_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_10] = {
+               .id = MT8186_IRQ_10,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT10,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ10_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ10_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ10_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ10_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_11] = {
+               .id = MT8186_IRQ_11,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT11,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ11_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ11_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ11_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ11_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_12] = {
+               .id = MT8186_IRQ_12,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT12,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ12_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ12_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ12_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ12_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_13] = {
+               .id = MT8186_IRQ_13,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT13,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ13_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ13_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ13_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ13_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_14] = {
+               .id = MT8186_IRQ_14,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT14,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ14_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ14_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ14_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ14_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_15] = {
+               .id = MT8186_IRQ_15,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT15,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON2,
+               .irq_fs_shift = IRQ15_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ15_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ15_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ15_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_16] = {
+               .id = MT8186_IRQ_16,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT16,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ16_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ16_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ16_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ16_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_17] = {
+               .id = MT8186_IRQ_17,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT17,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ17_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ17_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ17_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ17_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_18] = {
+               .id = MT8186_IRQ_18,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT18,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ18_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ18_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ18_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ18_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_19] = {
+               .id = MT8186_IRQ_19,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT19,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ19_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ19_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ19_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ19_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_20] = {
+               .id = MT8186_IRQ_20,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT20,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ20_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ20_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ20_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ20_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_21] = {
+               .id = MT8186_IRQ_21,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT21,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ21_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ21_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ21_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ21_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_22] = {
+               .id = MT8186_IRQ_22,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT22,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ22_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ22_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ22_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ22_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_23] = {
+               .id = MT8186_IRQ_23,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT23,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON3,
+               .irq_fs_shift = IRQ23_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ23_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ23_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ23_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_24] = {
+               .id = MT8186_IRQ_24,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT24,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON4,
+               .irq_fs_shift = IRQ24_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ24_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ24_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ24_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_25] = {
+               .id = MT8186_IRQ_25,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT25,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON4,
+               .irq_fs_shift = IRQ25_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ25_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ25_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ25_MCU_CLR_SFT,
+       },
+       [MT8186_IRQ_26] = {
+               .id = MT8186_IRQ_26,
+               .irq_cnt_reg = AFE_IRQ_MCU_CNT26,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ_MCU_CON4,
+               .irq_fs_shift = IRQ26_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ26_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ_MCU_CON0,
+               .irq_en_shift = IRQ26_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ26_MCU_CLR_SFT,
+       },
+};
+
+static const int memif_irq_usage[MT8186_MEMIF_NUM] = {
+       /* TODO: verify each memif & irq */
+       [MT8186_MEMIF_DL1] = MT8186_IRQ_0,
+       [MT8186_MEMIF_DL2] = MT8186_IRQ_1,
+       [MT8186_MEMIF_DL3] = MT8186_IRQ_2,
+       [MT8186_MEMIF_DL4] = MT8186_IRQ_3,
+       [MT8186_MEMIF_DL5] = MT8186_IRQ_4,
+       [MT8186_MEMIF_DL6] = MT8186_IRQ_5,
+       [MT8186_MEMIF_DL7] = MT8186_IRQ_6,
+       [MT8186_MEMIF_DL8] = MT8186_IRQ_7,
+       [MT8186_MEMIF_DL12] = MT8186_IRQ_9,
+       [MT8186_MEMIF_VUL12] = MT8186_IRQ_10,
+       [MT8186_MEMIF_VUL2] = MT8186_IRQ_11,
+       [MT8186_MEMIF_AWB] = MT8186_IRQ_12,
+       [MT8186_MEMIF_AWB2] = MT8186_IRQ_13,
+       [MT8186_MEMIF_VUL3] = MT8186_IRQ_14,
+       [MT8186_MEMIF_VUL4] = MT8186_IRQ_15,
+       [MT8186_MEMIF_VUL5] = MT8186_IRQ_16,
+       [MT8186_MEMIF_VUL6] = MT8186_IRQ_17,
+};
+
+static bool mt8186_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       /* these auto-gen reg has read-only bit, so put it as volatile */
+       /* volatile reg cannot be cached, so cannot be set when power off */
+       switch (reg) {
+       case AUDIO_TOP_CON0:    /* reg bit controlled by CCF */
+       case AUDIO_TOP_CON1:    /* reg bit controlled by CCF */
+       case AUDIO_TOP_CON2:
+       case AUDIO_TOP_CON3:
+       case AFE_DL1_CUR_MSB:
+       case AFE_DL1_CUR:
+       case AFE_DL1_END:
+       case AFE_DL2_CUR_MSB:
+       case AFE_DL2_CUR:
+       case AFE_DL2_END:
+       case AFE_DL3_CUR_MSB:
+       case AFE_DL3_CUR:
+       case AFE_DL3_END:
+       case AFE_DL4_CUR_MSB:
+       case AFE_DL4_CUR:
+       case AFE_DL4_END:
+       case AFE_DL12_CUR_MSB:
+       case AFE_DL12_CUR:
+       case AFE_DL12_END:
+       case AFE_ADDA_SRC_DEBUG_MON0:
+       case AFE_ADDA_SRC_DEBUG_MON1:
+       case AFE_ADDA_UL_SRC_MON0:
+       case AFE_ADDA_UL_SRC_MON1:
+       case AFE_SECURE_CON0:
+       case AFE_SRAM_BOUND:
+       case AFE_SECURE_CON1:
+       case AFE_VUL_CUR_MSB:
+       case AFE_VUL_CUR:
+       case AFE_VUL_END:
+       case AFE_SIDETONE_MON:
+       case AFE_SIDETONE_CON0:
+       case AFE_SIDETONE_COEFF:
+       case AFE_VUL2_CUR_MSB:
+       case AFE_VUL2_CUR:
+       case AFE_VUL2_END:
+       case AFE_VUL3_CUR_MSB:
+       case AFE_VUL3_CUR:
+       case AFE_VUL3_END:
+       case AFE_I2S_MON:
+       case AFE_DAC_MON:
+       case AFE_IRQ0_MCU_CNT_MON:
+       case AFE_IRQ6_MCU_CNT_MON:
+       case AFE_VUL4_CUR_MSB:
+       case AFE_VUL4_CUR:
+       case AFE_VUL4_END:
+       case AFE_VUL12_CUR_MSB:
+       case AFE_VUL12_CUR:
+       case AFE_VUL12_END:
+       case AFE_IRQ3_MCU_CNT_MON:
+       case AFE_IRQ4_MCU_CNT_MON:
+       case AFE_IRQ_MCU_STATUS:
+       case AFE_IRQ_MCU_CLR:
+       case AFE_IRQ_MCU_MON2:
+       case AFE_IRQ1_MCU_CNT_MON:
+       case AFE_IRQ2_MCU_CNT_MON:
+       case AFE_IRQ5_MCU_CNT_MON:
+       case AFE_IRQ7_MCU_CNT_MON:
+       case AFE_IRQ_MCU_MISS_CLR:
+       case AFE_GAIN1_CUR:
+       case AFE_GAIN2_CUR:
+       case AFE_SRAM_DELSEL_CON1:
+       case PCM_INTF_CON2:
+       case FPGA_CFG0:
+       case FPGA_CFG1:
+       case FPGA_CFG2:
+       case FPGA_CFG3:
+       case AUDIO_TOP_DBG_MON0:
+       case AUDIO_TOP_DBG_MON1:
+       case AFE_IRQ8_MCU_CNT_MON:
+       case AFE_IRQ11_MCU_CNT_MON:
+       case AFE_IRQ12_MCU_CNT_MON:
+       case AFE_IRQ9_MCU_CNT_MON:
+       case AFE_IRQ10_MCU_CNT_MON:
+       case AFE_IRQ13_MCU_CNT_MON:
+       case AFE_IRQ14_MCU_CNT_MON:
+       case AFE_IRQ15_MCU_CNT_MON:
+       case AFE_IRQ16_MCU_CNT_MON:
+       case AFE_IRQ17_MCU_CNT_MON:
+       case AFE_IRQ18_MCU_CNT_MON:
+       case AFE_IRQ19_MCU_CNT_MON:
+       case AFE_IRQ20_MCU_CNT_MON:
+       case AFE_IRQ21_MCU_CNT_MON:
+       case AFE_IRQ22_MCU_CNT_MON:
+       case AFE_IRQ23_MCU_CNT_MON:
+       case AFE_IRQ24_MCU_CNT_MON:
+       case AFE_IRQ25_MCU_CNT_MON:
+       case AFE_IRQ26_MCU_CNT_MON:
+       case AFE_IRQ31_MCU_CNT_MON:
+       case AFE_CBIP_MON0:
+       case AFE_CBIP_SLV_MUX_MON0:
+       case AFE_CBIP_SLV_DECODER_MON0:
+       case AFE_ADDA6_MTKAIF_MON0:
+       case AFE_ADDA6_MTKAIF_MON1:
+       case AFE_AWB_CUR_MSB:
+       case AFE_AWB_CUR:
+       case AFE_AWB_END:
+       case AFE_AWB2_CUR_MSB:
+       case AFE_AWB2_CUR:
+       case AFE_AWB2_END:
+       case AFE_DAI_CUR_MSB:
+       case AFE_DAI_CUR:
+       case AFE_DAI_END:
+       case AFE_DAI2_CUR_MSB:
+       case AFE_DAI2_CUR:
+       case AFE_DAI2_END:
+       case AFE_ADDA6_SRC_DEBUG_MON0:
+       case AFE_ADD6A_UL_SRC_MON0:
+       case AFE_ADDA6_UL_SRC_MON1:
+       case AFE_MOD_DAI_CUR_MSB:
+       case AFE_MOD_DAI_CUR:
+       case AFE_MOD_DAI_END:
+       case AFE_AWB_RCH_MON:
+       case AFE_AWB_LCH_MON:
+       case AFE_VUL_RCH_MON:
+       case AFE_VUL_LCH_MON:
+       case AFE_VUL12_RCH_MON:
+       case AFE_VUL12_LCH_MON:
+       case AFE_VUL2_RCH_MON:
+       case AFE_VUL2_LCH_MON:
+       case AFE_DAI_DATA_MON:
+       case AFE_MOD_DAI_DATA_MON:
+       case AFE_DAI2_DATA_MON:
+       case AFE_AWB2_RCH_MON:
+       case AFE_AWB2_LCH_MON:
+       case AFE_VUL3_RCH_MON:
+       case AFE_VUL3_LCH_MON:
+       case AFE_VUL4_RCH_MON:
+       case AFE_VUL4_LCH_MON:
+       case AFE_VUL5_RCH_MON:
+       case AFE_VUL5_LCH_MON:
+       case AFE_VUL6_RCH_MON:
+       case AFE_VUL6_LCH_MON:
+       case AFE_DL1_RCH_MON:
+       case AFE_DL1_LCH_MON:
+       case AFE_DL2_RCH_MON:
+       case AFE_DL2_LCH_MON:
+       case AFE_DL12_RCH1_MON:
+       case AFE_DL12_LCH1_MON:
+       case AFE_DL12_RCH2_MON:
+       case AFE_DL12_LCH2_MON:
+       case AFE_DL3_RCH_MON:
+       case AFE_DL3_LCH_MON:
+       case AFE_DL4_RCH_MON:
+       case AFE_DL4_LCH_MON:
+       case AFE_DL5_RCH_MON:
+       case AFE_DL5_LCH_MON:
+       case AFE_DL6_RCH_MON:
+       case AFE_DL6_LCH_MON:
+       case AFE_DL7_RCH_MON:
+       case AFE_DL7_LCH_MON:
+       case AFE_DL8_RCH_MON:
+       case AFE_DL8_LCH_MON:
+       case AFE_VUL5_CUR_MSB:
+       case AFE_VUL5_CUR:
+       case AFE_VUL5_END:
+       case AFE_VUL6_CUR_MSB:
+       case AFE_VUL6_CUR:
+       case AFE_VUL6_END:
+       case AFE_ADDA_DL_SDM_FIFO_MON:
+       case AFE_ADDA_DL_SRC_LCH_MON:
+       case AFE_ADDA_DL_SRC_RCH_MON:
+       case AFE_ADDA_DL_SDM_OUT_MON:
+       case AFE_CONNSYS_I2S_MON:
+       case AFE_ASRC_2CH_CON0:
+       case AFE_ASRC_2CH_CON2:
+       case AFE_ASRC_2CH_CON3:
+       case AFE_ASRC_2CH_CON4:
+       case AFE_ASRC_2CH_CON5:
+       case AFE_ASRC_2CH_CON7:
+       case AFE_ASRC_2CH_CON8:
+       case AFE_ASRC_2CH_CON12:
+       case AFE_ASRC_2CH_CON13:
+       case AFE_ADDA_MTKAIF_MON0:
+       case AFE_ADDA_MTKAIF_MON1:
+       case AFE_AUD_PAD_TOP:
+       case AFE_DL_NLE_R_MON0:
+       case AFE_DL_NLE_R_MON1:
+       case AFE_DL_NLE_R_MON2:
+       case AFE_DL_NLE_L_MON0:
+       case AFE_DL_NLE_L_MON1:
+       case AFE_DL_NLE_L_MON2:
+       case AFE_GENERAL1_ASRC_2CH_CON0:
+       case AFE_GENERAL1_ASRC_2CH_CON2:
+       case AFE_GENERAL1_ASRC_2CH_CON3:
+       case AFE_GENERAL1_ASRC_2CH_CON4:
+       case AFE_GENERAL1_ASRC_2CH_CON5:
+       case AFE_GENERAL1_ASRC_2CH_CON7:
+       case AFE_GENERAL1_ASRC_2CH_CON8:
+       case AFE_GENERAL1_ASRC_2CH_CON12:
+       case AFE_GENERAL1_ASRC_2CH_CON13:
+       case AFE_GENERAL2_ASRC_2CH_CON0:
+       case AFE_GENERAL2_ASRC_2CH_CON2:
+       case AFE_GENERAL2_ASRC_2CH_CON3:
+       case AFE_GENERAL2_ASRC_2CH_CON4:
+       case AFE_GENERAL2_ASRC_2CH_CON5:
+       case AFE_GENERAL2_ASRC_2CH_CON7:
+       case AFE_GENERAL2_ASRC_2CH_CON8:
+       case AFE_GENERAL2_ASRC_2CH_CON12:
+       case AFE_GENERAL2_ASRC_2CH_CON13:
+       case AFE_DL5_CUR_MSB:
+       case AFE_DL5_CUR:
+       case AFE_DL5_END:
+       case AFE_DL6_CUR_MSB:
+       case AFE_DL6_CUR:
+       case AFE_DL6_END:
+       case AFE_DL7_CUR_MSB:
+       case AFE_DL7_CUR:
+       case AFE_DL7_END:
+       case AFE_DL8_CUR_MSB:
+       case AFE_DL8_CUR:
+       case AFE_DL8_END:
+       case AFE_PROT_SIDEBAND_MON:
+       case AFE_DOMAIN_SIDEBAND0_MON:
+       case AFE_DOMAIN_SIDEBAND1_MON:
+       case AFE_DOMAIN_SIDEBAND2_MON:
+       case AFE_DOMAIN_SIDEBAND3_MON:
+       case AFE_APLL1_TUNER_CFG:       /* [20:31] is monitor */
+       case AFE_APLL2_TUNER_CFG:       /* [20:31] is monitor */
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config mt8186_afe_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+
+       .volatile_reg = mt8186_is_volatile_reg,
+
+       .max_register = AFE_MAX_REGISTER,
+       .num_reg_defaults_raw = AFE_MAX_REGISTER,
+
+       .cache_type = REGCACHE_FLAT,
+};
+
+static irqreturn_t mt8186_afe_irq_handler(int irq_id, void *dev)
+{
+       struct mtk_base_afe *afe = dev;
+       struct mtk_base_afe_irq *irq;
+       unsigned int status;
+       unsigned int status_mcu;
+       unsigned int mcu_en;
+       int ret;
+       int i;
+
+       /* get irq that is sent to MCU */
+       ret = regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+       if (ret) {
+               dev_err(afe->dev, "%s, get irq direction fail, ret %d", __func__, ret);
+               return ret;
+       }
+
+       ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+       /* only care IRQ which is sent to MCU */
+       status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+       if (ret || status_mcu == 0) {
+               dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+                       __func__, ret, status, mcu_en);
+
+               goto err_irq;
+       }
+
+       for (i = 0; i < MT8186_MEMIF_NUM; i++) {
+               struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+               if (!memif->substream)
+                       continue;
+
+               if (memif->irq_usage < 0)
+                       continue;
+
+               irq = &afe->irqs[memif->irq_usage];
+
+               if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+                       snd_pcm_period_elapsed(memif->substream);
+       }
+
+err_irq:
+       /* clear irq */
+       regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
+
+       return IRQ_HANDLED;
+}
+
+static int mt8186_afe_runtime_suspend(struct device *dev)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dev);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       unsigned int value = 0;
+       int ret;
+
+       if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+               goto skip_regmap;
+
+       /* disable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x0);
+
+       ret = regmap_read_poll_timeout(afe->regmap,
+                                      AFE_DAC_MON,
+                                      value,
+                                      (value & AFE_ON_RETM_MASK_SFT) == 0,
+                                      20,
+                                      1 * 1000 * 1000);
+       if (ret) {
+               dev_err(afe->dev, "%s(), ret %d\n", __func__, ret);
+               return ret;
+       }
+
+       /* make sure all irq status are cleared */
+       regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff);
+       regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, 0xffffffff);
+
+       /* reset sgen */
+       regmap_write(afe->regmap, AFE_SINEGEN_CON0, 0x0);
+       regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+                          INNER_LOOP_BACK_MODE_MASK_SFT,
+                          0x3f << INNER_LOOP_BACK_MODE_SFT);
+
+       /* cache only */
+       regcache_cache_only(afe->regmap, true);
+       regcache_mark_dirty(afe->regmap);
+
+skip_regmap:
+       mt8186_afe_disable_cgs(afe);
+       mt8186_afe_disable_clock(afe);
+
+       return 0;
+}
+
+static int mt8186_afe_runtime_resume(struct device *dev)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dev);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       ret = mt8186_afe_enable_clock(afe);
+       if (ret)
+               return ret;
+
+       ret = mt8186_afe_enable_cgs(afe);
+       if (ret)
+               return ret;
+
+       if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+               goto skip_regmap;
+
+       regcache_cache_only(afe->regmap, false);
+       regcache_sync(afe->regmap);
+
+       /* enable audio sys DCM for power saving */
+       regmap_update_bits(afe_priv->infracfg, PERI_BUS_DCM_CTRL, BIT(29), BIT(29));
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, BIT(29), BIT(29));
+
+       /* force cpu use 8_24 format when writing 32bit data */
+       regmap_update_bits(afe->regmap, AFE_MEMIF_CON0, CPU_HD_ALIGN_MASK_SFT, 0);
+
+       /* set all output port to 24bit */
+       regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff);
+       regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff);
+
+       /* enable AFE */
+       regmap_update_bits(afe->regmap, AFE_DAC_CON0, AUDIO_AFE_ON_MASK_SFT, BIT(0));
+
+skip_regmap:
+       return 0;
+}
+
+static int mt8186_afe_component_probe(struct snd_soc_component *component)
+{
+       mtk_afe_add_sub_dai_control(component);
+       mt8186_add_misc_control(component);
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver mt8186_afe_component = {
+       .name = AFE_PCM_NAME,
+       .pcm_construct = mtk_afe_pcm_new,
+       .pointer = mtk_afe_pcm_pointer,
+       .probe = mt8186_afe_component_probe,
+};
+
+static int mt8186_dai_memif_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mt8186_memif_dai_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mt8186_memif_dai_driver);
+
+       dai->controls = mt8186_pcm_kcontrols;
+       dai->num_controls = ARRAY_SIZE(mt8186_pcm_kcontrols);
+       dai->dapm_widgets = mt8186_memif_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mt8186_memif_widgets);
+       dai->dapm_routes = mt8186_memif_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mt8186_memif_routes);
+       return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+       mt8186_dai_adda_register,
+       mt8186_dai_i2s_register,
+       mt8186_dai_tdm_register,
+       mt8186_dai_hw_gain_register,
+       mt8186_dai_src_register,
+       mt8186_dai_pcm_register,
+       mt8186_dai_hostless_register,
+       mt8186_dai_memif_register,
+};
+
+static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct mtk_base_afe *afe;
+       struct mt8186_afe_private *afe_priv;
+       struct resource *res;
+       struct reset_control *rstc;
+       struct device *dev = &pdev->dev;
+       int i, ret, irq_id;
+
+       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
+       if (ret)
+               return ret;
+
+       afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
+       if (!afe)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, afe);
+
+       afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv), GFP_KERNEL);
+       if (!afe->platform_priv)
+               return -ENOMEM;
+
+       afe_priv = afe->platform_priv;
+       afe->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       afe->base_addr = devm_ioremap_resource(dev, res);
+       if (IS_ERR(afe->base_addr))
+               return PTR_ERR(afe->base_addr);
+
+       /* init audio related clock */
+       ret = mt8186_init_clock(afe);
+       if (ret) {
+               dev_err(dev, "init clock error, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(dev, mt8186_deinit_clock, (void *)afe);
+       if (ret)
+               return ret;
+
+       /* init memif */
+       afe->memif_32bit_supported = 0;
+       afe->memif_size = MT8186_MEMIF_NUM;
+       afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), GFP_KERNEL);
+       if (!afe->memif)
+               return -ENOMEM;
+
+       for (i = 0; i < afe->memif_size; i++) {
+               afe->memif[i].data = &memif_data[i];
+               afe->memif[i].irq_usage = memif_irq_usage[i];
+               afe->memif[i].const_irq = 1;
+       }
+
+       mutex_init(&afe->irq_alloc_lock);       /* needed when dynamic irq */
+
+       /* init irq */
+       afe->irqs_size = MT8186_IRQ_NUM;
+       afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+                                GFP_KERNEL);
+
+       if (!afe->irqs)
+               return -ENOMEM;
+
+       for (i = 0; i < afe->irqs_size; i++)
+               afe->irqs[i].irq_data = &irq_data[i];
+
+       /* request irq */
+       irq_id = platform_get_irq(pdev, 0);
+       if (irq_id <= 0)
+               return dev_err_probe(dev, irq_id < 0 ? irq_id : -ENXIO,
+                                    "no irq found");
+
+       ret = devm_request_irq(dev, irq_id, mt8186_afe_irq_handler,
+                              IRQF_TRIGGER_NONE,
+                              "Afe_ISR_Handle", (void *)afe);
+       if (ret)
+               return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+
+       ret = enable_irq_wake(irq_id);
+       if (ret < 0)
+               return dev_err_probe(dev, ret, "enable_irq_wake %d\n", irq_id);
+
+       /* init sub_dais */
+       INIT_LIST_HEAD(&afe->sub_dais);
+
+       for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+               ret = dai_register_cbs[i](afe);
+               if (ret)
+                       return dev_err_probe(dev, ret, "dai register i %d fail\n", i);
+       }
+
+       /* init dai_driver and component_driver */
+       ret = mtk_afe_combine_sub_dai(afe);
+       if (ret)
+               return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+       /* reset controller to reset audio regs before regmap cache */
+       rstc = devm_reset_control_get_exclusive(dev, "audiosys");
+       if (IS_ERR(rstc))
+               return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n");
+
+       ret = reset_control_reset(rstc);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to trigger audio reset\n");
+
+       /* enable clock for regcache get default value from hw */
+       afe_priv->pm_runtime_bypass_reg_ctl = true;
+
+       ret = devm_pm_runtime_enable(dev);
+       if (ret)
+               return ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to resume device\n");
+
+       afe->regmap = devm_regmap_init_mmio(dev, afe->base_addr,
+                                           &mt8186_afe_regmap_config);
+       if (IS_ERR(afe->regmap)) {
+               ret = PTR_ERR(afe->regmap);
+               goto err_pm_disable;
+       }
+
+       /* others */
+       afe->mtk_afe_hardware = &mt8186_afe_hardware;
+       afe->memif_fs = mt8186_memif_fs;
+       afe->irq_fs = mt8186_irq_fs;
+       afe->get_dai_fs = mt8186_get_dai_fs;
+       afe->get_memif_pbuf_size = mt8186_get_memif_pbuf_size;
+
+       afe->runtime_resume = mt8186_afe_runtime_resume;
+       afe->runtime_suspend = mt8186_afe_runtime_suspend;
+
+       /* register platform */
+       dev_dbg(dev, "%s(), devm_snd_soc_register_component\n", __func__);
+
+       ret = devm_snd_soc_register_component(dev,
+                                             &mt8186_afe_component,
+                                             afe->dai_drivers,
+                                             afe->num_dai_drivers);
+       if (ret) {
+               dev_err(dev, "err_dai_component\n");
+               goto err_pm_disable;
+       }
+
+       ret = pm_runtime_put_sync(dev);
+       if (ret) {
+               pm_runtime_get_noresume(dev);
+               dev_err(dev, "failed to suspend device: %d\n", ret);
+               goto err_pm_disable;
+       }
+       afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+       regcache_cache_only(afe->regmap, true);
+       regcache_mark_dirty(afe->regmap);
+
+       return 0;
+
+err_pm_disable:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_set_suspended(dev);
+
+       return ret;
+}
+
+static const struct of_device_id mt8186_afe_pcm_dt_match[] = {
+       { .compatible = "mediatek,mt8186-sound", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mt8186_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt8186_afe_pm_ops = {
+       SET_RUNTIME_PM_OPS(mt8186_afe_runtime_suspend,
+                          mt8186_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt8186_afe_pcm_driver = {
+       .driver = {
+                  .name = "mt8186-audio",
+                  .of_match_table = mt8186_afe_pcm_dt_match,
+                  .pm = &mt8186_afe_pm_ops,
+       },
+       .probe = mt8186_afe_pcm_dev_probe,
+};
+
+module_platform_driver(mt8186_afe_pcm_driver);
+
+MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8186");
+MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.c
new file mode 100644 (file)
index 0000000..578969c
--- /dev/null
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-audsys-clk.h  --  Mediatek 8186 audsys clock control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-audsys-clk.h"
+#include "mt8186-audsys-clkid.h"
+#include "mt8186-reg.h"
+
+struct afe_gate {
+       int id;
+       const char *name;
+       const char *parent_name;
+       int reg;
+       u8 bit;
+       const struct clk_ops *ops;
+       unsigned long flags;
+       u8 cg_flags;
+};
+
+#define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
+               .id = _id,                                      \
+               .name = _name,                                  \
+               .parent_name = _parent,                         \
+               .reg = _reg,                                    \
+               .bit = _bit,                                    \
+               .flags = _flags,                                \
+               .cg_flags = _cgflags,                           \
+       }
+
+#define GATE_AFE(_id, _name, _parent, _reg, _bit)              \
+       GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit,         \
+                      CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE)
+
+#define GATE_AUD0(_id, _name, _parent, _bit)                   \
+       GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
+
+#define GATE_AUD1(_id, _name, _parent, _bit)                   \
+       GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
+
+#define GATE_AUD2(_id, _name, _parent, _bit)                   \
+       GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit)
+
+static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
+       /* AUD0 */
+       GATE_AUD0(CLK_AUD_AFE, "aud_afe_clk", "top_audio", 2),
+       GATE_AUD0(CLK_AUD_22M, "aud_apll22m_clk", "top_aud_engen1", 8),
+       GATE_AUD0(CLK_AUD_24M, "aud_apll24m_clk", "top_aud_engen2", 9),
+       GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner_clk", "top_aud_engen2", 18),
+       GATE_AUD0(CLK_AUD_APLL_TUNER, "aud_apll_tuner_clk", "top_aud_engen1", 19),
+       GATE_AUD0(CLK_AUD_TDM, "aud_tdm_clk", "top_aud_1", 20),
+       GATE_AUD0(CLK_AUD_ADC, "aud_adc_clk", "top_audio", 24),
+       GATE_AUD0(CLK_AUD_DAC, "aud_dac_clk", "top_audio", 25),
+       GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis_clk", "top_audio", 26),
+       GATE_AUD0(CLK_AUD_TML, "aud_tml_clk", "top_audio", 27),
+       GATE_AUD0(CLK_AUD_NLE, "aud_nle_clk", "top_audio", 28),
+
+       /* AUD1 */
+       GATE_AUD1(CLK_AUD_I2S1_BCLK, "aud_i2s1_bclk", "top_audio", 4),
+       GATE_AUD1(CLK_AUD_I2S2_BCLK, "aud_i2s2_bclk", "top_audio", 5),
+       GATE_AUD1(CLK_AUD_I2S3_BCLK, "aud_i2s3_bclk", "top_audio", 6),
+       GATE_AUD1(CLK_AUD_I2S4_BCLK, "aud_i2s4_bclk", "top_audio", 7),
+       GATE_AUD1(CLK_AUD_CONNSYS_I2S_ASRC, "aud_connsys_i2s_asrc", "top_audio", 12),
+       GATE_AUD1(CLK_AUD_GENERAL1_ASRC, "aud_general1_asrc", "top_audio", 13),
+       GATE_AUD1(CLK_AUD_GENERAL2_ASRC, "aud_general2_asrc", "top_audio", 14),
+       GATE_AUD1(CLK_AUD_DAC_HIRES, "aud_dac_hires_clk", "top_audio_h", 15),
+       GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires_clk", "top_audio_h", 16),
+       GATE_AUD1(CLK_AUD_ADC_HIRES_TML, "aud_adc_hires_tml", "top_audio_h", 17),
+       GATE_AUD1(CLK_AUD_ADDA6_ADC, "aud_adda6_adc", "top_audio", 20),
+       GATE_AUD1(CLK_AUD_ADDA6_ADC_HIRES, "aud_adda6_adc_hires", "top_audio_h", 21),
+       GATE_AUD1(CLK_AUD_3RD_DAC, "aud_3rd_dac", "top_audio", 28),
+       GATE_AUD1(CLK_AUD_3RD_DAC_PREDIS, "aud_3rd_dac_predis", "top_audio", 29),
+       GATE_AUD1(CLK_AUD_3RD_DAC_TML, "aud_3rd_dac_tml", "top_audio", 30),
+       GATE_AUD1(CLK_AUD_3RD_DAC_HIRES, "aud_3rd_dac_hires", "top_audio_h", 31),
+
+       /* AUD2 */
+       GATE_AUD2(CLK_AUD_ETDM_IN1_BCLK, "aud_etdm_in1_bclk", "top_audio", 23),
+       GATE_AUD2(CLK_AUD_ETDM_OUT1_BCLK, "aud_etdm_out1_bclk", "top_audio", 24),
+};
+
+int mt8186_audsys_clk_register(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct clk *clk;
+       struct clk_lookup *cl;
+       int i;
+
+       afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK,
+                                       sizeof(*afe_priv->lookup),
+                                       GFP_KERNEL);
+
+       if (!afe_priv->lookup)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
+               const struct afe_gate *gate = &aud_clks[i];
+
+               clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
+                                       gate->flags, afe->base_addr + gate->reg,
+                                       gate->bit, gate->cg_flags, NULL);
+
+               if (IS_ERR(clk)) {
+                       dev_err(afe->dev, "Failed to register clk %s: %ld\n",
+                               gate->name, PTR_ERR(clk));
+                       continue;
+               }
+
+               /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
+               cl = kzalloc(sizeof(*cl), GFP_KERNEL);
+               if (!cl)
+                       return -ENOMEM;
+
+               cl->clk = clk;
+               cl->con_id = gate->name;
+               cl->dev_id = dev_name(afe->dev);
+               clkdev_add(cl);
+
+               afe_priv->lookup[i] = cl;
+       }
+
+       return 0;
+}
+
+void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct clk *clk;
+       struct clk_lookup *cl;
+       int i;
+
+       if (!afe_priv)
+               return;
+
+       for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+               cl = afe_priv->lookup[i];
+               if (!cl)
+                       continue;
+
+               clk = cl->clk;
+               clk_unregister_gate(clk);
+
+               clkdev_drop(cl);
+       }
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clk.h
new file mode 100644 (file)
index 0000000..b8d6a06
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-audsys-clk.h  --  Mediatek 8186 audsys clock definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Trevor Wu <trevor.wu@mediatek.com>
+ */
+
+#ifndef _MT8186_AUDSYS_CLK_H_
+#define _MT8186_AUDSYS_CLK_H_
+
+int mt8186_audsys_clk_register(struct mtk_base_afe *afe);
+void mt8186_audsys_clk_unregister(struct mtk_base_afe *afe);
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h b/sound/soc/mediatek/mt8186/mt8186-audsys-clkid.h
new file mode 100644 (file)
index 0000000..3ce5937
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-audsys-clkid.h  --  Mediatek 8186 audsys clock id definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_AUDSYS_CLKID_H_
+#define _MT8186_AUDSYS_CLKID_H_
+
+enum{
+       CLK_AUD_AFE,
+       CLK_AUD_22M,
+       CLK_AUD_24M,
+       CLK_AUD_APLL2_TUNER,
+       CLK_AUD_APLL_TUNER,
+       CLK_AUD_TDM,
+       CLK_AUD_ADC,
+       CLK_AUD_DAC,
+       CLK_AUD_DAC_PREDIS,
+       CLK_AUD_TML,
+       CLK_AUD_NLE,
+       CLK_AUD_I2S1_BCLK,
+       CLK_AUD_I2S2_BCLK,
+       CLK_AUD_I2S3_BCLK,
+       CLK_AUD_I2S4_BCLK,
+       CLK_AUD_CONNSYS_I2S_ASRC,
+       CLK_AUD_GENERAL1_ASRC,
+       CLK_AUD_GENERAL2_ASRC,
+       CLK_AUD_DAC_HIRES,
+       CLK_AUD_ADC_HIRES,
+       CLK_AUD_ADC_HIRES_TML,
+       CLK_AUD_ADDA6_ADC,
+       CLK_AUD_ADDA6_ADC_HIRES,
+       CLK_AUD_3RD_DAC,
+       CLK_AUD_3RD_DAC_PREDIS,
+       CLK_AUD_3RD_DAC_TML,
+       CLK_AUD_3RD_DAC_HIRES,
+       CLK_AUD_ETDM_IN1_BCLK,
+       CLK_AUD_ETDM_OUT1_BCLK,
+       CLK_AUD_NR_CLK,
+};
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-adda.c b/sound/soc/mediatek/mt8186/mt8186-dai-adda.c
new file mode 100644 (file)
index 0000000..2667045
--- /dev/null
@@ -0,0 +1,865 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI ADDA Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+enum {
+       UL_IIR_SW = 0,
+       UL_IIR_5HZ,
+       UL_IIR_10HZ,
+       UL_IIR_25HZ,
+       UL_IIR_50HZ,
+       UL_IIR_75HZ,
+};
+
+enum {
+       AUDIO_SDM_LEVEL_MUTE = 0,
+       AUDIO_SDM_LEVEL_NORMAL = 0x1d,
+       /* if you change level normal */
+       /* you need to change formula of hp impedance and dc trim too */
+};
+
+enum {
+       AUDIO_SDM_2ND = 0,
+       AUDIO_SDM_3RD,
+};
+
+enum {
+       DELAY_DATA_MISO1 = 0,
+       DELAY_DATA_MISO2,
+};
+
+enum {
+       MTK_AFE_ADDA_DL_RATE_8K = 0,
+       MTK_AFE_ADDA_DL_RATE_11K = 1,
+       MTK_AFE_ADDA_DL_RATE_12K = 2,
+       MTK_AFE_ADDA_DL_RATE_16K = 3,
+       MTK_AFE_ADDA_DL_RATE_22K = 4,
+       MTK_AFE_ADDA_DL_RATE_24K = 5,
+       MTK_AFE_ADDA_DL_RATE_32K = 6,
+       MTK_AFE_ADDA_DL_RATE_44K = 7,
+       MTK_AFE_ADDA_DL_RATE_48K = 8,
+       MTK_AFE_ADDA_DL_RATE_96K = 9,
+       MTK_AFE_ADDA_DL_RATE_192K = 10,
+};
+
+enum {
+       MTK_AFE_ADDA_UL_RATE_8K = 0,
+       MTK_AFE_ADDA_UL_RATE_16K = 1,
+       MTK_AFE_ADDA_UL_RATE_32K = 2,
+       MTK_AFE_ADDA_UL_RATE_48K = 3,
+       MTK_AFE_ADDA_UL_RATE_96K = 4,
+       MTK_AFE_ADDA_UL_RATE_192K = 5,
+       MTK_AFE_ADDA_UL_RATE_48K_HD = 6,
+};
+
+#define SDM_AUTO_RESET_THRESHOLD 0x190000
+
+struct mtk_afe_adda_priv {
+       int dl_rate;
+       int ul_rate;
+};
+
+static struct mtk_afe_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,
+                                                      const char *name)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id;
+
+       if (strncmp(name, "aud_dac", 7) == 0 || strncmp(name, "aud_adc", 7) == 0)
+               dai_id = MT8186_DAI_ADDA;
+       else
+               return NULL;
+
+       return afe_priv->dai_priv[dai_id];
+}
+
+static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe,
+                                          unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_ADDA_DL_RATE_8K;
+       case 11025:
+               return MTK_AFE_ADDA_DL_RATE_11K;
+       case 12000:
+               return MTK_AFE_ADDA_DL_RATE_12K;
+       case 16000:
+               return MTK_AFE_ADDA_DL_RATE_16K;
+       case 22050:
+               return MTK_AFE_ADDA_DL_RATE_22K;
+       case 24000:
+               return MTK_AFE_ADDA_DL_RATE_24K;
+       case 32000:
+               return MTK_AFE_ADDA_DL_RATE_32K;
+       case 44100:
+               return MTK_AFE_ADDA_DL_RATE_44K;
+       case 48000:
+               return MTK_AFE_ADDA_DL_RATE_48K;
+       case 96000:
+               return MTK_AFE_ADDA_DL_RATE_96K;
+       case 192000:
+               return MTK_AFE_ADDA_DL_RATE_192K;
+       default:
+               dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+                        __func__, rate);
+       }
+
+       return MTK_AFE_ADDA_DL_RATE_48K;
+}
+
+static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe,
+                                          unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_ADDA_UL_RATE_8K;
+       case 16000:
+               return MTK_AFE_ADDA_UL_RATE_16K;
+       case 32000:
+               return MTK_AFE_ADDA_UL_RATE_32K;
+       case 48000:
+               return MTK_AFE_ADDA_UL_RATE_48K;
+       case 96000:
+               return MTK_AFE_ADDA_UL_RATE_96K;
+       case 192000:
+               return MTK_AFE_ADDA_UL_RATE_192K;
+       default:
+               dev_info(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n",
+                        __func__, rate);
+       }
+
+       return MTK_AFE_ADDA_UL_RATE_48K;
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN3, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN3, I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN3, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN3, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN3_1, I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN3_1, I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN3_1, I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN3_1, I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN3,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN3,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN3,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1 Switch", AFE_CONN3,
+                                   I_PCM_2_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN3_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH1 Switch", AFE_CONN3_1,
+                                   I_SRC_2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN4, I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN4, I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN4, I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN4, I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN4, I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN4, I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN4, I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN4_1, I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN4_1, I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN4_1, I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN4_1, I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN4,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN4,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN4,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN4,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN4_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_2_OUT_CH2 Switch", AFE_CONN4_1,
+                                   I_SRC_2_OUT_CH2, 1, 0),
+};
+
+enum {
+       SUPPLY_SEQ_ADDA_AFE_ON,
+       SUPPLY_SEQ_ADDA_DL_ON,
+       SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+       SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+       SUPPLY_SEQ_ADDA_FIFO,
+       SUPPLY_SEQ_ADDA_AP_DMIC,
+       SUPPLY_SEQ_ADDA_UL_ON,
+};
+
+static int mtk_adda_ul_src_dmic(struct mtk_base_afe *afe, int id)
+{
+       unsigned int reg;
+
+       switch (id) {
+       case MT8186_DAI_ADDA:
+       case MT8186_DAI_AP_DMIC:
+               reg = AFE_ADDA_UL_SRC_CON0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* dmic mode, 3.25M*/
+       regmap_update_bits(afe->regmap, reg,
+                          DIGMIC_3P25M_1P625M_SEL_MASK_SFT, 0);
+       regmap_update_bits(afe->regmap, reg,
+                          DMIC_LOW_POWER_CTL_MASK_SFT, 0);
+
+       /* turn on dmic, ch1, ch2 */
+       regmap_update_bits(afe->regmap, reg,
+                          UL_SDM_3_LEVEL_MASK_SFT,
+                          BIT(UL_SDM_3_LEVEL_SFT));
+       regmap_update_bits(afe->regmap, reg,
+                          UL_MODE_3P25M_CH1_CTL_MASK_SFT,
+                          BIT(UL_MODE_3P25M_CH1_CTL_SFT));
+       regmap_update_bits(afe->regmap, reg,
+                          UL_MODE_3P25M_CH2_CTL_MASK_SFT,
+                          BIT(UL_MODE_3P25M_CH2_CTL_SFT));
+
+       return 0;
+}
+
+static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int mtkaif_dmic = afe_priv->mtkaif_dmic;
+
+       dev_dbg(afe->dev, "%s(), name %s, event 0x%x, mtkaif_dmic %d\n",
+               __func__, w->name, event, mtkaif_dmic);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 1);
+
+               /* update setting to dmic */
+               if (mtkaif_dmic) {
+                       /* mtkaif_rxif_data_mode = 1, dmic */
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+                                          0x1, 0x1);
+
+                       /* dmic mode, 3.25M*/
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0,
+                                          MTKAIF_RXIF_VOICE_MODE_MASK_SFT,
+                                          0x0);
+                       mtk_adda_ul_src_dmic(afe, MT8186_DAI_ADDA);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+               usleep_range(125, 135);
+               mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 1);
+
+               /* reset dmic */
+               afe_priv->mtkaif_dmic = 0;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
+                                 struct snd_kcontrol *kcontrol,
+                                 int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
+                       regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39);
+               else
+                       regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_mtkaif_cfg_event(struct snd_soc_dapm_widget *w,
+                                    struct snd_kcontrol *kcontrol,
+                                    int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int delay_data;
+       int delay_cycle;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2) {
+                       /* set protocol 2 */
+                       regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000);
+                       /* mtkaif_rxif_clkinv_adc inverse */
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_CFG0,
+                                          MTKAIF_RXIF_CLKINV_ADC_MASK_SFT,
+                                          BIT(MTKAIF_RXIF_CLKINV_ADC_SFT));
+
+                       if (strcmp(w->name, "ADDA_MTKAIF_CFG") == 0) {
+                               if (afe_priv->mtkaif_chosen_phase[0] < 0 &&
+                                   afe_priv->mtkaif_chosen_phase[1] < 0) {
+                                       dev_err(afe->dev,
+                                               "%s(), calib fail mtkaif_chosen_phase[0/1]:%d/%d\n",
+                                               __func__,
+                                               afe_priv->mtkaif_chosen_phase[0],
+                                               afe_priv->mtkaif_chosen_phase[1]);
+                                       break;
+                               }
+
+                               if (afe_priv->mtkaif_chosen_phase[0] < 0 ||
+                                   afe_priv->mtkaif_chosen_phase[1] < 0) {
+                                       dev_err(afe->dev,
+                                               "%s(), skip delay setting mtkaif_chosen_phase[0/1]:%d/%d\n",
+                                               __func__,
+                                               afe_priv->mtkaif_chosen_phase[0],
+                                               afe_priv->mtkaif_chosen_phase[1]);
+                                       break;
+                               }
+                       }
+
+                       /* set delay for ch12 */
+                       if (afe_priv->mtkaif_phase_cycle[0] >=
+                           afe_priv->mtkaif_phase_cycle[1]) {
+                               delay_data = DELAY_DATA_MISO1;
+                               delay_cycle = afe_priv->mtkaif_phase_cycle[0] -
+                                             afe_priv->mtkaif_phase_cycle[1];
+                       } else {
+                               delay_data = DELAY_DATA_MISO2;
+                               delay_cycle = afe_priv->mtkaif_phase_cycle[1] -
+                                             afe_priv->mtkaif_phase_cycle[0];
+                       }
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_RX_CFG2,
+                                          MTKAIF_RXIF_DELAY_DATA_MASK_SFT,
+                                          delay_data <<
+                                          MTKAIF_RXIF_DELAY_DATA_SFT);
+
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_MTKAIF_RX_CFG2,
+                                          MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT,
+                                          delay_cycle <<
+                                          MTKAIF_RXIF_DELAY_CYCLE_SFT);
+
+               } else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2) {
+                       regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x10000);
+               } else {
+                       regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0);
+               }
+
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_adda_dl_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_ADDA, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+               usleep_range(125, 135);
+               mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_ADDA, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mt8186_adda_dmic_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic;
+
+       return 0;
+}
+
+static int mt8186_adda_dmic_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dmic_on;
+
+       dmic_on = ucontrol->value.integer.value[0];
+
+       dev_dbg(afe->dev, "%s(), kcontrol name %s, dmic_on %d\n",
+               __func__, kcontrol->id.name, dmic_on);
+
+       if (afe_priv->mtkaif_dmic == dmic_on)
+               return 0;
+
+       afe_priv->mtkaif_dmic = dmic_on;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new mtk_adda_controls[] = {
+       SOC_SINGLE("ADDA_DL_GAIN", AFE_ADDA_DL_SRC2_CON1,
+                  DL_2_GAIN_CTL_PRE_SFT, DL_2_GAIN_CTL_PRE_MASK, 0),
+       SOC_SINGLE_BOOL_EXT("MTKAIF_DMIC Switch", 0,
+                           mt8186_adda_dmic_get, mt8186_adda_dmic_set),
+};
+
+/* ADDA UL MUX */
+enum {
+       ADDA_UL_MUX_MTKAIF = 0,
+       ADDA_UL_MUX_AP_DMIC,
+       ADDA_UL_MUX_MASK = 0x1,
+};
+
+static const char * const adda_ul_mux_map[] = {
+       "MTKAIF", "AP_DMIC"
+};
+
+static int adda_ul_map_value[] = {
+       ADDA_UL_MUX_MTKAIF,
+       ADDA_UL_MUX_AP_DMIC,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(adda_ul_mux_map_enum,
+                                 SND_SOC_NOPM,
+                                 0,
+                                 ADDA_UL_MUX_MASK,
+                                 adda_ul_mux_map,
+                                 adda_ul_map_value);
+
+static const struct snd_kcontrol_new adda_ul_mux_control =
+       SOC_DAPM_ENUM("ADDA_UL_MUX Select", adda_ul_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_adda_dl_ch1_mix,
+                          ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
+       SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_adda_dl_ch2_mix,
+                          ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON,
+                             AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0,
+                             NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON,
+                             AFE_ADDA_DL_SRC2_CON0,
+                             DL_2_SRC_ON_CTL_PRE_SFT, 0,
+                             mtk_adda_dl_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON,
+                             AFE_ADDA_UL_SRC_CON0,
+                             UL_SRC_ON_CTL_SFT, 0,
+                             mtk_adda_ul_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("AUD_PAD_TOP", SUPPLY_SEQ_ADDA_AUD_PAD_TOP,
+                             0, 0, 0,
+                             mtk_adda_pad_top_event,
+                             SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY_S("ADDA_MTKAIF_CFG", SUPPLY_SEQ_ADDA_MTKAIF_CFG,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_adda_mtkaif_cfg_event,
+                             SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_SUPPLY_S("AP_DMIC_EN", SUPPLY_SEQ_ADDA_AP_DMIC,
+                             AFE_ADDA_UL_SRC_CON0,
+                             UL_AP_DMIC_ON_SFT, 0,
+                             NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY_S("ADDA_FIFO", SUPPLY_SEQ_ADDA_FIFO,
+                             AFE_ADDA_UL_DL_CON0,
+                             AFE_ADDA_FIFO_AUTO_RST_SFT, 1,
+                             NULL, 0),
+
+       SND_SOC_DAPM_MUX("ADDA_UL_Mux", SND_SOC_NOPM, 0, 0,
+                        &adda_ul_mux_control),
+
+       SND_SOC_DAPM_INPUT("AP_DMIC_INPUT"),
+
+       /* clock */
+       SND_SOC_DAPM_CLOCK_SUPPLY("top_mux_audio_h"),
+
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_hires_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"),
+
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"),
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_hires_clk"),
+};
+
+#define HIRES_THRESHOLD 48000
+static int mtk_afe_dac_hires_connect(struct snd_soc_dapm_widget *source,
+                                    struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = source;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_adda_priv *adda_priv;
+
+       adda_priv = get_adda_priv_by_name(afe, w->name);
+
+       if (!adda_priv) {
+               dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
+               return 0;
+       }
+
+       return (adda_priv->dl_rate > HIRES_THRESHOLD) ? 1 : 0;
+}
+
+static int mtk_afe_adc_hires_connect(struct snd_soc_dapm_widget *source,
+                                    struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = source;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_adda_priv *adda_priv;
+
+       adda_priv = get_adda_priv_by_name(afe, w->name);
+
+       if (!adda_priv) {
+               dev_err(afe->dev, "%s(), adda_priv == NULL", __func__);
+               return 0;
+       }
+
+       return (adda_priv->ul_rate > HIRES_THRESHOLD) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
+       /* playback */
+       {"ADDA_DL_CH1", "DL1_CH1 Switch", "DL1"},
+       {"ADDA_DL_CH2", "DL1_CH1 Switch", "DL1"},
+       {"ADDA_DL_CH2", "DL1_CH2 Switch", "DL1"},
+
+       {"ADDA_DL_CH1", "DL12_CH1 Switch", "DL12"},
+       {"ADDA_DL_CH2", "DL12_CH2 Switch", "DL12"},
+
+       {"ADDA_DL_CH1", "DL6_CH1 Switch", "DL6"},
+       {"ADDA_DL_CH2", "DL6_CH2 Switch", "DL6"},
+
+       {"ADDA_DL_CH1", "DL8_CH1 Switch", "DL8"},
+       {"ADDA_DL_CH2", "DL8_CH2 Switch", "DL8"},
+
+       {"ADDA_DL_CH1", "DL2_CH1 Switch", "DL2"},
+       {"ADDA_DL_CH2", "DL2_CH1 Switch", "DL2"},
+       {"ADDA_DL_CH2", "DL2_CH2 Switch", "DL2"},
+
+       {"ADDA_DL_CH1", "DL3_CH1 Switch", "DL3"},
+       {"ADDA_DL_CH2", "DL3_CH1 Switch", "DL3"},
+       {"ADDA_DL_CH2", "DL3_CH2 Switch", "DL3"},
+
+       {"ADDA_DL_CH1", "DL4_CH1 Switch", "DL4"},
+       {"ADDA_DL_CH2", "DL4_CH2 Switch", "DL4"},
+
+       {"ADDA_DL_CH1", "DL5_CH1 Switch", "DL5"},
+       {"ADDA_DL_CH2", "DL5_CH2 Switch", "DL5"},
+
+       {"ADDA Playback", NULL, "ADDA_DL_CH1"},
+       {"ADDA Playback", NULL, "ADDA_DL_CH2"},
+
+       {"ADDA Playback", NULL, "ADDA Enable"},
+       {"ADDA Playback", NULL, "ADDA Playback Enable"},
+
+       /* capture */
+       {"ADDA_UL_Mux", "MTKAIF", "ADDA Capture"},
+       {"ADDA_UL_Mux", "AP_DMIC", "AP DMIC Capture"},
+
+       {"ADDA Capture", NULL, "ADDA Enable"},
+       {"ADDA Capture", NULL, "ADDA Capture Enable"},
+       {"ADDA Capture", NULL, "AUD_PAD_TOP"},
+       {"ADDA Capture", NULL, "ADDA_MTKAIF_CFG"},
+
+       {"AP DMIC Capture", NULL, "ADDA Enable"},
+       {"AP DMIC Capture", NULL, "ADDA Capture Enable"},
+       {"AP DMIC Capture", NULL, "ADDA_FIFO"},
+       {"AP DMIC Capture", NULL, "AP_DMIC_EN"},
+
+       {"AP DMIC Capture", NULL, "AP_DMIC_INPUT"},
+
+       /* clk */
+       {"ADDA Playback", NULL, "aud_dac_clk"},
+       {"ADDA Playback", NULL, "aud_dac_predis_clk"},
+       {"ADDA Playback", NULL, "aud_dac_hires_clk", mtk_afe_dac_hires_connect},
+
+       {"ADDA Capture Enable", NULL, "aud_adc_clk"},
+       {"ADDA Capture Enable", NULL, "aud_adc_hires_clk",
+        mtk_afe_adc_hires_connect},
+
+       /* hires source from apll1 */
+       {"top_mux_audio_h", NULL, APLL2_W_NAME},
+
+       {"aud_dac_hires_clk", NULL, "top_mux_audio_h"},
+       {"aud_adc_hires_clk", NULL, "top_mux_audio_h"},
+};
+
+/* dai ops */
+static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       unsigned int rate = params_rate(params);
+       int id = dai->id;
+       struct mtk_afe_adda_priv *adda_priv = afe_priv->dai_priv[id];
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+               __func__, id, substream->stream, rate);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               unsigned int dl_src2_con0;
+               unsigned int dl_src2_con1;
+
+               adda_priv->dl_rate = rate;
+
+               /* set sampling rate */
+               dl_src2_con0 = adda_dl_rate_transform(afe, rate) <<
+                              DL_2_INPUT_MODE_CTL_SFT;
+
+               /* set output mode, UP_SAMPLING_RATE_X8 */
+               dl_src2_con0 |= (0x3 << DL_2_OUTPUT_SEL_CTL_SFT);
+
+               /* turn off mute function */
+               dl_src2_con0 |= BIT(DL_2_MUTE_CH2_OFF_CTL_PRE_SFT);
+               dl_src2_con0 |= BIT(DL_2_MUTE_CH1_OFF_CTL_PRE_SFT);
+
+               /* set voice input data if input sample rate is 8k or 16k */
+               if (rate == 8000 || rate == 16000)
+                       dl_src2_con0 |= BIT(DL_2_VOICE_MODE_CTL_PRE_SFT);
+
+               /* SA suggest apply -0.3db to audio/speech path */
+               dl_src2_con1 = MTK_AFE_ADDA_DL_GAIN_NORMAL <<
+                              DL_2_GAIN_CTL_PRE_SFT;
+
+               /* turn on down-link gain */
+               dl_src2_con0 |= BIT(DL_2_GAIN_ON_CTL_PRE_SFT);
+
+               if (id == MT8186_DAI_ADDA) {
+                       /* clean predistortion */
+                       regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0);
+                       regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0);
+
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_DL_SRC2_CON0, dl_src2_con0);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_DL_SRC2_CON1, dl_src2_con1);
+
+                       /* set sdm gain */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_DCCOMP_CON,
+                                          ATTGAIN_CTL_MASK_SFT,
+                                          AUDIO_SDM_LEVEL_NORMAL <<
+                                          ATTGAIN_CTL_SFT);
+
+                       /* Use new 2nd sdm */
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_DITHER_CON,
+                                          AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT,
+                                          BIT(AFE_DL_SDM_DITHER_64TAP_EN_SFT));
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+                                          AFE_DL_USE_NEW_2ND_SDM_MASK_SFT,
+                                          BIT(AFE_DL_USE_NEW_2ND_SDM_SFT));
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_DCCOMP_CON,
+                                          USE_3RD_SDM_MASK_SFT,
+                                          AUDIO_SDM_2ND << USE_3RD_SDM_SFT);
+
+                       /* sdm auto reset */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+                                    SDM_AUTO_RESET_THRESHOLD);
+                       regmap_update_bits(afe->regmap,
+                                          AFE_ADDA_DL_SDM_AUTO_RESET_CON,
+                                          SDM_AUTO_RESET_TEST_ON_MASK_SFT,
+                                          BIT(SDM_AUTO_RESET_TEST_ON_SFT));
+               }
+       } else {
+               unsigned int ul_src_con0 = 0;
+               unsigned int voice_mode = adda_ul_rate_transform(afe, rate);
+
+               adda_priv->ul_rate = rate;
+               ul_src_con0 |= (voice_mode << 17) & (0x7 << 17);
+
+               /* enable iir */
+               ul_src_con0 |= (1 << UL_IIR_ON_TMP_CTL_SFT) &
+                              UL_IIR_ON_TMP_CTL_MASK_SFT;
+               ul_src_con0 |= (UL_IIR_SW << UL_IIRMODE_CTL_SFT) &
+                              UL_IIRMODE_CTL_MASK_SFT;
+               switch (id) {
+               case MT8186_DAI_ADDA:
+               case MT8186_DAI_AP_DMIC:
+                       /* 35Hz @ 48k */
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_02_01, 0);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_04_03, 0x3fb8);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_06_05, 0x3fb80000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_08_07, 0x3fb80000);
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_IIR_COEF_10_09, 0xc048);
+
+                       regmap_write(afe->regmap,
+                                    AFE_ADDA_UL_SRC_CON0, ul_src_con0);
+
+                       /* Using Internal ADC */
+                       regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, BIT(0), 0);
+
+                       /* mtkaif_rxif_data_mode = 0, amic */
+                       regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, BIT(0), 0);
+                       break;
+               default:
+                       break;
+               }
+
+               /* ap dmic */
+               switch (id) {
+               case MT8186_DAI_AP_DMIC:
+                       mtk_adda_ul_src_dmic(afe, id);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_adda_ops = {
+       .hw_params = mtk_dai_adda_hw_params,
+};
+
+/* dai driver */
+#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                                SNDRV_PCM_RATE_96000 |\
+                                SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+                               SNDRV_PCM_RATE_16000 |\
+                               SNDRV_PCM_RATE_32000 |\
+                               SNDRV_PCM_RATE_48000 |\
+                               SNDRV_PCM_RATE_96000 |\
+                               SNDRV_PCM_RATE_192000)
+
+#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                         SNDRV_PCM_FMTBIT_S24_LE |\
+                         SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
+       {
+               .name = "ADDA",
+               .id = MT8186_DAI_ADDA,
+               .playback = {
+                       .stream_name = "ADDA Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_PLAYBACK_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ADDA Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_CAPTURE_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .ops = &mtk_dai_adda_ops,
+       },
+       {
+               .name = "AP_DMIC",
+               .id = MT8186_DAI_AP_DMIC,
+               .capture = {
+                       .stream_name = "AP DMIC Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ADDA_CAPTURE_RATES,
+                       .formats = MTK_ADDA_FORMATS,
+               },
+               .ops = &mtk_dai_adda_ops,
+       },
+};
+
+int mt8186_dai_adda_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_adda_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+       dai->controls = mtk_adda_controls;
+       dai->num_controls = ARRAY_SIZE(mtk_adda_controls);
+       dai->dapm_widgets = mtk_dai_adda_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+       dai->dapm_routes = mtk_dai_adda_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+
+       /* set dai priv */
+       ret = mt8186_dai_set_priv(afe, MT8186_DAI_ADDA,
+                                 sizeof(struct mtk_afe_adda_priv), NULL);
+       if (ret)
+               return ret;
+
+       /* ap dmic priv share with adda */
+       afe_priv->dai_priv[MT8186_DAI_AP_DMIC] =
+               afe_priv->dai_priv[MT8186_DAI_ADDA];
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c b/sound/soc/mediatek/mt8186/mt8186-dai-hostless.c
new file mode 100644 (file)
index 0000000..bf0d838
--- /dev/null
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI Hostless Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include "mt8186-afe-common.h"
+
+static const struct snd_pcm_hardware mt8186_hostless_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_MMAP_VALID),
+       .period_bytes_min = 256,
+       .period_bytes_max = 4 * 48 * 1024,
+       .periods_min = 2,
+       .periods_max = 256,
+       .buffer_bytes_max = 4 * 48 * 1024,
+       .fifo_size = 0,
+};
+
+/* dai component */
+static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = {
+       /* Hostless ADDA Loopback */
+       {"ADDA_DL_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+       {"ADDA_DL_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+       {"ADDA_DL_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+       {"ADDA_DL_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+       {"I2S1_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+       {"I2S1_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+       {"I2S3_CH1", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+       {"I2S3_CH1", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+       {"I2S3_CH2", "ADDA_UL_CH1 Switch", "Hostless LPBK DL"},
+       {"I2S3_CH2", "ADDA_UL_CH2 Switch", "Hostless LPBK DL"},
+       {"Hostless LPBK UL", NULL, "ADDA_UL_Mux"},
+
+       /* Hostelss FM */
+       /* connsys_i2s to hw gain 1*/
+       {"Hostless FM UL", NULL, "Connsys I2S"},
+
+       {"HW_GAIN1_IN_CH1", "CONNSYS_I2S_CH1 Switch", "Hostless FM DL"},
+       {"HW_GAIN1_IN_CH2", "CONNSYS_I2S_CH2 Switch", "Hostless FM DL"},
+       /* hw gain to adda dl */
+       {"Hostless FM UL", NULL, "HW Gain 1 Out"},
+
+       {"ADDA_DL_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
+       {"ADDA_DL_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
+       /* hw gain to i2s3 */
+       {"I2S3_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
+       {"I2S3_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
+       /* hw gain to i2s1 */
+       {"I2S1_CH1", "GAIN1_OUT_CH1 Switch", "Hostless FM DL"},
+       {"I2S1_CH2", "GAIN1_OUT_CH2 Switch", "Hostless FM DL"},
+
+       /* Hostless_SRC */
+       {"ADDA_DL_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
+       {"ADDA_DL_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
+       {"I2S1_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
+       {"I2S1_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
+       {"I2S3_CH1", "SRC_1_OUT_CH1 Switch", "Hostless_SRC_1_DL"},
+       {"I2S3_CH2", "SRC_1_OUT_CH2 Switch", "Hostless_SRC_1_DL"},
+       {"Hostless_SRC_1_UL", NULL, "HW_SRC_1_Out"},
+
+       /* Hostless_SRC_bargein */
+       {"HW_SRC_1_IN_CH1", "I2S0_CH1 Switch", "Hostless_SRC_Bargein_DL"},
+       {"HW_SRC_1_IN_CH2", "I2S0_CH2 Switch", "Hostless_SRC_Bargein_DL"},
+       {"Hostless_SRC_Bargein_UL", NULL, "I2S0"},
+
+       /* Hostless AAudio */
+       {"Hostless HW Gain AAudio In", NULL, "HW Gain 2 In"},
+       {"Hostless SRC AAudio UL", NULL, "HW Gain 2 Out"},
+       {"HW_SRC_2_IN_CH1", "HW_GAIN2_OUT_CH1 Switch", "Hostless SRC AAudio DL"},
+       {"HW_SRC_2_IN_CH2", "HW_GAIN2_OUT_CH2 Switch", "Hostless SRC AAudio DL"},
+};
+
+/* dai ops */
+static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream,
+                                   struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       snd_soc_set_runtime_hwparams(substream, &mt8186_hostless_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_hostless_ops = {
+       .startup = mtk_dai_hostless_startup,
+};
+
+/* dai driver */
+#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                          SNDRV_PCM_RATE_88200 |\
+                          SNDRV_PCM_RATE_96000 |\
+                          SNDRV_PCM_RATE_176400 |\
+                          SNDRV_PCM_RATE_192000)
+
+#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                            SNDRV_PCM_FMTBIT_S24_LE |\
+                            SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
+       {
+               .name = "Hostless LPBK DAI",
+               .id = MT8186_DAI_HOSTLESS_LPBK,
+               .playback = {
+                       .stream_name = "Hostless LPBK DL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Hostless LPBK UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless FM DAI",
+               .id = MT8186_DAI_HOSTLESS_FM,
+               .playback = {
+                       .stream_name = "Hostless FM DL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Hostless FM UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless_SRC_1_DAI",
+               .id = MT8186_DAI_HOSTLESS_SRC_1,
+               .playback = {
+                       .stream_name = "Hostless_SRC_1_DL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Hostless_SRC_1_UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless_SRC_Bargein_DAI",
+               .id = MT8186_DAI_HOSTLESS_SRC_BARGEIN,
+               .playback = {
+                       .stream_name = "Hostless_SRC_Bargein_DL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Hostless_SRC_Bargein_UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       /* BE dai */
+       {
+               .name = "Hostless_UL1 DAI",
+               .id = MT8186_DAI_HOSTLESS_UL1,
+               .capture = {
+                       .stream_name = "Hostless_UL1 UL",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless_UL2 DAI",
+               .id = MT8186_DAI_HOSTLESS_UL2,
+               .capture = {
+                       .stream_name = "Hostless_UL2 UL",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless_UL3 DAI",
+               .id = MT8186_DAI_HOSTLESS_UL3,
+               .capture = {
+                       .stream_name = "Hostless_UL3 UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless_UL5 DAI",
+               .id = MT8186_DAI_HOSTLESS_UL5,
+               .capture = {
+                       .stream_name = "Hostless_UL5 UL",
+                       .channels_min = 1,
+                       .channels_max = 12,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless_UL6 DAI",
+               .id = MT8186_DAI_HOSTLESS_UL6,
+               .capture = {
+                       .stream_name = "Hostless_UL6 UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless HW Gain AAudio DAI",
+               .id = MT8186_DAI_HOSTLESS_HW_GAIN_AAUDIO,
+               .capture = {
+                       .stream_name = "Hostless HW Gain AAudio In",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+       {
+               .name = "Hostless SRC AAudio DAI",
+               .id = MT8186_DAI_HOSTLESS_SRC_AAUDIO,
+               .playback = {
+                       .stream_name = "Hostless SRC AAudio DL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Hostless SRC AAudio UL",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HOSTLESS_RATES,
+                       .formats = MTK_HOSTLESS_FORMATS,
+               },
+               .ops = &mtk_dai_hostless_ops,
+       },
+};
+
+int mt8186_dai_hostless_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_hostless_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+       dai->dapm_routes = mtk_dai_hostless_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c b/sound/soc/mediatek/mt8186/mt8186-dai-hw-gain.c
new file mode 100644 (file)
index 0000000..33edd6c
--- /dev/null
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI HW Gain Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-interconnection.h"
+
+#define HW_GAIN_1_EN_W_NAME "HW GAIN 1 Enable"
+#define HW_GAIN_2_EN_W_NAME "HW GAIN 2 Enable"
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH1 Switch", AFE_CONN13_1,
+                                   I_CONNSYS_I2S_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain1_in_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("CONNSYS_I2S_CH2 Switch", AFE_CONN14_1,
+                                   I_CONNSYS_I2S_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain2_in_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN15,
+                                   I_ADDA_UL_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain2_in_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN16,
+                                   I_ADDA_UL_CH2, 1, 0),
+};
+
+static int mtk_hw_gain_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int gain_cur;
+       unsigned int gain_con1;
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (strcmp(w->name, HW_GAIN_1_EN_W_NAME) == 0) {
+                       gain_cur = AFE_GAIN1_CUR;
+                       gain_con1 = AFE_GAIN1_CON1;
+               } else {
+                       gain_cur = AFE_GAIN2_CUR;
+                       gain_con1 = AFE_GAIN2_CON1;
+               }
+
+               /* let hw gain ramp up, set cur gain to 0 */
+               regmap_update_bits(afe->regmap, gain_cur, AFE_GAIN1_CUR_MASK_SFT, 0);
+
+               /* set target gain to 0 */
+               regmap_update_bits(afe->regmap, gain_con1, GAIN1_TARGET_MASK_SFT, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_hw_gain_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_gain1_in_ch1_mix,
+                          ARRAY_SIZE(mtk_hw_gain1_in_ch1_mix)),
+       SND_SOC_DAPM_MIXER("HW_GAIN1_IN_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_gain1_in_ch2_mix,
+                          ARRAY_SIZE(mtk_hw_gain1_in_ch2_mix)),
+       SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_gain2_in_ch1_mix,
+                          ARRAY_SIZE(mtk_hw_gain2_in_ch1_mix)),
+       SND_SOC_DAPM_MIXER("HW_GAIN2_IN_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_gain2_in_ch2_mix,
+                          ARRAY_SIZE(mtk_hw_gain2_in_ch2_mix)),
+
+       SND_SOC_DAPM_SUPPLY(HW_GAIN_1_EN_W_NAME,
+                           AFE_GAIN1_CON0, GAIN1_ON_SFT, 0,
+                           mtk_hw_gain_event,
+                           SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_SUPPLY(HW_GAIN_2_EN_W_NAME,
+                           AFE_GAIN2_CON0, GAIN2_ON_SFT, 0,
+                           mtk_hw_gain_event,
+                           SND_SOC_DAPM_PRE_PMU),
+
+       SND_SOC_DAPM_INPUT("HW Gain 1 Out Endpoint"),
+       SND_SOC_DAPM_INPUT("HW Gain 2 Out Endpoint"),
+       SND_SOC_DAPM_OUTPUT("HW Gain 1 In Endpoint"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_hw_gain_routes[] = {
+       {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH1"},
+       {"HW Gain 1 In", NULL, "HW_GAIN1_IN_CH2"},
+       {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH1"},
+       {"HW Gain 2 In", NULL, "HW_GAIN2_IN_CH2"},
+
+       {"HW Gain 1 In", NULL, HW_GAIN_1_EN_W_NAME},
+       {"HW Gain 1 Out", NULL, HW_GAIN_1_EN_W_NAME},
+       {"HW Gain 2 In", NULL, HW_GAIN_2_EN_W_NAME},
+       {"HW Gain 2 Out", NULL, HW_GAIN_2_EN_W_NAME},
+
+       {"HW Gain 1 In Endpoint", NULL, "HW Gain 1 In"},
+       {"HW Gain 1 Out", NULL, "HW Gain 1 Out Endpoint"},
+       {"HW Gain 2 Out", NULL, "HW Gain 2 Out Endpoint"},
+};
+
+static const struct snd_kcontrol_new mtk_hw_gain_controls[] = {
+       SOC_SINGLE("HW Gain 1 Volume", AFE_GAIN1_CON1,
+                  GAIN1_TARGET_SFT, GAIN1_TARGET_MASK, 0),
+       SOC_SINGLE("HW Gain 2 Volume", AFE_GAIN2_CON1,
+                  GAIN2_TARGET_SFT, GAIN2_TARGET_MASK, 0),
+};
+
+/* dai ops */
+static int mtk_dai_gain_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+               __func__, dai->id, substream->stream, rate);
+
+       /* rate */
+       regmap_update_bits(afe->regmap,
+                          dai->id == MT8186_DAI_HW_GAIN_1 ?
+                          AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
+                          GAIN1_MODE_MASK_SFT,
+                          rate_reg << GAIN1_MODE_SFT);
+
+       /* sample per step */
+       regmap_update_bits(afe->regmap,
+                          dai->id == MT8186_DAI_HW_GAIN_1 ?
+                          AFE_GAIN1_CON0 : AFE_GAIN2_CON0,
+                          GAIN1_SAMPLE_PER_STEP_MASK_SFT,
+                          (dai->id == MT8186_DAI_HW_GAIN_1 ? 0x40 : 0x0) <<
+                          GAIN1_SAMPLE_PER_STEP_SFT);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_gain_ops = {
+       .hw_params = mtk_dai_gain_hw_params,
+};
+
+/* dai driver */
+#define MTK_HW_GAIN_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                          SNDRV_PCM_RATE_88200 |\
+                          SNDRV_PCM_RATE_96000 |\
+                          SNDRV_PCM_RATE_176400 |\
+                          SNDRV_PCM_RATE_192000)
+
+#define MTK_HW_GAIN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                            SNDRV_PCM_FMTBIT_S24_LE |\
+                            SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_gain_driver[] = {
+       {
+               .name = "HW Gain 1",
+               .id = MT8186_DAI_HW_GAIN_1,
+               .playback = {
+                       .stream_name = "HW Gain 1 In",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HW_GAIN_RATES,
+                       .formats = MTK_HW_GAIN_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "HW Gain 1 Out",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HW_GAIN_RATES,
+                       .formats = MTK_HW_GAIN_FORMATS,
+               },
+               .ops = &mtk_dai_gain_ops,
+               .symmetric_rate = 1,
+               .symmetric_channels = 1,
+               .symmetric_sample_bits = 1,
+       },
+       {
+               .name = "HW Gain 2",
+               .id = MT8186_DAI_HW_GAIN_2,
+               .playback = {
+                       .stream_name = "HW Gain 2 In",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HW_GAIN_RATES,
+                       .formats = MTK_HW_GAIN_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "HW Gain 2 Out",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_HW_GAIN_RATES,
+                       .formats = MTK_HW_GAIN_FORMATS,
+               },
+               .ops = &mtk_dai_gain_ops,
+               .symmetric_rate = 1,
+               .symmetric_channels = 1,
+               .symmetric_sample_bits = 1,
+       },
+};
+
+int mt8186_dai_hw_gain_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_gain_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_gain_driver);
+
+       dai->controls = mtk_hw_gain_controls;
+       dai->num_controls = ARRAY_SIZE(mtk_hw_gain_controls);
+       dai->dapm_widgets = mtk_dai_hw_gain_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_hw_gain_widgets);
+       dai->dapm_routes = mtk_dai_hw_gain_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hw_gain_routes);
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c b/sound/soc/mediatek/mt8186/mt8186-dai-i2s.c
new file mode 100644 (file)
index 0000000..ec79e2f
--- /dev/null
@@ -0,0 +1,1223 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+enum {
+       I2S_FMT_EIAJ = 0,
+       I2S_FMT_I2S = 1,
+};
+
+enum {
+       I2S_WLEN_16_BIT = 0,
+       I2S_WLEN_32_BIT = 1,
+};
+
+enum {
+       I2S_HD_NORMAL = 0,
+       I2S_HD_LOW_JITTER = 1,
+};
+
+enum {
+       I2S1_SEL_O28_O29 = 0,
+       I2S1_SEL_O03_O04 = 1,
+};
+
+enum {
+       I2S_IN_PAD_CONNSYS = 0,
+       I2S_IN_PAD_IO_MUX = 1,
+};
+
+struct mtk_afe_i2s_priv {
+       int id;
+       int rate; /* for determine which apll to use */
+       int low_jitter_en;
+       int master; /* only i2s0 has slave mode*/
+
+       const char *share_property_name;
+       int share_i2s_id;
+
+       int mclk_id;
+       int mclk_rate;
+       int mclk_apll;
+};
+
+static unsigned int get_i2s_wlen(snd_pcm_format_t format)
+{
+       return snd_pcm_format_physical_width(format) <= 16 ?
+              I2S_WLEN_16_BIT : I2S_WLEN_32_BIT;
+}
+
+#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux"
+#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux"
+#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux"
+#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux"
+#define MTK_AFE_I2S0_SRC_KCONTROL_NAME "I2S0_SRC_Mux"
+
+#define I2S0_HD_EN_W_NAME "I2S0_HD_EN"
+#define I2S1_HD_EN_W_NAME "I2S1_HD_EN"
+#define I2S2_HD_EN_W_NAME "I2S2_HD_EN"
+#define I2S3_HD_EN_W_NAME "I2S3_HD_EN"
+
+#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN"
+#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN"
+#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN"
+#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN"
+
+static int get_i2s_id_by_name(struct mtk_base_afe *afe,
+                             const char *name)
+{
+       if (strncmp(name, "I2S0", 4) == 0)
+               return MT8186_DAI_I2S_0;
+       else if (strncmp(name, "I2S1", 4) == 0)
+               return MT8186_DAI_I2S_1;
+       else if (strncmp(name, "I2S2", 4) == 0)
+               return MT8186_DAI_I2S_2;
+       else if (strncmp(name, "I2S3", 4) == 0)
+               return MT8186_DAI_I2S_3;
+
+       return -EINVAL;
+}
+
+static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe,
+                                                    const char *name)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_i2s_id_by_name(afe, name);
+
+       if (dai_id < 0)
+               return NULL;
+
+       return afe_priv->dai_priv[dai_id];
+}
+
+/* low jitter control */
+static const char * const mt8186_i2s_hd_str[] = {
+       "Normal", "Low_Jitter"
+};
+
+static const struct soc_enum mt8186_i2s_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_i2s_hd_str),
+                           mt8186_i2s_hd_str),
+};
+
+static int mt8186_i2s_hd_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+       ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en;
+
+       return 0;
+}
+
+static int mt8186_i2s_hd_set(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int hd_en;
+
+       if (ucontrol->value.enumerated.item[0] >= e->items)
+               return -EINVAL;
+
+       hd_en = ucontrol->value.integer.value[0];
+
+       dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+               __func__, kcontrol->id.name, hd_en);
+
+       i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name);
+       if (i2s_priv->low_jitter_en == hd_en)
+               return 0;
+
+       i2s_priv->low_jitter_en = hd_en;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = {
+       SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8186_i2s_enum[0],
+                    mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8186_i2s_enum[0],
+                    mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8186_i2s_enum[0],
+                    mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+       SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8186_i2s_enum[0],
+                    mt8186_i2s_hd_get, mt8186_i2s_hd_set),
+};
+
+/* dai component */
+/* i2s virtual mux to output widget */
+static const char * const i2s_mux_map[] = {
+       "Normal", "Dummy_Widget",
+};
+
+static int i2s_mux_map_value[] = {
+       0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s_mux_map_enum,
+                                             SND_SOC_NOPM,
+                                             0,
+                                             1,
+                                             i2s_mux_map,
+                                             i2s_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_in_mux_control =
+       SOC_DAPM_ENUM("I2S0 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s1_out_mux_control =
+       SOC_DAPM_ENUM("I2S1 Out Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s2_in_mux_control =
+       SOC_DAPM_ENUM("I2S2 In Select", i2s_mux_map_enum);
+
+static const struct snd_kcontrol_new i2s3_out_mux_control =
+       SOC_DAPM_ENUM("I2S3 Out Select", i2s_mux_map_enum);
+
+/* i2s in lpbk */
+static const char * const i2s_lpbk_mux_map[] = {
+       "Normal", "Lpbk",
+};
+
+static int i2s_lpbk_mux_map_value[] = {
+       0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s0_lpbk_mux_map_enum,
+                                             AFE_I2S_CON,
+                                             I2S_LOOPBACK_SFT,
+                                             1,
+                                             i2s_lpbk_mux_map,
+                                             i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s0_lpbk_mux_control =
+       SOC_DAPM_ENUM("I2S Lpbk Select", i2s0_lpbk_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(i2s2_lpbk_mux_map_enum,
+                                             AFE_I2S_CON2,
+                                             I2S3_LOOPBACK_SFT,
+                                             1,
+                                             i2s_lpbk_mux_map,
+                                             i2s_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new i2s2_lpbk_mux_control =
+       SOC_DAPM_ENUM("I2S Lpbk Select", i2s2_lpbk_mux_map_enum);
+
+/* interconnection */
+static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN0,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN0,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN0,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN0,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN0,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN0_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN0_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN0_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN0_1,
+                                   I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN0,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN0,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN0,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN0,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN0,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN0_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN1,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN1,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN1,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN1,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN1,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN1_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN1_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN1_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN1_1,
+                                   I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN1,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN1,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN1,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3 Switch", AFE_CONN1,
+                                   I_ADDA_UL_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN1,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN1,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN1_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN28,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN28,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN28,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH1 Switch", AFE_CONN28,
+                                   I_DL12_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH3 Switch", AFE_CONN28,
+                                   I_DL12_CH3, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN28_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN28_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN28_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH1 Switch", AFE_CONN28_1,
+                                   I_DL8_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN28,
+                                   I_GAIN1_OUT_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN28,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1 Switch", AFE_CONN28,
+                                   I_PCM_1_CAP_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH1 Switch", AFE_CONN28_1,
+                                   I_SRC_1_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN29,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN29,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN29,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH2 Switch", AFE_CONN29,
+                                   I_DL12_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL12_CH4 Switch", AFE_CONN29,
+                                   I_DL12_CH4, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN29_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN29_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN29_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL8_CH2 Switch", AFE_CONN29_1,
+                                   I_DL8_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN29,
+                                   I_GAIN1_OUT_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN29,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2 Switch", AFE_CONN29,
+                                   I_PCM_1_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2 Switch", AFE_CONN29,
+                                   I_PCM_2_CAP_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("SRC_1_OUT_CH2 Switch", AFE_CONN29_1,
+                                   I_SRC_1_OUT_CH2, 1, 0),
+};
+
+enum {
+       SUPPLY_SEQ_APLL,
+       SUPPLY_SEQ_I2S_MCLK_EN,
+       SUPPLY_SEQ_I2S_HD_EN,
+       SUPPLY_SEQ_I2S_EN,
+};
+
+static int mtk_i2s_en_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_afe_gpio_request(afe->dev, true, i2s_priv->id, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               mt8186_afe_gpio_request(afe->dev, false, i2s_priv->id, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_apll_event(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (strcmp(w->name, APLL1_W_NAME) == 0)
+                       mt8186_apll1_enable(afe);
+               else
+                       mt8186_apll2_enable(afe);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (strcmp(w->name, APLL1_W_NAME) == 0)
+                       mt8186_apll1_disable(afe);
+               else
+                       mt8186_apll2_disable(afe);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol,
+                            int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               i2s_priv->mclk_rate = 0;
+               mt8186_mck_disable(afe, i2s_priv->mclk_id);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = {
+       SND_SOC_DAPM_INPUT("CONNSYS"),
+
+       SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s1_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s1_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s1_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s1_ch2_mix)),
+
+       SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s3_ch1_mix,
+                          ARRAY_SIZE(mtk_i2s3_ch1_mix)),
+       SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_i2s3_ch2_mix,
+                          ARRAY_SIZE(mtk_i2s3_ch2_mix)),
+
+       /* i2s en*/
+       SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON1, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON2, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN,
+                             AFE_I2S_CON3, I2S_EN_SFT, 0,
+                             mtk_i2s_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       /* i2s hd en */
+       SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON, I2S1_HD_EN_SFT, 0, NULL,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, NULL,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, NULL,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN,
+                             AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, NULL,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* i2s mclk en */
+       SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_mclk_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* apll */
+       SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_apll_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_apll_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* allow i2s on without codec on */
+       SND_SOC_DAPM_OUTPUT("I2S_DUMMY_OUT"),
+       SND_SOC_DAPM_MUX("I2S1_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s1_out_mux_control),
+       SND_SOC_DAPM_MUX("I2S3_Out_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s3_out_mux_control),
+       SND_SOC_DAPM_INPUT("I2S_DUMMY_IN"),
+       SND_SOC_DAPM_MUX("I2S0_In_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s0_in_mux_control),
+       SND_SOC_DAPM_MUX("I2S2_In_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s2_in_mux_control),
+
+       /* i2s in lpbk */
+       SND_SOC_DAPM_MUX("I2S0_Lpbk_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s0_lpbk_mux_control),
+       SND_SOC_DAPM_MUX("I2S2_Lpbk_Mux",
+                        SND_SOC_NOPM, 0, 0, &i2s2_lpbk_mux_control),
+};
+
+static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source,
+                                    struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+       if (i2s_priv->share_i2s_id < 0)
+               return 0;
+
+       return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name);
+}
+
+static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source,
+                                 struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+       if (get_i2s_id_by_name(afe, sink->name) ==
+           get_i2s_id_by_name(afe, source->name))
+               return i2s_priv->low_jitter_en;
+
+       /* check if share i2s need hd en */
+       if (i2s_priv->share_i2s_id < 0)
+               return 0;
+
+       if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+               return i2s_priv->low_jitter_en;
+
+       return 0;
+}
+
+static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+       int cur_apll;
+       int i2s_need_apll;
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+       /* which apll */
+       cur_apll = mt8186_get_apll_by_name(afe, source->name);
+       /* choose APLL from i2s rate */
+       i2s_need_apll = mt8186_get_apll_by_rate(afe, i2s_priv->rate);
+
+       return (i2s_need_apll == cur_apll) ? 1 : 0;
+}
+
+static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+
+       i2s_priv = get_i2s_priv_by_name(afe, sink->name);
+       if (get_i2s_id_by_name(afe, sink->name) ==
+           get_i2s_id_by_name(afe, source->name))
+               return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+       /* check if share i2s need mclk */
+       if (i2s_priv->share_i2s_id < 0)
+               return 0;
+
+       if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name))
+               return (i2s_priv->mclk_rate > 0) ? 1 : 0;
+
+       return 0;
+}
+
+static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+                                    struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mtk_afe_i2s_priv *i2s_priv;
+       int cur_apll;
+
+       i2s_priv = get_i2s_priv_by_name(afe, w->name);
+       /* which apll */
+       cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+       return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = {
+       {"Connsys I2S", NULL, "CONNSYS"},
+
+       /* i2s0 */
+       {"I2S0", NULL, "I2S0_EN"},
+       {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s1 */
+       {"I2S1_CH1", "DL1_CH1 Switch", "DL1"},
+       {"I2S1_CH2", "DL1_CH2 Switch", "DL1"},
+
+       {"I2S1_CH1", "DL2_CH1 Switch", "DL2"},
+       {"I2S1_CH2", "DL2_CH2 Switch", "DL2"},
+
+       {"I2S1_CH1", "DL3_CH1 Switch", "DL3"},
+       {"I2S1_CH2", "DL3_CH2 Switch", "DL3"},
+
+       {"I2S1_CH1", "DL12_CH1 Switch", "DL12"},
+       {"I2S1_CH2", "DL12_CH2 Switch", "DL12"},
+
+       {"I2S1_CH1", "DL12_CH3 Switch", "DL12"},
+       {"I2S1_CH2", "DL12_CH4 Switch", "DL12"},
+
+       {"I2S1_CH1", "DL6_CH1 Switch", "DL6"},
+       {"I2S1_CH2", "DL6_CH2 Switch", "DL6"},
+
+       {"I2S1_CH1", "DL4_CH1 Switch", "DL4"},
+       {"I2S1_CH2", "DL4_CH2 Switch", "DL4"},
+
+       {"I2S1_CH1", "DL5_CH1 Switch", "DL5"},
+       {"I2S1_CH2", "DL5_CH2 Switch", "DL5"},
+
+       {"I2S1_CH1", "DL8_CH1 Switch", "DL8"},
+       {"I2S1_CH2", "DL8_CH2 Switch", "DL8"},
+
+       {"I2S1", NULL, "I2S1_CH1"},
+       {"I2S1", NULL, "I2S1_CH2"},
+
+       {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S1_EN"},
+       {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s2 */
+       {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S2", NULL, "I2S2_EN"},
+       {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect},
+
+       {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* i2s3 */
+       {"I2S3_CH1", "DL1_CH1 Switch", "DL1"},
+       {"I2S3_CH2", "DL1_CH2 Switch", "DL1"},
+
+       {"I2S3_CH1", "DL2_CH1 Switch", "DL2"},
+       {"I2S3_CH2", "DL2_CH2 Switch", "DL2"},
+
+       {"I2S3_CH1", "DL3_CH1 Switch", "DL3"},
+       {"I2S3_CH2", "DL3_CH2 Switch", "DL3"},
+
+       {"I2S3_CH1", "DL12_CH1 Switch", "DL12"},
+       {"I2S3_CH2", "DL12_CH2 Switch", "DL12"},
+
+       {"I2S3_CH1", "DL12_CH3 Switch", "DL12"},
+       {"I2S3_CH2", "DL12_CH4 Switch", "DL12"},
+
+       {"I2S3_CH1", "DL6_CH1 Switch", "DL6"},
+       {"I2S3_CH2", "DL6_CH2 Switch", "DL6"},
+
+       {"I2S3_CH1", "DL4_CH1 Switch", "DL4"},
+       {"I2S3_CH2", "DL4_CH2 Switch", "DL4"},
+
+       {"I2S3_CH1", "DL5_CH1 Switch", "DL5"},
+       {"I2S3_CH2", "DL5_CH2 Switch", "DL5"},
+
+       {"I2S3_CH1", "DL8_CH1 Switch", "DL8"},
+       {"I2S3_CH2", "DL8_CH2 Switch", "DL8"},
+
+       {"I2S3", NULL, "I2S3_CH1"},
+       {"I2S3", NULL, "I2S3_CH2"},
+
+       {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect},
+       {"I2S3", NULL, "I2S3_EN"},
+
+       {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect},
+       {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect},
+       {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect},
+
+       {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect},
+       {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect},
+       {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect},
+
+       /* allow i2s on without codec on */
+       {"I2S0", NULL, "I2S0_In_Mux"},
+       {"I2S0_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+       {"I2S1_Out_Mux", "Dummy_Widget", "I2S1"},
+       {"I2S_DUMMY_OUT", NULL, "I2S1_Out_Mux"},
+
+       {"I2S2", NULL, "I2S2_In_Mux"},
+       {"I2S2_In_Mux", "Dummy_Widget", "I2S_DUMMY_IN"},
+
+       {"I2S3_Out_Mux", "Dummy_Widget", "I2S3"},
+       {"I2S_DUMMY_OUT", NULL, "I2S3_Out_Mux"},
+
+       /* i2s in lpbk */
+       {"I2S0_Lpbk_Mux", "Lpbk", "I2S3"},
+       {"I2S2_Lpbk_Mux", "Lpbk", "I2S1"},
+       {"I2S0", NULL, "I2S0_Lpbk_Mux"},
+       {"I2S2", NULL, "I2S2_Lpbk_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_connsys_i2s_hw_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *params,
+                                        struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8186_rate_transform(afe->dev,
+                                                     rate, dai->id);
+       unsigned int i2s_con = 0;
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+               __func__, dai->id, substream->stream, rate);
+
+       /* non-inverse, i2s mode, slave, 16bits, from connsys */
+       i2s_con |= 0 << INV_PAD_CTRL_SFT;
+       i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+       i2s_con |= 1 << I2S_SRC_SFT;
+       i2s_con |= get_i2s_wlen(SNDRV_PCM_FORMAT_S16_LE) << I2S_WLEN_SFT;
+       i2s_con |= 0 << I2SIN_PAD_SEL_SFT;
+       regmap_write(afe->regmap, AFE_CONNSYS_I2S_CON, i2s_con);
+
+       /* use asrc */
+       regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+                          I2S_BYPSRC_MASK_SFT, 0);
+
+       /* slave mode, set i2s for asrc */
+       regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+                          I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT);
+
+       if (rate == 44100)
+               regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1b9000);
+       else if (rate == 32000)
+               regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x140000);
+       else
+               regmap_write(afe->regmap, AFE_ASRC_2CH_CON3, 0x1e0000);
+
+       /* Calibration setting */
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON4, 0x140000);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON9, 0x36000);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON10, 0x2fc00);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON6, 0x7ef4);
+       regmap_write(afe->regmap, AFE_ASRC_2CH_CON5, 0xff5986);
+
+       /* 0:Stereo 1:Mono */
+       regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON2,
+                          CHSET_IS_MONO_MASK_SFT, 0);
+
+       return 0;
+}
+
+static int mtk_dai_connsys_i2s_trigger(struct snd_pcm_substream *substream,
+                                      int cmd, struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       dev_dbg(afe->dev, "%s(), cmd %d, stream %d\n",
+               __func__, cmd, substream->stream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               /* i2s enable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_CONNSYS_I2S_CON,
+                                  I2S_EN_MASK_SFT,
+                                  BIT(I2S_EN_SFT));
+
+               /* calibrator enable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON5,
+                                  CALI_EN_MASK_SFT,
+                                  BIT(CALI_EN_SFT));
+
+               /* asrc enable */
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON0,
+                                  CON0_CHSET_STR_CLR_MASK_SFT,
+                                  BIT(CON0_CHSET_STR_CLR_SFT));
+               regmap_update_bits(afe->regmap,
+                                  AFE_ASRC_2CH_CON0,
+                                  CON0_ASM_ON_MASK_SFT,
+                                  BIT(CON0_ASM_ON_SFT));
+
+               afe_priv->dai_on[dai->id] = true;
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON0,
+                                  CON0_ASM_ON_MASK_SFT, 0);
+               regmap_update_bits(afe->regmap, AFE_ASRC_2CH_CON5,
+                                  CALI_EN_MASK_SFT, 0);
+
+               /* i2s disable */
+               regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+                                  I2S_EN_MASK_SFT, 0);
+
+               /* bypass asrc */
+               regmap_update_bits(afe->regmap, AFE_CONNSYS_I2S_CON,
+                                  I2S_BYPSRC_MASK_SFT, BIT(I2S_BYPSRC_SFT));
+
+               afe_priv->dai_on[dai->id] = false;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_connsys_i2s_ops = {
+       .hw_params = mtk_dai_connsys_i2s_hw_params,
+       .trigger = mtk_dai_connsys_i2s_trigger,
+};
+
+/* i2s */
+static int mtk_dai_i2s_config(struct mtk_base_afe *afe,
+                             struct snd_pcm_hw_params *params,
+                             int i2s_id)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id];
+
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8186_rate_transform(afe->dev,
+                                                     rate, i2s_id);
+       snd_pcm_format_t format = params_format(params);
+       unsigned int i2s_con = 0;
+       int ret;
+
+       dev_dbg(afe->dev, "%s(), id %d, rate %d, format %d\n",
+               __func__, i2s_id, rate, format);
+
+       i2s_priv->rate = rate;
+
+       switch (i2s_id) {
+       case MT8186_DAI_I2S_0:
+               i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT;
+               i2s_con |= rate_reg << I2S_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON,
+                                  0xffffeffa, i2s_con);
+               break;
+       case MT8186_DAI_I2S_1:
+               i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT;
+               i2s_con |= rate_reg << I2S2_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON1,
+                                  0xffffeffa, i2s_con);
+               break;
+       case MT8186_DAI_I2S_2:
+               i2s_con = 8 << I2S3_UPDATE_WORD_SFT;
+               i2s_con |= rate_reg << I2S3_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON2,
+                                  0xffffeffa, i2s_con);
+               break;
+       case MT8186_DAI_I2S_3:
+               i2s_con = rate_reg << I2S4_OUT_MODE_SFT;
+               i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT;
+               i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT;
+               regmap_update_bits(afe->regmap, AFE_I2S_CON3,
+                                  0xffffeffa, i2s_con);
+               break;
+       default:
+               dev_err(afe->dev, "%s(), id %d not support\n",
+                       __func__, i2s_id);
+               return -EINVAL;
+       }
+
+       /* set share i2s */
+       if (i2s_priv && i2s_priv->share_i2s_id >= 0) {
+               ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+       return mtk_dai_i2s_config(afe, params, dai->id);
+}
+
+static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id];
+       int apll;
+       int apll_rate;
+
+       if (dir != SND_SOC_CLOCK_OUT) {
+               dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+               return -EINVAL;
+       }
+
+       dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+       apll = mt8186_get_apll_by_rate(afe, freq);
+       apll_rate = mt8186_get_apll_rate(afe, apll);
+
+       if (freq > apll_rate) {
+               dev_err(afe->dev, "%s(), freq > apll rate", __func__);
+               return -EINVAL;
+       }
+
+       if (apll_rate % freq != 0) {
+               dev_err(afe->dev, "%s(), APLL cannot generate freq Hz", __func__);
+               return -EINVAL;
+       }
+
+       i2s_priv->mclk_rate = freq;
+       i2s_priv->mclk_apll = apll;
+
+       if (i2s_priv->share_i2s_id > 0) {
+               struct mtk_afe_i2s_priv *share_i2s_priv;
+
+               share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id];
+               if (!share_i2s_priv) {
+                       dev_err(afe->dev, "%s(), share_i2s_priv == NULL", __func__);
+                       return -EINVAL;
+               }
+
+               share_i2s_priv->mclk_rate = i2s_priv->mclk_rate;
+               share_i2s_priv->mclk_apll = i2s_priv->mclk_apll;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_i2s_ops = {
+       .hw_params = mtk_dai_i2s_hw_params,
+       .set_sysclk = mtk_dai_i2s_set_sysclk,
+};
+
+/* dai driver */
+#define MTK_CONNSYS_I2S_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = {
+       {
+               .name = "CONNSYS_I2S",
+               .id = MT8186_DAI_CONNSYS_I2S,
+               .capture = {
+                       .stream_name = "Connsys I2S",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_CONNSYS_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_connsys_i2s_ops,
+       },
+       {
+               .name = "I2S0",
+               .id = MT8186_DAI_I2S_0,
+               .capture = {
+                       .stream_name = "I2S0",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S1",
+               .id = MT8186_DAI_I2S_1,
+               .playback = {
+                       .stream_name = "I2S1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S2",
+               .id = MT8186_DAI_I2S_2,
+               .capture = {
+                       .stream_name = "I2S2",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       },
+       {
+               .name = "I2S3",
+               .id = MT8186_DAI_I2S_3,
+               .playback = {
+                       .stream_name = "I2S3",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_I2S_RATES,
+                       .formats = MTK_I2S_FORMATS,
+               },
+               .ops = &mtk_dai_i2s_ops,
+       }
+};
+
+/* this enum is merely for mtk_afe_i2s_priv declare */
+enum {
+       DAI_I2S0 = 0,
+       DAI_I2S1,
+       DAI_I2S2,
+       DAI_I2S3,
+       DAI_I2S_NUM,
+};
+
+static const struct mtk_afe_i2s_priv mt8186_i2s_priv[DAI_I2S_NUM] = {
+       [DAI_I2S0] = {
+               .id = MT8186_DAI_I2S_0,
+               .mclk_id = MT8186_I2S0_MCK,
+               .share_property_name = "i2s0-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S1] = {
+               .id = MT8186_DAI_I2S_1,
+               .mclk_id = MT8186_I2S1_MCK,
+               .share_property_name = "i2s1-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S2] = {
+               .id = MT8186_DAI_I2S_2,
+               .mclk_id = MT8186_I2S2_MCK,
+               .share_property_name = "i2s2-share",
+               .share_i2s_id = -1,
+       },
+       [DAI_I2S3] = {
+               .id = MT8186_DAI_I2S_3,
+               /*  clock gate naming is hf_faud_i2s4_m_ck*/
+               .mclk_id = MT8186_I2S4_MCK,
+               .share_property_name = "i2s3-share",
+               .share_i2s_id = -1,
+       }
+};
+
+static int mt8186_dai_i2s_get_share(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       const struct device_node *of_node = afe->dev->of_node;
+       const char *of_str;
+       const char *property_name;
+       struct mtk_afe_i2s_priv *i2s_priv;
+       int i;
+
+       for (i = 0; i < DAI_I2S_NUM; i++) {
+               i2s_priv = afe_priv->dai_priv[mt8186_i2s_priv[i].id];
+               property_name = mt8186_i2s_priv[i].share_property_name;
+               if (of_property_read_string(of_node, property_name, &of_str))
+                       continue;
+               i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str);
+       }
+
+       return 0;
+}
+
+static int mt8186_dai_i2s_set_priv(struct mtk_base_afe *afe)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < DAI_I2S_NUM; i++) {
+               ret = mt8186_dai_set_priv(afe, mt8186_i2s_priv[i].id,
+                                         sizeof(struct mtk_afe_i2s_priv),
+                                         &mt8186_i2s_priv[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int mt8186_dai_i2s_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+       int ret;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_i2s_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver);
+
+       dai->controls = mtk_dai_i2s_controls;
+       dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls);
+       dai->dapm_widgets = mtk_dai_i2s_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets);
+       dai->dapm_routes = mtk_dai_i2s_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes);
+
+       /* set all dai i2s private data */
+       ret = mt8186_dai_i2s_set_priv(afe);
+       if (ret)
+               return ret;
+
+       /* parse share i2s */
+       ret = mt8186_dai_i2s_get_share(afe);
+       if (ret)
+               return ret;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c b/sound/soc/mediatek/mt8186/mt8186-dai-pcm.c
new file mode 100644 (file)
index 0000000..41221a6
--- /dev/null
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI I2S Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+struct mtk_afe_pcm_priv {
+       unsigned int id;
+       unsigned int fmt;
+       unsigned int bck_invert;
+       unsigned int lck_invert;
+};
+
+enum aud_tx_lch_rpt {
+       AUD_TX_LCH_RPT_NO_REPEAT = 0,
+       AUD_TX_LCH_RPT_REPEAT = 1
+};
+
+enum aud_vbt_16k_mode {
+       AUD_VBT_16K_MODE_DISABLE = 0,
+       AUD_VBT_16K_MODE_ENABLE = 1
+};
+
+enum aud_ext_modem {
+       AUD_EXT_MODEM_SELECT_INTERNAL = 0,
+       AUD_EXT_MODEM_SELECT_EXTERNAL = 1
+};
+
+enum aud_pcm_sync_type {
+       /* bck sync length = 1 */
+       AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
+       /* bck sync length = PCM_INTF_CON1[9:13] */
+       AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
+};
+
+enum aud_bt_mode {
+       AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
+       AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
+};
+
+enum aud_pcm_afifo_src {
+       /* slave mode & external modem uses different crystal */
+       AUD_PCM_AFIFO_ASRC = 0,
+       /* slave mode & external modem uses the same crystal */
+       AUD_PCM_AFIFO_AFIFO = 1
+};
+
+enum aud_pcm_clock_source {
+       AUD_PCM_CLOCK_MASTER_MODE = 0,
+       AUD_PCM_CLOCK_SLAVE_MODE = 1
+};
+
+enum aud_pcm_wlen {
+       AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
+       AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
+};
+
+enum aud_pcm_24bit {
+       AUD_PCM_24BIT_PCM_16_BITS = 0,
+       AUD_PCM_24BIT_PCM_24_BITS = 1
+};
+
+enum aud_pcm_mode {
+       AUD_PCM_MODE_PCM_MODE_8K = 0,
+       AUD_PCM_MODE_PCM_MODE_16K = 1,
+       AUD_PCM_MODE_PCM_MODE_32K = 2,
+       AUD_PCM_MODE_PCM_MODE_48K = 3,
+};
+
+enum aud_pcm_fmt {
+       AUD_PCM_FMT_I2S = 0,
+       AUD_PCM_FMT_EIAJ = 1,
+       AUD_PCM_FMT_PCM_MODE_A = 2,
+       AUD_PCM_FMT_PCM_MODE_B = 3
+};
+
+enum aud_bclk_out_inv {
+       AUD_BCLK_OUT_INV_NO_INVERSE = 0,
+       AUD_BCLK_OUT_INV_INVERSE = 1
+};
+
+enum aud_lrclk_out_inv {
+       AUD_LRCLK_OUT_INV_NO_INVERSE = 0,
+       AUD_LRCLK_OUT_INV_INVERSE = 1
+};
+
+enum aud_pcm_en {
+       AUD_PCM_EN_DISABLE = 0,
+       AUD_PCM_EN_ENABLE = 1
+};
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN7,
+                                   I_ADDA_UL_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN7,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN7_1,
+                                   I_DL4_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN8,
+                                   I_ADDA_UL_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN8,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN8_1,
+                                   I_DL4_CH2, 1, 0),
+};
+
+static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+
+       dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_PCM, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_PCM, 0);
+               break;
+       }
+
+       return 0;
+}
+
+/* pcm in/out lpbk */
+static const char * const pcm_lpbk_mux_map[] = {
+       "Normal", "Lpbk",
+};
+
+static int pcm_lpbk_mux_map_value[] = {
+       0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_in_lpbk_mux_map_enum,
+                                             PCM_INTF_CON1,
+                                             PCM_I2S_PCM_LOOPBACK_SFT,
+                                             1,
+                                             pcm_lpbk_mux_map,
+                                             pcm_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new pcm_in_lpbk_mux_control =
+       SOC_DAPM_ENUM("PCM In Lpbk Select", pcm_in_lpbk_mux_map_enum);
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_out_lpbk_mux_map_enum,
+                                             PCM_INTF_CON1,
+                                             PCM_I2S_PCM_LOOPBACK_SFT,
+                                             1,
+                                             pcm_lpbk_mux_map,
+                                             pcm_lpbk_mux_map_value);
+
+static const struct snd_kcontrol_new pcm_out_lpbk_mux_control =
+       SOC_DAPM_ENUM("PCM Out Lpbk Select", pcm_out_lpbk_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_1_playback_ch1_mix,
+                          ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
+       SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_pcm_1_playback_ch2_mix,
+                          ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
+
+       SND_SOC_DAPM_SUPPLY("PCM_1_EN",
+                           PCM_INTF_CON1, PCM_EN_SFT, 0,
+                           mtk_pcm_en_event,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* pcm in lpbk */
+       SND_SOC_DAPM_MUX("PCM_In_Lpbk_Mux",
+                        SND_SOC_NOPM, 0, 0, &pcm_in_lpbk_mux_control),
+
+       /* pcm out lpbk */
+       SND_SOC_DAPM_MUX("PCM_Out_Lpbk_Mux",
+                        SND_SOC_NOPM, 0, 0, &pcm_out_lpbk_mux_control),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
+       {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
+       {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
+
+       {"PCM 1 Playback", NULL, "PCM_1_EN"},
+       {"PCM 1 Capture", NULL, "PCM_1_EN"},
+
+       {"PCM_1_PB_CH1", "DL2_CH1 Switch", "DL2"},
+       {"PCM_1_PB_CH2", "DL2_CH2 Switch", "DL2"},
+
+       {"PCM_1_PB_CH1", "DL4_CH1 Switch", "DL4"},
+       {"PCM_1_PB_CH2", "DL4_CH2 Switch", "DL4"},
+
+       /* pcm out lpbk */
+       {"PCM_Out_Lpbk_Mux", "Lpbk", "PCM 1 Playback"},
+       {"I2S0", NULL, "PCM_Out_Lpbk_Mux"},
+
+       /* pcm in lpbk */
+       {"PCM_In_Lpbk_Mux", "Lpbk", "PCM 1 Capture"},
+       {"I2S3", NULL, "PCM_In_Lpbk_Mux"},
+};
+
+/* dai ops */
+static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int pcm_id = dai->id;
+       struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[pcm_id];
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id);
+       snd_pcm_format_t format = params_format(params);
+       unsigned int data_width =
+               snd_pcm_format_width(format);
+       unsigned int wlen_width =
+               snd_pcm_format_physical_width(format);
+       unsigned int pcm_con = 0;
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n",
+               __func__, dai->id, substream->stream, dai->playback_widget->active,
+               dai->capture_widget->active);
+       dev_dbg(afe->dev, "%s(), rate %d, rate_reg %d, data_width %d, wlen_width %d\n",
+               __func__, rate, rate_reg, data_width, wlen_width);
+
+       if (dai->playback_widget->active || dai->capture_widget->active)
+               return 0;
+
+       switch (dai->id) {
+       case MT8186_DAI_PCM:
+               pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
+               pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
+               pcm_con |= AUD_EXT_MODEM_SELECT_EXTERNAL << PCM_EXT_MODEM_SFT;
+               pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
+               pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
+               pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
+               pcm_con |= AUD_PCM_CLOCK_MASTER_MODE << PCM_SLAVE_SFT;
+               pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
+
+               /* sampling rate */
+               pcm_con |= rate_reg << PCM_MODE_SFT;
+
+               /* format */
+               pcm_con |= pcm_priv->fmt << PCM_FMT_SFT;
+
+               /* 24bit data width */
+               if (data_width > 16)
+                       pcm_con |= AUD_PCM_24BIT_PCM_24_BITS << PCM_24BIT_SFT;
+               else
+                       pcm_con |= AUD_PCM_24BIT_PCM_16_BITS << PCM_24BIT_SFT;
+
+               /* wlen width*/
+               if (wlen_width > 16)
+                       pcm_con |= AUD_PCM_WLEN_PCM_64_BCK_CYCLES << PCM_WLEN_SFT;
+               else
+                       pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM_WLEN_SFT;
+
+               /* clock invert */
+               pcm_con |= pcm_priv->lck_invert << PCM_SYNC_OUT_INV_SFT;
+               pcm_con |= pcm_priv->bck_invert << PCM_BCLK_OUT_INV_SFT;
+
+               regmap_update_bits(afe->regmap, PCM_INTF_CON1, 0xfffffffe, pcm_con);
+               break;
+       default:
+               dev_err(afe->dev, "%s(), id %d not support\n", __func__, dai->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id];
+
+       /* DAI mode*/
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               pcm_priv->fmt = AUD_PCM_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               pcm_priv->fmt = AUD_PCM_FMT_EIAJ;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_B;
+               break;
+       default:
+               pcm_priv->fmt = AUD_PCM_FMT_I2S;
+       }
+
+       /* DAI clock inversion*/
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+               pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+               pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE;
+               pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE;
+               pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE;
+               break;
+       default:
+               pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+               pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
+       .hw_params = mtk_dai_pcm_hw_params,
+       .set_fmt = mtk_dai_pcm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
+                      SNDRV_PCM_RATE_16000 |\
+                      SNDRV_PCM_RATE_32000 |\
+                      SNDRV_PCM_RATE_48000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
+       {
+               .name = "PCM 1",
+               .id = MT8186_DAI_PCM,
+               .playback = {
+                       .stream_name = "PCM 1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "PCM 1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_dai_pcm_ops,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
+       },
+};
+
+static struct mtk_afe_pcm_priv *init_pcm_priv_data(struct mtk_base_afe *afe)
+{
+       struct mtk_afe_pcm_priv *pcm_priv;
+
+       pcm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_pcm_priv),
+                               GFP_KERNEL);
+       if (!pcm_priv)
+               return NULL;
+
+       pcm_priv->id = MT8186_DAI_PCM;
+       pcm_priv->fmt = AUD_PCM_FMT_I2S;
+       pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE;
+       pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE;
+
+       return pcm_priv;
+}
+
+int mt8186_dai_pcm_register(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_pcm_priv *pcm_priv;
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_pcm_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+       dai->dapm_widgets = mtk_dai_pcm_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+       dai->dapm_routes = mtk_dai_pcm_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+
+       pcm_priv = init_pcm_priv_data(afe);
+       if (!pcm_priv)
+               return -ENOMEM;
+
+       afe_priv->dai_priv[MT8186_DAI_PCM] = pcm_priv;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-src.c b/sound/soc/mediatek/mt8186/mt8186-dai-src.c
new file mode 100644 (file)
index 0000000..67989ff
--- /dev/null
@@ -0,0 +1,695 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+//  MediaTek ALSA SoC Audio DAI SRC Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include "mt8186-afe-common.h"
+#include "mt8186-interconnection.h"
+
+struct mtk_afe_src_priv {
+       int dl_rate;
+       int ul_rate;
+};
+
+static const unsigned int src_iir_coeff_32_to_16[] = {
+       0x0dbae6, 0xff9b0a, 0x0dbae6, 0x05e488, 0xe072b9, 0x000002,
+       0x0dbae6, 0x000f3b, 0x0dbae6, 0x06a537, 0xe17d79, 0x000002,
+       0x0dbae6, 0x01246a, 0x0dbae6, 0x087261, 0xe306be, 0x000002,
+       0x0dbae6, 0x03437d, 0x0dbae6, 0x0bc16f, 0xe57c87, 0x000002,
+       0x0dbae6, 0x072981, 0x0dbae6, 0x111dd3, 0xe94f2a, 0x000002,
+       0x0dbae6, 0x0dc4a6, 0x0dbae6, 0x188611, 0xee85a0, 0x000002,
+       0x0dbae6, 0x168b9a, 0x0dbae6, 0x200e8f, 0xf3ccf1, 0x000002,
+       0x000000, 0x1b75cb, 0x1b75cb, 0x2374a2, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_44_to_16[] = {
+       0x09ae28, 0xf7d97d, 0x09ae28, 0x212a3d, 0xe0ac3a, 0x000002,
+       0x09ae28, 0xf8525a, 0x09ae28, 0x216d72, 0xe234be, 0x000002,
+       0x09ae28, 0xf980f5, 0x09ae28, 0x22a057, 0xe45a81, 0x000002,
+       0x09ae28, 0xfc0a08, 0x09ae28, 0x24d3bd, 0xe7752d, 0x000002,
+       0x09ae28, 0x016162, 0x09ae28, 0x27da01, 0xeb6ea8, 0x000002,
+       0x09ae28, 0x0b67df, 0x09ae28, 0x2aca4a, 0xef34c4, 0x000002,
+       0x000000, 0x135c50, 0x135c50, 0x2c1079, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_44_to_32[] = {
+       0x096966, 0x0c4d35, 0x096966, 0xedee81, 0xf05070, 0x000003,
+       0x12d2cc, 0x193910, 0x12d2cc, 0xddbf4f, 0xe21e1d, 0x000002,
+       0x12d2cc, 0x1a9e60, 0x12d2cc, 0xe18916, 0xe470fd, 0x000002,
+       0x12d2cc, 0x1d06e0, 0x12d2cc, 0xe8a4a6, 0xe87b24, 0x000002,
+       0x12d2cc, 0x207578, 0x12d2cc, 0xf4fe62, 0xef5917, 0x000002,
+       0x12d2cc, 0x24055f, 0x12d2cc, 0x05ee2b, 0xf8b502, 0x000002,
+       0x000000, 0x25a599, 0x25a599, 0x0fabe2, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_48_to_16[] = {
+       0x0296a4, 0xfd69dd, 0x0296a4, 0x209439, 0xe01ff9, 0x000002,
+       0x0f4ff3, 0xf0d6d4, 0x0f4ff3, 0x209bc9, 0xe076c3, 0x000002,
+       0x0e8490, 0xf1fe63, 0x0e8490, 0x20cfd6, 0xe12124, 0x000002,
+       0x14852f, 0xed794a, 0x14852f, 0x21503d, 0xe28b32, 0x000002,
+       0x136222, 0xf17677, 0x136222, 0x225be1, 0xe56964, 0x000002,
+       0x0a8d85, 0xfc4a97, 0x0a8d85, 0x24310c, 0xea6952, 0x000002,
+       0x05eff5, 0x043455, 0x05eff5, 0x4ced8f, 0xe134d6, 0x000001,
+       0x000000, 0x3aebe6, 0x3aebe6, 0x04f3b0, 0x000000, 0x000004
+};
+
+static const unsigned int src_iir_coeff_48_to_32[] = {
+       0x10c1b8, 0x10a7df, 0x10c1b8, 0xe7514e, 0xe0b41f, 0x000002,
+       0x10c1b8, 0x116257, 0x10c1b8, 0xe9402f, 0xe25aaa, 0x000002,
+       0x10c1b8, 0x130c89, 0x10c1b8, 0xed3cc3, 0xe4dddb, 0x000002,
+       0x10c1b8, 0x1600dd, 0x10c1b8, 0xf48000, 0xe90c55, 0x000002,
+       0x10c1b8, 0x1a672e, 0x10c1b8, 0x00494c, 0xefa807, 0x000002,
+       0x10c1b8, 0x1f38e6, 0x10c1b8, 0x0ee076, 0xf7c5f3, 0x000002,
+       0x000000, 0x218370, 0x218370, 0x168b40, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_48_to_44[] = {
+       0x0bf71c, 0x170f3f, 0x0bf71c, 0xe3a4c8, 0xf096cb, 0x000003,
+       0x0bf71c, 0x17395e, 0x0bf71c, 0xe58085, 0xf210c8, 0x000003,
+       0x0bf71c, 0x1782bd, 0x0bf71c, 0xe95ef6, 0xf4c899, 0x000003,
+       0x0bf71c, 0x17cd97, 0x0bf71c, 0xf1608a, 0xfa3b18, 0x000003,
+       0x000000, 0x2fdc6f, 0x2fdc6f, 0xf15663, 0x000000, 0x000001
+};
+
+static const unsigned int src_iir_coeff_96_to_16[] = {
+       0x0805a1, 0xf21ae3, 0x0805a1, 0x3840bb, 0xe02a2e, 0x000002,
+       0x0d5dd8, 0xe8f259, 0x0d5dd8, 0x1c0af6, 0xf04700, 0x000003,
+       0x0bb422, 0xec08d9, 0x0bb422, 0x1bfccc, 0xf09216, 0x000003,
+       0x08fde6, 0xf108be, 0x08fde6, 0x1bf096, 0xf10ae0, 0x000003,
+       0x0ae311, 0xeeeda3, 0x0ae311, 0x37c646, 0xe385f5, 0x000002,
+       0x044089, 0xfa7242, 0x044089, 0x37a785, 0xe56526, 0x000002,
+       0x00c75c, 0xffb947, 0x00c75c, 0x378ba3, 0xe72c5f, 0x000002,
+       0x000000, 0x0ef76e, 0x0ef76e, 0x377fda, 0x000000, 0x000001,
+};
+
+static const unsigned int src_iir_coeff_96_to_44[] = {
+       0x08b543, 0xfd80f4, 0x08b543, 0x0e2332, 0xe06ed0, 0x000002,
+       0x1b6038, 0xf90e7e, 0x1b6038, 0x0ec1ac, 0xe16f66, 0x000002,
+       0x188478, 0xfbb921, 0x188478, 0x105859, 0xe2e596, 0x000002,
+       0x13eff3, 0xffa707, 0x13eff3, 0x13455c, 0xe533b7, 0x000002,
+       0x0dc239, 0x03d458, 0x0dc239, 0x17f120, 0xe8b617, 0x000002,
+       0x0745f1, 0x05d790, 0x0745f1, 0x1e3d75, 0xed5f18, 0x000002,
+       0x05641f, 0x085e2b, 0x05641f, 0x48efd0, 0xe3e9c8, 0x000001,
+       0x000000, 0x28f632, 0x28f632, 0x273905, 0x000000, 0x000001,
+};
+
+static unsigned int mtk_get_src_freq_mode(struct mtk_base_afe *afe, int rate)
+{
+       switch (rate) {
+       case 8000:
+               return 0x50000;
+       case 11025:
+               return 0x6e400;
+       case 12000:
+               return 0x78000;
+       case 16000:
+               return 0xa0000;
+       case 22050:
+               return 0xdc800;
+       case 24000:
+               return 0xf0000;
+       case 32000:
+               return 0x140000;
+       case 44100:
+               return 0x1b9000;
+       case 48000:
+               return 0x1e0000;
+       case 88200:
+               return 0x372000;
+       case 96000:
+               return 0x3c0000;
+       case 176400:
+               return 0x6e4000;
+       case 192000:
+               return 0x780000;
+       default:
+               dev_err(afe->dev, "%s(), rate %d invalid!!!\n",
+                       __func__, rate);
+               return 0;
+       }
+}
+
+static const unsigned int *get_iir_coeff(unsigned int rate_in,
+                                        unsigned int rate_out,
+                                        unsigned int *param_num)
+{
+       if (rate_in == 32000 && rate_out == 16000) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_32_to_16);
+               return src_iir_coeff_32_to_16;
+       } else if (rate_in == 44100 && rate_out == 16000) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_44_to_16);
+               return src_iir_coeff_44_to_16;
+       } else if (rate_in == 44100 && rate_out == 32000) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_44_to_32);
+               return src_iir_coeff_44_to_32;
+       } else if ((rate_in == 48000 && rate_out == 16000) ||
+                  (rate_in == 96000 && rate_out == 32000)) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_48_to_16);
+               return src_iir_coeff_48_to_16;
+       } else if (rate_in == 48000 && rate_out == 32000) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_48_to_32);
+               return src_iir_coeff_48_to_32;
+       } else if (rate_in == 48000 && rate_out == 44100) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_48_to_44);
+               return src_iir_coeff_48_to_44;
+       } else if (rate_in == 96000 && rate_out == 16000) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_96_to_16);
+               return src_iir_coeff_96_to_16;
+       } else if ((rate_in == 96000 && rate_out == 44100) ||
+                  (rate_in == 48000 && rate_out == 22050)) {
+               *param_num = ARRAY_SIZE(src_iir_coeff_96_to_44);
+               return src_iir_coeff_96_to_44;
+       }
+
+       *param_num = 0;
+       return NULL;
+}
+
+static int mtk_set_src_1_param(struct mtk_base_afe *afe, int id)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+       unsigned int iir_coeff_num;
+       unsigned int iir_stage;
+       int rate_in = src_priv->dl_rate;
+       int rate_out = src_priv->ul_rate;
+       unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out);
+       unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in);
+
+       /* set out freq mode */
+       regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON3,
+                          G_SRC_ASM_FREQ_4_MASK_SFT,
+                          out_freq_mode << G_SRC_ASM_FREQ_4_SFT);
+
+       /* set in freq mode */
+       regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON4,
+                          G_SRC_ASM_FREQ_5_MASK_SFT,
+                          in_freq_mode << G_SRC_ASM_FREQ_5_SFT);
+
+       regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5986);
+       regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON5, 0x3f5987);
+       regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON6, 0x1fbd);
+       regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2, 0);
+
+       /* set iir if in_rate > out_rate */
+       if (rate_in > rate_out) {
+               int i;
+               const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out,
+                                                             &iir_coeff_num);
+
+               if (iir_coeff_num == 0 || !iir_coeff) {
+                       dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n",
+                               __func__, iir_coeff_num, iir_coeff);
+                       return -EINVAL;
+               }
+
+               /* COEFF_SRAM_CTRL */
+               regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0,
+                                  G_SRC_COEFF_SRAM_CTRL_MASK_SFT,
+                                  BIT(G_SRC_COEFF_SRAM_CTRL_SFT));
+               /* Clear coeff history to r/w coeff from the first position */
+               regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON13,
+                                  G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0);
+               /* Write SRC coeff, should not read the reg during write */
+               for (i = 0; i < iir_coeff_num; i++)
+                       regmap_write(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON12,
+                                    iir_coeff[i]);
+               /* disable sram access */
+               regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON0,
+                                  G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0);
+               /* CHSET_IIR_STAGE */
+               iir_stage = (iir_coeff_num / 6) - 1;
+               regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
+                                  G_SRC_CHSET_IIR_STAGE_MASK_SFT,
+                                  iir_stage << G_SRC_CHSET_IIR_STAGE_SFT);
+               /* CHSET_IIR_EN */
+               regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
+                                  G_SRC_CHSET_IIR_EN_MASK_SFT,
+                                  BIT(G_SRC_CHSET_IIR_EN_SFT));
+       } else {
+               /* CHSET_IIR_EN off */
+               regmap_update_bits(afe->regmap, AFE_GENERAL1_ASRC_2CH_CON2,
+                                  G_SRC_CHSET_IIR_EN_MASK_SFT, 0);
+       }
+
+       return 0;
+}
+
+static int mtk_set_src_2_param(struct mtk_base_afe *afe, int id)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+       unsigned int iir_coeff_num;
+       unsigned int iir_stage;
+       int rate_in = src_priv->dl_rate;
+       int rate_out = src_priv->ul_rate;
+       unsigned int out_freq_mode = mtk_get_src_freq_mode(afe, rate_out);
+       unsigned int in_freq_mode = mtk_get_src_freq_mode(afe, rate_in);
+
+       /* set out freq mode */
+       regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON3,
+                          G_SRC_ASM_FREQ_4_MASK_SFT,
+                          out_freq_mode << G_SRC_ASM_FREQ_4_SFT);
+
+       /* set in freq mode */
+       regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON4,
+                          G_SRC_ASM_FREQ_5_MASK_SFT,
+                          in_freq_mode << G_SRC_ASM_FREQ_5_SFT);
+
+       regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5986);
+       regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON5, 0x3f5987);
+       regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON6, 0x1fbd);
+       regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2, 0);
+
+       /* set iir if in_rate > out_rate */
+       if (rate_in > rate_out) {
+               int i;
+               const unsigned int *iir_coeff = get_iir_coeff(rate_in, rate_out,
+                                                             &iir_coeff_num);
+
+               if (iir_coeff_num == 0 || !iir_coeff) {
+                       dev_err(afe->dev, "%s(), iir coeff error, num %d, coeff %p\n",
+                                __func__, iir_coeff_num, iir_coeff);
+                       return -EINVAL;
+               }
+
+               /* COEFF_SRAM_CTRL */
+               regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0,
+                                  G_SRC_COEFF_SRAM_CTRL_MASK_SFT,
+                                  BIT(G_SRC_COEFF_SRAM_CTRL_SFT));
+               /* Clear coeff history to r/w coeff from the first position */
+               regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON13,
+                                  G_SRC_COEFF_SRAM_ADR_MASK_SFT, 0);
+               /* Write SRC coeff, should not read the reg during write */
+               for (i = 0; i < iir_coeff_num; i++)
+                       regmap_write(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON12,
+                                    iir_coeff[i]);
+               /* disable sram access */
+               regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON0,
+                                  G_SRC_COEFF_SRAM_CTRL_MASK_SFT, 0);
+               /* CHSET_IIR_STAGE */
+               iir_stage = (iir_coeff_num / 6) - 1;
+               regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
+                                  G_SRC_CHSET_IIR_STAGE_MASK_SFT,
+                                  iir_stage << G_SRC_CHSET_IIR_STAGE_SFT);
+               /* CHSET_IIR_EN */
+               regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
+                                  G_SRC_CHSET_IIR_EN_MASK_SFT,
+                                  BIT(G_SRC_CHSET_IIR_EN_SFT));
+       } else {
+               /* CHSET_IIR_EN off */
+               regmap_update_bits(afe->regmap, AFE_GENERAL2_ASRC_2CH_CON2,
+                                  G_SRC_CHSET_IIR_EN_MASK_SFT, 0);
+       }
+
+       return 0;
+}
+
+#define HW_SRC_1_EN_W_NAME "HW_SRC_1_Enable"
+#define HW_SRC_2_EN_W_NAME "HW_SRC_2_Enable"
+
+static int mtk_hw_src_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int id;
+       struct mtk_afe_src_priv *src_priv;
+       unsigned int reg;
+
+       if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0)
+               id = MT8186_DAI_SRC_1;
+       else
+               id = MT8186_DAI_SRC_2;
+
+       src_priv = afe_priv->dai_priv[id];
+
+       dev_dbg(afe->dev,
+               "%s(), name %s, event 0x%x, id %d, src_priv %p, dl_rate %d, ul_rate %d\n",
+               __func__, w->name, event, id, src_priv,
+               src_priv->dl_rate, src_priv->ul_rate);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (id == MT8186_DAI_SRC_1)
+                       mtk_set_src_1_param(afe, id);
+               else
+                       mtk_set_src_2_param(afe, id);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               reg = (id == MT8186_DAI_SRC_1) ?
+                     AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0;
+               /* ASM_ON */
+               regmap_update_bits(afe->regmap, reg,
+                                  G_SRC_ASM_ON_MASK_SFT,
+                                  BIT(G_SRC_ASM_ON_SFT));
+               /* CHSET_ON */
+               regmap_update_bits(afe->regmap, reg,
+                                  G_SRC_CHSET_ON_MASK_SFT,
+                                  BIT(G_SRC_CHSET_ON_SFT));
+               /* CHSET_STR_CLR */
+               regmap_update_bits(afe->regmap, reg,
+                                  G_SRC_CHSET_STR_CLR_MASK_SFT,
+                                  BIT(G_SRC_CHSET_STR_CLR_SFT));
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               reg = (id == MT8186_DAI_SRC_1) ?
+                     AFE_GENERAL1_ASRC_2CH_CON0 : AFE_GENERAL2_ASRC_2CH_CON0;
+               /* ASM_OFF */
+               regmap_update_bits(afe->regmap, reg, G_SRC_ASM_ON_MASK_SFT, 0);
+               /* CHSET_OFF */
+               regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_ON_MASK_SFT, 0);
+               /* CHSET_STR_CLR */
+               regmap_update_bits(afe->regmap, reg, G_SRC_CHSET_STR_CLR_MASK_SFT, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/* dai component */
+static const struct snd_kcontrol_new mtk_hw_src_1_in_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN40,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN40,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN40,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN40_1,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN40_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1 Switch", AFE_CONN40,
+                                   I_I2S0_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN40_1,
+                                   I_DL5_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_src_1_in_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN41,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN41,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN41,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN41_1,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN41_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2 Switch", AFE_CONN41,
+                                   I_I2S0_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN41_1,
+                                   I_DL5_CH2, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_src_2_in_ch1_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1 Switch", AFE_CONN42,
+                                   I_DL1_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN42,
+                                   I_DL2_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1 Switch", AFE_CONN42,
+                                   I_DL3_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN42,
+                                   I_DL4_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH1 Switch", AFE_CONN42_1,
+                                   I_DL5_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH1 Switch", AFE_CONN42_1,
+                                   I_DL6_CH1, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH1 Switch", AFE_CONN42,
+                                   I_GAIN2_OUT_CH1, 1, 0),
+};
+
+static const struct snd_kcontrol_new mtk_hw_src_2_in_ch2_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2 Switch", AFE_CONN43,
+                                   I_DL1_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN43,
+                                   I_DL2_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2 Switch", AFE_CONN43,
+                                   I_DL3_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN43,
+                                   I_DL4_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL5_CH2 Switch", AFE_CONN43_1,
+                                   I_DL5_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("DL6_CH2 Switch", AFE_CONN43_1,
+                                   I_DL6_CH2, 1, 0),
+       SOC_DAPM_SINGLE_AUTODISABLE("HW_GAIN2_OUT_CH2 Switch", AFE_CONN43,
+                                   I_GAIN2_OUT_CH2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_src_widgets[] = {
+       /* inter-connections */
+       SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_src_1_in_ch1_mix,
+                          ARRAY_SIZE(mtk_hw_src_1_in_ch1_mix)),
+       SND_SOC_DAPM_MIXER("HW_SRC_1_IN_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_src_1_in_ch2_mix,
+                          ARRAY_SIZE(mtk_hw_src_1_in_ch2_mix)),
+       SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH1", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_src_2_in_ch1_mix,
+                          ARRAY_SIZE(mtk_hw_src_2_in_ch1_mix)),
+       SND_SOC_DAPM_MIXER("HW_SRC_2_IN_CH2", SND_SOC_NOPM, 0, 0,
+                          mtk_hw_src_2_in_ch2_mix,
+                          ARRAY_SIZE(mtk_hw_src_2_in_ch2_mix)),
+
+       SND_SOC_DAPM_SUPPLY(HW_SRC_1_EN_W_NAME,
+                           GENERAL_ASRC_EN_ON, GENERAL1_ASRC_EN_ON_SFT, 0,
+                           mtk_hw_src_event,
+                           SND_SOC_DAPM_PRE_PMU |
+                           SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_SUPPLY(HW_SRC_2_EN_W_NAME,
+                           GENERAL_ASRC_EN_ON, GENERAL2_ASRC_EN_ON_SFT, 0,
+                           mtk_hw_src_event,
+                           SND_SOC_DAPM_PRE_PMU |
+                           SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_INPUT("HW SRC 1 Out Endpoint"),
+       SND_SOC_DAPM_INPUT("HW SRC 2 Out Endpoint"),
+       SND_SOC_DAPM_OUTPUT("HW SRC 1 In Endpoint"),
+       SND_SOC_DAPM_OUTPUT("HW SRC 2 In Endpoint"),
+};
+
+static int mtk_afe_src_en_connect(struct snd_soc_dapm_widget *source,
+                                 struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = source;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_src_priv *src_priv;
+
+       if (strcmp(w->name, HW_SRC_1_EN_W_NAME) == 0)
+               src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_1];
+       else
+               src_priv = afe_priv->dai_priv[MT8186_DAI_SRC_2];
+
+       dev_dbg(afe->dev,
+               "%s(), source %s, sink %s, dl_rate %d, ul_rate %d\n",
+               __func__, source->name, sink->name,
+               src_priv->dl_rate, src_priv->ul_rate);
+
+       return (src_priv->dl_rate > 0 && src_priv->ul_rate > 0) ? 1 : 0;
+}
+
+static const struct snd_soc_dapm_route mtk_dai_src_routes[] = {
+       {"HW_SRC_1_IN_CH1", "DL1_CH1 Switch", "DL1"},
+       {"HW_SRC_1_IN_CH2", "DL1_CH2 Switch", "DL1"},
+       {"HW_SRC_2_IN_CH1", "DL1_CH1 Switch", "DL1"},
+       {"HW_SRC_2_IN_CH2", "DL1_CH2 Switch", "DL1"},
+       {"HW_SRC_1_IN_CH1", "DL2_CH1 Switch", "DL2"},
+       {"HW_SRC_1_IN_CH2", "DL2_CH2 Switch", "DL2"},
+       {"HW_SRC_2_IN_CH1", "DL2_CH1 Switch", "DL2"},
+       {"HW_SRC_2_IN_CH2", "DL2_CH2 Switch", "DL2"},
+       {"HW_SRC_1_IN_CH1", "DL3_CH1 Switch", "DL3"},
+       {"HW_SRC_1_IN_CH2", "DL3_CH2 Switch", "DL3"},
+       {"HW_SRC_2_IN_CH1", "DL3_CH1 Switch", "DL3"},
+       {"HW_SRC_2_IN_CH2", "DL3_CH2 Switch", "DL3"},
+       {"HW_SRC_1_IN_CH1", "DL6_CH1 Switch", "DL6"},
+       {"HW_SRC_1_IN_CH2", "DL6_CH2 Switch", "DL6"},
+       {"HW_SRC_2_IN_CH1", "DL6_CH1 Switch", "DL6"},
+       {"HW_SRC_2_IN_CH2", "DL6_CH2 Switch", "DL6"},
+       {"HW_SRC_1_IN_CH1", "DL5_CH1 Switch", "DL5"},
+       {"HW_SRC_1_IN_CH2", "DL5_CH2 Switch", "DL5"},
+       {"HW_SRC_2_IN_CH1", "DL5_CH1 Switch", "DL5"},
+       {"HW_SRC_2_IN_CH2", "DL5_CH2 Switch", "DL5"},
+       {"HW_SRC_1_IN_CH1", "DL4_CH1 Switch", "DL4"},
+       {"HW_SRC_1_IN_CH2", "DL4_CH2 Switch", "DL4"},
+       {"HW_SRC_2_IN_CH1", "DL4_CH1 Switch", "DL4"},
+       {"HW_SRC_2_IN_CH2", "DL4_CH2 Switch", "DL4"},
+
+       {"HW_SRC_1_In", NULL, "HW_SRC_1_IN_CH1"},
+       {"HW_SRC_1_In", NULL, "HW_SRC_1_IN_CH2"},
+
+       {"HW_SRC_2_In", NULL, "HW_SRC_2_IN_CH1"},
+       {"HW_SRC_2_In", NULL, "HW_SRC_2_IN_CH2"},
+
+       {"HW_SRC_1_In", NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect},
+       {"HW_SRC_1_Out", NULL, HW_SRC_1_EN_W_NAME, mtk_afe_src_en_connect},
+       {"HW_SRC_2_In", NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect},
+       {"HW_SRC_2_Out", NULL, HW_SRC_2_EN_W_NAME, mtk_afe_src_en_connect},
+
+       {"HW SRC 1 In Endpoint", NULL, "HW_SRC_1_In"},
+       {"HW SRC 2 In Endpoint", NULL, "HW_SRC_2_In"},
+       {"HW_SRC_1_Out", NULL, "HW SRC 1 Out Endpoint"},
+       {"HW_SRC_2_Out", NULL, "HW SRC 2 Out Endpoint"},
+};
+
+/* dai ops */
+static int mtk_dai_src_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int id = dai->id;
+       struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+       unsigned int sft, mask;
+       unsigned int rate = params_rate(params);
+       unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, id);
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n",
+               __func__, id, substream->stream, rate);
+
+       /* rate */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               src_priv->dl_rate = rate;
+               if (id == MT8186_DAI_SRC_1) {
+                       sft = GENERAL1_ASRCIN_MODE_SFT;
+                       mask = GENERAL1_ASRCIN_MODE_MASK;
+               } else {
+                       sft = GENERAL2_ASRCIN_MODE_SFT;
+                       mask = GENERAL2_ASRCIN_MODE_MASK;
+               }
+       } else {
+               src_priv->ul_rate = rate;
+               if (id == MT8186_DAI_SRC_1) {
+                       sft = GENERAL1_ASRCOUT_MODE_SFT;
+                       mask = GENERAL1_ASRCOUT_MODE_MASK;
+               } else {
+                       sft = GENERAL2_ASRCOUT_MODE_SFT;
+                       mask = GENERAL2_ASRCOUT_MODE_MASK;
+               }
+       }
+
+       regmap_update_bits(afe->regmap, GENERAL_ASRC_MODE, mask << sft, rate_reg << sft);
+
+       return 0;
+}
+
+static int mtk_dai_src_hw_free(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int id = dai->id;
+       struct mtk_afe_src_priv *src_priv = afe_priv->dai_priv[id];
+
+       dev_dbg(afe->dev, "%s(), id %d, stream %d\n",
+               __func__, id, substream->stream);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               src_priv->dl_rate = 0;
+       else
+               src_priv->ul_rate = 0;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_src_ops = {
+       .hw_params = mtk_dai_src_hw_params,
+       .hw_free = mtk_dai_src_hw_free,
+};
+
+/* dai driver */
+#define MTK_SRC_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_SRC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_src_driver[] = {
+       {
+               .name = "HW_SRC_1",
+               .id = MT8186_DAI_SRC_1,
+               .playback = {
+                       .stream_name = "HW_SRC_1_In",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_SRC_RATES,
+                       .formats = MTK_SRC_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "HW_SRC_1_Out",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_SRC_RATES,
+                       .formats = MTK_SRC_FORMATS,
+               },
+               .ops = &mtk_dai_src_ops,
+       },
+       {
+               .name = "HW_SRC_2",
+               .id = MT8186_DAI_SRC_2,
+               .playback = {
+                       .stream_name = "HW_SRC_2_In",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_SRC_RATES,
+                       .formats = MTK_SRC_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "HW_SRC_2_Out",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_SRC_RATES,
+                       .formats = MTK_SRC_FORMATS,
+               },
+               .ops = &mtk_dai_src_ops,
+       },
+};
+
+int mt8186_dai_src_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+       int ret;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_src_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_src_driver);
+
+       dai->dapm_widgets = mtk_dai_src_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_src_widgets);
+       dai->dapm_routes = mtk_dai_src_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_src_routes);
+
+       /* set dai priv */
+       ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_1,
+                                 sizeof(struct mtk_afe_src_priv), NULL);
+       if (ret)
+               return ret;
+
+       ret = mt8186_dai_set_priv(afe, MT8186_DAI_SRC_2,
+                                 sizeof(struct mtk_afe_src_priv), NULL);
+       if (ret)
+               return ret;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c b/sound/soc/mediatek/mt8186/mt8186-dai-tdm.c
new file mode 100644 (file)
index 0000000..4148dce
--- /dev/null
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio DAI TDM Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-interconnection.h"
+
+#define TDM_HD_EN_W_NAME "TDM_HD_EN"
+#define TDM_MCLK_EN_W_NAME "TDM_MCLK_EN"
+#define MTK_AFE_TDM_KCONTROL_NAME "TDM_HD_Mux"
+
+struct mtk_afe_tdm_priv {
+       unsigned int id;
+       unsigned int rate; /* for determine which apll to use */
+       unsigned int bck_invert;
+       unsigned int lck_invert;
+       unsigned int lrck_width;
+       unsigned int mclk_id;
+       unsigned int mclk_multiple; /* according to sample rate */
+       unsigned int mclk_rate;
+       unsigned int mclk_apll;
+       unsigned int tdm_mode;
+       unsigned int data_mode;
+       unsigned int slave_mode;
+       unsigned int low_jitter_en;
+};
+
+enum {
+       TDM_IN_I2S = 0,
+       TDM_IN_LJ = 1,
+       TDM_IN_RJ = 2,
+       TDM_IN_DSP_A = 4,
+       TDM_IN_DSP_B = 5,
+};
+
+enum {
+       TDM_DATA_ONE_PIN = 0,
+       TDM_DATA_MULTI_PIN,
+};
+
+enum {
+       TDM_BCK_NON_INV = 0,
+       TDM_BCK_INV = 1,
+};
+
+enum {
+       TDM_LCK_NON_INV = 0,
+       TDM_LCK_INV = 1,
+};
+
+static unsigned int get_tdm_lrck_width(snd_pcm_format_t format,
+                                      unsigned int mode)
+{
+       if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
+               return 0;
+
+       return snd_pcm_format_physical_width(format) - 1;
+}
+
+static unsigned int get_tdm_ch_fixup(unsigned int channels)
+{
+       if (channels > 4)
+               return 8;
+       else if (channels > 2)
+               return 4;
+
+       return 2;
+}
+
+static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
+                                        unsigned int channels)
+{
+       if (mode == TDM_IN_DSP_A || mode == TDM_IN_DSP_B)
+               return get_tdm_ch_fixup(channels);
+
+       return 2;
+}
+
+enum {
+       SUPPLY_SEQ_APLL,
+       SUPPLY_SEQ_TDM_MCK_EN,
+       SUPPLY_SEQ_TDM_HD_EN,
+       SUPPLY_SEQ_TDM_EN,
+};
+
+static int get_tdm_id_by_name(const char *name)
+{
+       return MT8186_DAI_TDM_IN;
+}
+
+static int mtk_tdm_en_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol,
+                           int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x\n",
+               __func__, w->name, event);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_afe_gpio_request(afe->dev, true, tdm_priv->id, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               mt8186_afe_gpio_request(afe->dev, false, tdm_priv->id, 0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol,
+                               int event)
+{
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       dev_dbg(cmpnt->dev, "%s(), name %s, event 0x%x, dai_id %d\n",
+               __func__, w->name, event, dai_id);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               mt8186_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               tdm_priv->mclk_rate = 0;
+               mt8186_mck_disable(afe, tdm_priv->mclk_id);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+/* dai component */
+/* tdm virtual mux to output widget */
+static const char * const tdm_mux_map[] = {
+       "Normal", "Dummy_Widget",
+};
+
+static int tdm_mux_map_value[] = {
+       0, 1,
+};
+
+static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(tdm_mux_map_enum,
+                                             SND_SOC_NOPM,
+                                             0,
+                                             1,
+                                             tdm_mux_map,
+                                             tdm_mux_map_value);
+
+static const struct snd_kcontrol_new tdm_in_mux_control =
+       SOC_DAPM_ENUM("TDM In Select", tdm_mux_map_enum);
+
+static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
+       SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
+
+       SND_SOC_DAPM_SUPPLY_S("TDM_EN", SUPPLY_SEQ_TDM_EN,
+                             ETDM_IN1_CON0, ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT,
+                             0, mtk_tdm_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       /* tdm hd en */
+       SND_SOC_DAPM_SUPPLY_S(TDM_HD_EN_W_NAME, SUPPLY_SEQ_TDM_HD_EN,
+                             ETDM_IN1_CON2, ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT,
+                             0, NULL,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S(TDM_MCLK_EN_W_NAME, SUPPLY_SEQ_TDM_MCK_EN,
+                             SND_SOC_NOPM, 0, 0,
+                             mtk_tdm_mck_en_event,
+                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_INPUT("TDM_DUMMY_IN"),
+
+       SND_SOC_DAPM_MUX("TDM_In_Mux",
+                        SND_SOC_NOPM, 0, 0, &tdm_in_mux_control),
+};
+
+static int mtk_afe_tdm_mclk_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       return (tdm_priv->mclk_rate > 0) ? 1 : 0;
+}
+
+static int mtk_afe_tdm_mclk_apll_connect(struct snd_soc_dapm_widget *source,
+                                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+       int cur_apll;
+
+       /* which apll */
+       cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+       return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
+}
+
+static int mtk_afe_tdm_hd_connect(struct snd_soc_dapm_widget *source,
+                                 struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       return tdm_priv->low_jitter_en;
+}
+
+static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
+                                   struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget *w = sink;
+       struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(w->name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+       int cur_apll;
+       int tdm_need_apll;
+
+       /* which apll */
+       cur_apll = mt8186_get_apll_by_name(afe, source->name);
+
+       /* choose APLL from tdm rate */
+       tdm_need_apll = mt8186_get_apll_by_rate(afe, tdm_priv->rate);
+
+       return (tdm_need_apll == cur_apll) ? 1 : 0;
+}
+
+/* low jitter control */
+static const char * const mt8186_tdm_hd_str[] = {
+       "Normal", "Low_Jitter"
+};
+
+static const struct soc_enum mt8186_tdm_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_tdm_hd_str),
+                           mt8186_tdm_hd_str),
+};
+
+static int mt8186_tdm_hd_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(kcontrol->id.name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+
+       ucontrol->value.integer.value[0] = tdm_priv->low_jitter_en;
+
+       return 0;
+}
+
+static int mt8186_tdm_hd_set(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int dai_id = get_tdm_id_by_name(kcontrol->id.name);
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id];
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int hd_en;
+
+       if (ucontrol->value.enumerated.item[0] >= e->items)
+               return -EINVAL;
+
+       hd_en = ucontrol->value.integer.value[0];
+
+       dev_dbg(afe->dev, "%s(), kcontrol name %s, hd_en %d\n",
+               __func__, kcontrol->id.name, hd_en);
+
+       if (tdm_priv->low_jitter_en == hd_en)
+               return 0;
+
+       tdm_priv->low_jitter_en = hd_en;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = {
+       SOC_ENUM_EXT(MTK_AFE_TDM_KCONTROL_NAME, mt8186_tdm_enum[0],
+                    mt8186_tdm_hd_get, mt8186_tdm_hd_set),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
+       {"TDM IN", NULL, "aud_tdm_clk"},
+       {"TDM IN", NULL, "TDM_EN"},
+       {"TDM IN", NULL, TDM_HD_EN_W_NAME, mtk_afe_tdm_hd_connect},
+       {TDM_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
+       {TDM_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
+
+       {"TDM IN", NULL, TDM_MCLK_EN_W_NAME, mtk_afe_tdm_mclk_connect},
+       {TDM_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_tdm_mclk_apll_connect},
+       {TDM_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_tdm_mclk_apll_connect},
+
+       /* allow tdm on without codec on */
+       {"TDM IN", NULL, "TDM_In_Mux"},
+       {"TDM_In_Mux", "Dummy_Widget", "TDM_DUMMY_IN"},
+};
+
+/* dai ops */
+static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
+                               struct mtk_afe_tdm_priv *tdm_priv,
+                               int freq)
+{
+       int apll;
+       int apll_rate;
+
+       apll = mt8186_get_apll_by_rate(afe, freq);
+       apll_rate = mt8186_get_apll_rate(afe, apll);
+
+       if (!freq || freq > apll_rate) {
+               dev_err(afe->dev,
+                       "%s(), freq(%d Hz) invalid\n", __func__, freq);
+               return -EINVAL;
+       }
+
+       if (apll_rate % freq != 0) {
+               dev_err(afe->dev,
+                       "%s(), APLL cannot generate %d Hz", __func__, freq);
+               return -EINVAL;
+       }
+
+       tdm_priv->mclk_rate = freq;
+       tdm_priv->mclk_apll = apll;
+
+       return 0;
+}
+
+static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       int tdm_id = dai->id;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
+       unsigned int tdm_mode = tdm_priv->tdm_mode;
+       unsigned int data_mode = tdm_priv->data_mode;
+       unsigned int rate = params_rate(params);
+       unsigned int channels = params_channels(params);
+       snd_pcm_format_t format = params_format(params);
+       unsigned int bit_width =
+               snd_pcm_format_physical_width(format);
+       unsigned int tdm_channels = (data_mode == TDM_DATA_ONE_PIN) ?
+               get_tdm_ch_per_sdata(tdm_mode, channels) : 2;
+       unsigned int lrck_width =
+               get_tdm_lrck_width(format, tdm_mode);
+       unsigned int tdm_con = 0;
+       bool slave_mode = tdm_priv->slave_mode;
+       bool lrck_inv = tdm_priv->lck_invert;
+       bool bck_inv = tdm_priv->bck_invert;
+       unsigned int tran_rate;
+       unsigned int tran_relatch_rate;
+
+       tdm_priv->rate = rate;
+       tran_rate = mt8186_rate_transform(afe->dev, rate, dai->id);
+       tran_relatch_rate = mt8186_tdm_relatch_rate_transform(afe->dev, rate);
+
+       /* calculate mclk_rate, if not set explicitly */
+       if (!tdm_priv->mclk_rate) {
+               tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
+               mtk_dai_tdm_cal_mclk(afe, tdm_priv, tdm_priv->mclk_rate);
+       }
+
+       /* ETDM_IN1_CON0 */
+       tdm_con |= slave_mode << ETDM_IN1_CON0_REG_SLAVE_MODE_SFT;
+       tdm_con |= tdm_mode << ETDM_IN1_CON0_REG_FMT_SFT;
+       tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_BIT_LENGTH_SFT;
+       tdm_con |= (bit_width - 1) << ETDM_IN1_CON0_REG_WORD_LENGTH_SFT;
+       tdm_con |= (tdm_channels - 1) << ETDM_IN1_CON0_REG_CH_NUM_SFT;
+       /* need to disable sync mode otherwise this may cause latch data error */
+       tdm_con |= 0 << ETDM_IN1_CON0_REG_SYNC_MODE_SFT;
+       /* relatch 1x en clock fix to h26m */
+       tdm_con |= 0 << ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT;
+       regmap_update_bits(afe->regmap, ETDM_IN1_CON0, ETDM_IN_CON0_CTRL_MASK, tdm_con);
+
+       /* ETDM_IN1_CON1 */
+       tdm_con = 0;
+       tdm_con |= 0 << ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT;
+       tdm_con |= 1 << ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT;
+       tdm_con |= (lrck_width - 1) << ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT;
+       regmap_update_bits(afe->regmap, ETDM_IN1_CON1, ETDM_IN_CON1_CTRL_MASK, tdm_con);
+
+       /* ETDM_IN1_CON3 */
+       tdm_con = 0;
+       tdm_con = ETDM_IN_CON3_FS(tran_rate);
+       regmap_update_bits(afe->regmap, ETDM_IN1_CON3, ETDM_IN_CON3_CTRL_MASK, tdm_con);
+
+       /* ETDM_IN1_CON4 */
+       tdm_con = 0;
+       tdm_con = ETDM_IN_CON4_FS(tran_relatch_rate);
+       if (slave_mode) {
+               if (lrck_inv)
+                       tdm_con |= ETDM_IN_CON4_CON0_SLAVE_LRCK_INV;
+               if (bck_inv)
+                       tdm_con |= ETDM_IN_CON4_CON0_SLAVE_BCK_INV;
+       } else {
+               if (lrck_inv)
+                       tdm_con |= ETDM_IN_CON4_CON0_MASTER_LRCK_INV;
+               if (bck_inv)
+                       tdm_con |= ETDM_IN_CON4_CON0_MASTER_BCK_INV;
+       }
+       regmap_update_bits(afe->regmap, ETDM_IN1_CON4, ETDM_IN_CON4_CTRL_MASK, tdm_con);
+
+       /* ETDM_IN1_CON2 */
+       tdm_con = 0;
+       if (data_mode == TDM_DATA_MULTI_PIN) {
+               tdm_con |= ETDM_IN_CON2_MULTI_IP_2CH_MODE;
+               tdm_con |= ETDM_IN_CON2_MULTI_IP_CH(channels);
+       }
+       regmap_update_bits(afe->regmap, ETDM_IN1_CON2, ETDM_IN_CON2_CTRL_MASK, tdm_con);
+
+       /* ETDM_IN1_CON8 */
+       tdm_con = 0;
+       if (slave_mode) {
+               tdm_con |= 1 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
+               tdm_con |= 0 << ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT;
+               tdm_con |= ETDM_IN_CON8_FS(tran_relatch_rate);
+       } else {
+               tdm_con |= 0 << ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT;
+       }
+       regmap_update_bits(afe->regmap, ETDM_IN1_CON8, ETDM_IN_CON8_CTRL_MASK, tdm_con);
+
+       return 0;
+}
+
+static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+       if (dir != SND_SOC_CLOCK_IN) {
+               dev_err(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
+               return -EINVAL;
+       }
+
+       dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq);
+
+       return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
+}
+
+static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+       /* DAI mode*/
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               tdm_priv->tdm_mode = TDM_IN_I2S;
+               tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               tdm_priv->tdm_mode = TDM_IN_LJ;
+               tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               tdm_priv->tdm_mode = TDM_IN_RJ;
+               tdm_priv->data_mode = TDM_DATA_MULTI_PIN;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               tdm_priv->tdm_mode = TDM_IN_DSP_A;
+               tdm_priv->data_mode = TDM_DATA_ONE_PIN;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               tdm_priv->tdm_mode = TDM_IN_DSP_B;
+               tdm_priv->data_mode = TDM_DATA_ONE_PIN;
+               break;
+       default:
+               dev_err(afe->dev, "%s(), invalid DAIFMT_FORMAT_MASK", __func__);
+               return -EINVAL;
+       }
+
+       /* DAI clock inversion*/
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               tdm_priv->bck_invert = TDM_BCK_NON_INV;
+               tdm_priv->lck_invert = TDM_LCK_NON_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               tdm_priv->bck_invert = TDM_BCK_NON_INV;
+               tdm_priv->lck_invert = TDM_LCK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               tdm_priv->bck_invert = TDM_BCK_INV;
+               tdm_priv->lck_invert = TDM_LCK_NON_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               tdm_priv->bck_invert = TDM_BCK_INV;
+               tdm_priv->lck_invert = TDM_LCK_INV;
+               break;
+       default:
+               dev_err(afe->dev, "%s(), invalid DAIFMT_INV_MASK", __func__);
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
+               tdm_priv->slave_mode = false;
+               break;
+       case SND_SOC_DAIFMT_BC_FC:
+               tdm_priv->slave_mode = true;
+               break;
+       default:
+               dev_err(afe->dev, "%s(), invalid DAIFMT_CLOCK_PROVIDER_MASK",
+                       __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int mtk_dai_tdm_set_tdm_slot(struct snd_soc_dai *dai,
+                                   unsigned int tx_mask,
+                                   unsigned int rx_mask,
+                                   int slots,
+                                   int slot_width)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
+
+       dev_dbg(dai->dev, "%s %d slot_width %d\n", __func__, dai->id, slot_width);
+
+       tdm_priv->lrck_width = slot_width;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
+       .hw_params = mtk_dai_tdm_hw_params,
+       .set_sysclk = mtk_dai_tdm_set_sysclk,
+       .set_fmt = mtk_dai_tdm_set_fmt,
+       .set_tdm_slot = mtk_dai_tdm_set_tdm_slot,
+};
+
+/* dai driver */
+#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
+       {
+               .name = "TDM IN",
+               .id = MT8186_DAI_TDM_IN,
+               .capture = {
+                       .stream_name = "TDM IN",
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rates = MTK_TDM_RATES,
+                       .formats = MTK_TDM_FORMATS,
+               },
+               .ops = &mtk_dai_tdm_ops,
+       },
+};
+
+static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe)
+{
+       struct mtk_afe_tdm_priv *tdm_priv;
+
+       tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
+                               GFP_KERNEL);
+       if (!tdm_priv)
+               return NULL;
+
+       tdm_priv->mclk_multiple = 512;
+       tdm_priv->mclk_id = MT8186_TDM_MCK;
+       tdm_priv->id = MT8186_DAI_TDM_IN;
+
+       return tdm_priv;
+}
+
+int mt8186_dai_tdm_register(struct mtk_base_afe *afe)
+{
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_afe_tdm_priv *tdm_priv;
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_tdm_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
+
+       dai->controls = mtk_dai_tdm_controls;
+       dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls);
+       dai->dapm_widgets = mtk_dai_tdm_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
+       dai->dapm_routes = mtk_dai_tdm_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
+
+       tdm_priv = init_tdm_priv_data(afe);
+       if (!tdm_priv)
+               return -ENOMEM;
+
+       afe_priv->dai_priv[MT8186_DAI_TDM_IN] = tdm_priv;
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-interconnection.h b/sound/soc/mediatek/mt8186/mt8186-interconnection.h
new file mode 100644 (file)
index 0000000..5b188d9
--- /dev/null
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Mediatek MT8186 audio driver interconnection definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_INTERCONNECTION_H_
+#define _MT8186_INTERCONNECTION_H_
+
+/* in port define */
+#define I_I2S0_CH1 0
+#define I_I2S0_CH2 1
+#define I_ADDA_UL_CH1 3
+#define I_ADDA_UL_CH2 4
+#define I_DL1_CH1 5
+#define I_DL1_CH2 6
+#define I_DL2_CH1 7
+#define I_DL2_CH2 8
+#define I_PCM_1_CAP_CH1 9
+#define I_GAIN1_OUT_CH1 10
+#define I_GAIN1_OUT_CH2 11
+#define I_GAIN2_OUT_CH1 12
+#define I_GAIN2_OUT_CH2 13
+#define I_PCM_2_CAP_CH1 14
+#define I_ADDA_UL_CH3 17
+#define I_ADDA_UL_CH4 18
+#define I_DL12_CH1 19
+#define I_DL12_CH2 20
+#define I_DL12_CH3 5
+#define I_DL12_CH4 6
+#define I_PCM_2_CAP_CH2 21
+#define I_PCM_1_CAP_CH2 22
+#define I_DL3_CH1 23
+#define I_DL3_CH2 24
+#define I_I2S2_CH1 25
+#define I_I2S2_CH2 26
+#define I_I2S2_CH3 27
+#define I_I2S2_CH4 28
+
+/* in port define >= 32 */
+#define I_32_OFFSET 32
+#define I_CONNSYS_I2S_CH1 (34 - I_32_OFFSET)
+#define I_CONNSYS_I2S_CH2 (35 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH1 (36 - I_32_OFFSET)
+#define I_SRC_1_OUT_CH2 (37 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH1 (38 - I_32_OFFSET)
+#define I_SRC_2_OUT_CH2 (39 - I_32_OFFSET)
+#define I_DL4_CH1 (40 - I_32_OFFSET)
+#define I_DL4_CH2 (41 - I_32_OFFSET)
+#define I_DL5_CH1 (42 - I_32_OFFSET)
+#define I_DL5_CH2 (43 - I_32_OFFSET)
+#define I_DL6_CH1 (44 - I_32_OFFSET)
+#define I_DL6_CH2 (45 - I_32_OFFSET)
+#define I_DL7_CH1 (46 - I_32_OFFSET)
+#define I_DL7_CH2 (47 - I_32_OFFSET)
+#define I_DL8_CH1 (48 - I_32_OFFSET)
+#define I_DL8_CH2 (49 - I_32_OFFSET)
+#define I_TDM_IN_CH1 (56 - I_32_OFFSET)
+#define I_TDM_IN_CH2 (57 - I_32_OFFSET)
+#define I_TDM_IN_CH3 (58 - I_32_OFFSET)
+#define I_TDM_IN_CH4 (59 - I_32_OFFSET)
+#define I_TDM_IN_CH5 (60 - I_32_OFFSET)
+#define I_TDM_IN_CH6 (61 - I_32_OFFSET)
+#define I_TDM_IN_CH7 (62 - I_32_OFFSET)
+#define I_TDM_IN_CH8 (63 - I_32_OFFSET)
+
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-misc-control.c b/sound/soc/mediatek/mt8186/mt8186-misc-control.c
new file mode 100644 (file)
index 0000000..2317de8
--- /dev/null
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MediaTek ALSA SoC Audio Misc Control
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "../common/mtk-afe-fe-dai.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8186-afe-common.h"
+
+static const char * const mt8186_sgen_mode_str[] = {
+       "I0I1",   "I2",     "I3I4",   "I5I6",
+       "I7I8",   "I9I22",  "I10I11", "I12I13",
+       "I14I21", "I15I16", "I17I18", "I19I20",
+       "I23I24", "I25I26", "I27I28", "I33",
+       "I34I35", "I36I37", "I38I39", "I40I41",
+       "I42I43", "I44I45", "I46I47", "I48I49",
+       "I56I57", "I58I59", "I60I61", "I62I63",
+       "O0O1",   "O2",     "O3O4",   "O5O6",
+       "O7O8",   "O9O10",  "O11",    "O12",
+       "O13O14", "O15O16", "O17O18", "O19O20",
+       "O21O22", "O23O24", "O25",    "O28O29",
+       "O34",    "O35",    "O32O33", "O36O37",
+       "O38O39", "O30O31", "O40O41", "O42O43",
+       "O44O45", "O46O47", "O48O49", "O50O51",
+       "O58O59", "O60O61", "O62O63", "O64O65",
+       "O66O67", "O68O69", "O26O27", "OFF",
+};
+
+static const int mt8186_sgen_mode_idx[] = {
+       0, 2, 4, 6,
+       8, 22, 10, 12,
+       14, -1, 18, 20,
+       24, 26, 28, 33,
+       34, 36, 38, 40,
+       42, 44, 46, 48,
+       56, 58, 60, 62,
+       128, 130, 132, 134,
+       135, 138, 139, 140,
+       142, 144, 166, 148,
+       150, 152, 153, 156,
+       162, 163, 160, 164,
+       166, -1, 168, 170,
+       172, 174, 176, 178,
+       186, 188, 190, 192,
+       194, 196, -1, -1,
+};
+
+static const char * const mt8186_sgen_rate_str[] = {
+       "8K", "11K", "12K", "16K",
+       "22K", "24K", "32K", "44K",
+       "48K", "88k", "96k", "176k",
+       "192k"
+};
+
+static const int mt8186_sgen_rate_idx[] = {
+       0, 1, 2, 4,
+       5, 6, 8, 9,
+       10, 11, 12, 13,
+       14
+};
+
+/* this order must match reg bit amp_div_ch1/2 */
+static const char * const mt8186_sgen_amp_str[] = {
+       "1/128", "1/64", "1/32", "1/16", "1/8", "1/4", "1/2", "1" };
+
+static int mt8186_sgen_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->sgen_mode;
+
+       return 0;
+}
+
+static int mt8186_sgen_set(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int mode;
+       int mode_idx;
+
+       if (ucontrol->value.enumerated.item[0] >= e->items)
+               return -EINVAL;
+
+       mode = ucontrol->value.integer.value[0];
+       mode_idx = mt8186_sgen_mode_idx[mode];
+
+       dev_dbg(afe->dev, "%s(), mode %d, mode_idx %d\n",
+               __func__, mode, mode_idx);
+
+       if (mode == afe_priv->sgen_mode)
+               return 0;
+
+       if (mode_idx >= 0) {
+               regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+                                  INNER_LOOP_BACK_MODE_MASK_SFT,
+                                  mode_idx << INNER_LOOP_BACK_MODE_SFT);
+               regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+                                  DAC_EN_MASK_SFT, BIT(DAC_EN_SFT));
+       } else {
+               /* disable sgen */
+               regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+                                  DAC_EN_MASK_SFT, 0);
+               regmap_update_bits(afe->regmap, AFE_SINEGEN_CON2,
+                                  INNER_LOOP_BACK_MODE_MASK_SFT,
+                                  0x3f << INNER_LOOP_BACK_MODE_SFT);
+       }
+
+       afe_priv->sgen_mode = mode;
+
+       return 1;
+}
+
+static int mt8186_sgen_rate_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->sgen_rate;
+
+       return 0;
+}
+
+static int mt8186_sgen_rate_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int rate;
+
+       if (ucontrol->value.enumerated.item[0] >= e->items)
+               return -EINVAL;
+
+       rate = ucontrol->value.integer.value[0];
+
+       dev_dbg(afe->dev, "%s(), rate %d\n", __func__, rate);
+
+       if (rate == afe_priv->sgen_rate)
+               return 0;
+
+       regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+                          SINE_MODE_CH1_MASK_SFT,
+                          mt8186_sgen_rate_idx[rate] << SINE_MODE_CH1_SFT);
+
+       regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+                          SINE_MODE_CH2_MASK_SFT,
+                          mt8186_sgen_rate_idx[rate] << SINE_MODE_CH2_SFT);
+
+       afe_priv->sgen_rate = rate;
+
+       return 1;
+}
+
+static int mt8186_sgen_amplitude_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+
+       ucontrol->value.integer.value[0] = afe_priv->sgen_amplitude;
+       return 0;
+}
+
+static int mt8186_sgen_amplitude_set(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       int amplitude;
+
+       if (ucontrol->value.enumerated.item[0] >= e->items)
+               return -EINVAL;
+
+       amplitude = ucontrol->value.integer.value[0];
+       if (amplitude > AMP_DIV_CH1_MASK) {
+               dev_err(afe->dev, "%s(), amplitude %d invalid\n",
+                       __func__, amplitude);
+               return -EINVAL;
+       }
+
+       dev_dbg(afe->dev, "%s(), amplitude %d\n", __func__, amplitude);
+
+       if (amplitude == afe_priv->sgen_amplitude)
+               return 0;
+
+       regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+                          AMP_DIV_CH1_MASK_SFT,
+                          amplitude << AMP_DIV_CH1_SFT);
+       regmap_update_bits(afe->regmap, AFE_SINEGEN_CON0,
+                          AMP_DIV_CH2_MASK_SFT,
+                          amplitude << AMP_DIV_CH2_SFT);
+
+       afe_priv->sgen_amplitude = amplitude;
+
+       return 1;
+}
+
+static const struct soc_enum mt8186_afe_sgen_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_mode_str),
+                           mt8186_sgen_mode_str),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_rate_str),
+                           mt8186_sgen_rate_str),
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8186_sgen_amp_str),
+                           mt8186_sgen_amp_str),
+};
+
+static const struct snd_kcontrol_new mt8186_afe_sgen_controls[] = {
+       SOC_ENUM_EXT("Audio_SineGen_Switch", mt8186_afe_sgen_enum[0],
+                    mt8186_sgen_get, mt8186_sgen_set),
+       SOC_ENUM_EXT("Audio_SineGen_SampleRate", mt8186_afe_sgen_enum[1],
+                    mt8186_sgen_rate_get, mt8186_sgen_rate_set),
+       SOC_ENUM_EXT("Audio_SineGen_Amplitude", mt8186_afe_sgen_enum[2],
+                    mt8186_sgen_amplitude_get, mt8186_sgen_amplitude_set),
+       SOC_SINGLE("Audio_SineGen_Mute_Ch1", AFE_SINEGEN_CON0,
+                  MUTE_SW_CH1_MASK_SFT, MUTE_SW_CH1_MASK, 0),
+       SOC_SINGLE("Audio_SineGen_Mute_Ch2", AFE_SINEGEN_CON0,
+                  MUTE_SW_CH2_MASK_SFT, MUTE_SW_CH2_MASK, 0),
+       SOC_SINGLE("Audio_SineGen_Freq_Div_Ch1", AFE_SINEGEN_CON0,
+                  FREQ_DIV_CH1_SFT, FREQ_DIV_CH1_MASK, 0),
+       SOC_SINGLE("Audio_SineGen_Freq_Div_Ch2", AFE_SINEGEN_CON0,
+                  FREQ_DIV_CH2_SFT, FREQ_DIV_CH2_MASK, 0),
+};
+
+int mt8186_add_misc_control(struct snd_soc_component *component)
+{
+       snd_soc_add_component_controls(component,
+                                      mt8186_afe_sgen_controls,
+                                      ARRAY_SIZE(mt8186_afe_sgen_controls));
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.c
new file mode 100644 (file)
index 0000000..4e66603
--- /dev/null
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-mt6366-common.c
+//     --  MT8186 MT6366 ALSA common driver
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+//
+#include <sound/soc.h>
+
+#include "../../codecs/mt6358.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-mt6366-common.h"
+
+int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_afe =
+               snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
+       struct mt8186_afe_private *afe_priv = afe->platform_priv;
+       struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+       int ret;
+
+       /* set mtkaif protocol */
+       mt6358_set_mtkaif_protocol(cmpnt_codec,
+                                  MT6358_MTKAIF_PROTOCOL_1);
+       afe_priv->mtkaif_protocol = MT6358_MTKAIF_PROTOCOL_1;
+
+       ret = snd_soc_dapm_sync(dapm);
+       if (ret) {
+               dev_err(rtd->dev, "failed to snd_soc_dapm_sync\n");
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mt8186_mt6366_init);
+
+int mt8186_mt6366_card_set_be_link(struct snd_soc_card *card,
+                                  struct snd_soc_dai_link *link,
+                                  struct device_node *node,
+                                  char *link_name)
+{
+       int ret;
+
+       if (node && strcmp(link->name, link_name) == 0) {
+               ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link);
+               if (ret < 0)
+                       return dev_err_probe(card->dev, ret, "get dai link codecs fail\n");
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mt8186_mt6366_card_set_be_link);
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-common.h b/sound/soc/mediatek/mt8186/mt8186-mt6366-common.h
new file mode 100644 (file)
index 0000000..907d8f5
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt8186-mt6366-common.h
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_MT6366_COMMON_H_
+#define _MT8186_MT6366_COMMON_H_
+
+int mt8186_mt6366_init(struct snd_soc_pcm_runtime *rtd);
+int mt8186_mt6366_card_set_be_link(struct snd_soc_card *card,
+                                  struct snd_soc_dai_link *link,
+                                  struct device_node *node,
+                                  char *link_name);
+#endif
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
new file mode 100644 (file)
index 0000000..387f25c
--- /dev/null
@@ -0,0 +1,1002 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-mt6366-da7219-max98357.c
+//     --  MT8186-MT6366-DA7219-MAX98357 ALSA SoC machine driver
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../../codecs/da7219-aad.h"
+#include "../../codecs/da7219.h"
+#include "../../codecs/mt6358.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-mt6366-common.h"
+
+#define DA7219_CODEC_DAI "da7219-hifi"
+#define DA7219_DEV_NAME "da7219.5-001a"
+
+struct mt8186_mt6366_da7219_max98357_priv {
+       struct snd_soc_jack headset_jack, hdmi_jack;
+};
+
+static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF("mt6358-sound"),
+               .name_prefix = "Mt6366",
+       },
+       {
+               .dlc = COMP_CODEC_CONF("bt-sco"),
+               .name_prefix = "Mt8186 bt",
+       },
+       {
+               .dlc = COMP_CODEC_CONF("hdmi-audio-codec"),
+               .name_prefix = "Mt8186 hdmi",
+       },
+};
+
+static int mt8186_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct mt8186_mt6366_da7219_max98357_priv *priv =
+               snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_jack *jack = &priv->headset_jack;
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       int ret;
+
+       /* Enable Headset and 4 Buttons Jack detection */
+       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                   SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                   jack);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+       da7219_aad_jack_det(cmpnt_codec, &priv->headset_jack);
+
+       return 0;
+}
+
+static int mt8186_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
+                                      struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai;
+       unsigned int rate = params_rate(params);
+       unsigned int mclk_fs_ratio = 256;
+       unsigned int mclk_fs = rate * mclk_fs_ratio;
+       unsigned int freq;
+       int ret, j;
+
+       ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0,
+                                    mclk_fs, SND_SOC_CLOCK_OUT);
+       if (ret < 0) {
+               dev_err(rtd->dev, "failed to set cpu dai sysclk: %d\n", ret);
+               return ret;
+       }
+
+       for_each_rtd_codec_dais(rtd, j, codec_dai) {
+               if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) {
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                                    DA7219_CLKSRC_MCLK,
+                                                    mclk_fs,
+                                                    SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "failed to set sysclk: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       if ((rate % 8000) == 0)
+                               freq = DA7219_PLL_FREQ_OUT_98304;
+                       else
+                               freq = DA7219_PLL_FREQ_OUT_90316;
+
+                       ret = snd_soc_dai_set_pll(codec_dai, 0,
+                                                 DA7219_SYSCLK_PLL_SRM,
+                                                 0, freq);
+                       if (ret) {
+                               dev_err(rtd->dev, "failed to start PLL: %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int mt8186_da7219_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *codec_dai;
+       int ret = 0, j;
+
+       for_each_rtd_codec_dais(rtd, j, codec_dai) {
+               if (!strcmp(codec_dai->component->name, DA7219_DEV_NAME)) {
+                       ret = snd_soc_dai_set_pll(codec_dai,
+                                                 0, DA7219_SYSCLK_MCLK, 0, 0);
+                       if (ret < 0) {
+                               dev_err(rtd->dev, "failed to stop PLL: %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8186_da7219_i2s_ops = {
+       .hw_params = mt8186_da7219_i2s_hw_params,
+       .hw_free = mt8186_da7219_i2s_hw_free,
+};
+
+static int mt8186_mt6366_da7219_max98357_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct mt8186_mt6366_da7219_max98357_priv *priv =
+               snd_soc_card_get_drvdata(rtd->card);
+       int ret;
+
+       ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack);
+       if (ret) {
+               dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+}
+
+static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                 struct snd_pcm_hw_params *params,
+                                 snd_pcm_format_t fmt)
+{
+       struct snd_interval *channels = hw_param_interval(params,
+               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt);
+
+       /* fix BE i2s channel to 2 channel */
+       channels->min = 2;
+       channels->max = 2;
+
+       /* clean param mask first */
+       snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+                            0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+
+       params_set_format(params, fmt);
+
+       return 0;
+}
+
+static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                     struct snd_pcm_hw_params *params)
+{
+       return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE);
+}
+
+static int mt8186_anx7625_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                             struct snd_pcm_hw_params *params)
+{
+       return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
+}
+
+static int mt8186_mt6366_da7219_max98357_playback_startup(struct snd_pcm_substream *substream)
+{
+       static const unsigned int rates[] = {
+               48000
+       };
+       static const unsigned int channels[] = {
+               2
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list  = rates,
+               .mask = 0,
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_channels = {
+               .count = ARRAY_SIZE(channels),
+               .list  = channels,
+               .mask = 0,
+       };
+
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_RATE,
+                                        &constraints_rates);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list rate failed\n");
+               return ret;
+       }
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_CHANNELS,
+                                        &constraints_channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list channel failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8186_mt6366_da7219_max98357_playback_ops = {
+       .startup = mt8186_mt6366_da7219_max98357_playback_startup,
+};
+
+static int mt8186_mt6366_da7219_max98357_capture_startup(struct snd_pcm_substream *substream)
+{
+       static const unsigned int rates[] = {
+               48000
+       };
+       static const unsigned int channels[] = {
+               1, 2
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list  = rates,
+               .mask = 0,
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_channels = {
+               .count = ARRAY_SIZE(channels),
+               .list  = channels,
+               .mask = 0,
+       };
+
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_RATE,
+                                        &constraints_rates);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list rate failed\n");
+               return ret;
+       }
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_CHANNELS,
+                                        &constraints_channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list channel failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8186_mt6366_da7219_max98357_capture_ops = {
+       .startup = mt8186_mt6366_da7219_max98357_capture_startup,
+};
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback12,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback4,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback8,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture4,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* hostless */
+SND_SOC_DAILINK_DEFS(hostless_lpbk,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_fm,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_src1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_src_bargein,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* BE */
+SND_SOC_DAILINK_DEFS(adda,
+                    DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound",
+                                                  "mt6358-snd-codec-aif1"),
+                                       COMP_CODEC("dmic-codec",
+                                                  "dmic-hifi")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s0,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_gain1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_gain2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_src1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_src2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(connsys_i2s,
+                    DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(pcm1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(tdm_in,
+                    DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* hostless */
+SND_SOC_DAILINK_DEFS(hostless_ul1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_src_aaudio,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+static struct snd_soc_dai_link mt8186_mt6366_da7219_max98357_dai_links[] = {
+       /* Front End DAI links */
+       {
+               .name = "Playback_1",
+               .stream_name = "Playback_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_da7219_max98357_playback_ops,
+               SND_SOC_DAILINK_REG(playback1),
+       },
+       {
+               .name = "Playback_12",
+               .stream_name = "Playback_12",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback12),
+       },
+       {
+               .name = "Playback_2",
+               .stream_name = "Playback_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               SND_SOC_DAILINK_REG(playback2),
+       },
+       {
+               .name = "Playback_3",
+               .stream_name = "Playback_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_da7219_max98357_playback_ops,
+               SND_SOC_DAILINK_REG(playback3),
+       },
+       {
+               .name = "Playback_4",
+               .stream_name = "Playback_4",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback4),
+       },
+       {
+               .name = "Playback_5",
+               .stream_name = "Playback_5",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback5),
+       },
+       {
+               .name = "Playback_6",
+               .stream_name = "Playback_6",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback6),
+       },
+       {
+               .name = "Playback_7",
+               .stream_name = "Playback_7",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback7),
+       },
+       {
+               .name = "Playback_8",
+               .stream_name = "Playback_8",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback8),
+       },
+       {
+               .name = "Capture_1",
+               .stream_name = "Capture_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture1),
+       },
+       {
+               .name = "Capture_2",
+               .stream_name = "Capture_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_da7219_max98357_capture_ops,
+               SND_SOC_DAILINK_REG(capture2),
+       },
+       {
+               .name = "Capture_3",
+               .stream_name = "Capture_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture3),
+       },
+       {
+               .name = "Capture_4",
+               .stream_name = "Capture_4",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_da7219_max98357_capture_ops,
+               SND_SOC_DAILINK_REG(capture4),
+       },
+       {
+               .name = "Capture_5",
+               .stream_name = "Capture_5",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture5),
+       },
+       {
+               .name = "Capture_6",
+               .stream_name = "Capture_6",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               SND_SOC_DAILINK_REG(capture6),
+       },
+       {
+               .name = "Capture_7",
+               .stream_name = "Capture_7",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture7),
+       },
+       {
+               .name = "Hostless_LPBK",
+               .stream_name = "Hostless_LPBK",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_lpbk),
+       },
+       {
+               .name = "Hostless_FM",
+               .stream_name = "Hostless_FM",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_fm),
+       },
+       {
+               .name = "Hostless_SRC_1",
+               .stream_name = "Hostless_SRC_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_src1),
+       },
+       {
+               .name = "Hostless_SRC_Bargein",
+               .stream_name = "Hostless_SRC_Bargein",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_src_bargein),
+       },
+       {
+               .name = "Hostless_HW_Gain_AAudio",
+               .stream_name = "Hostless_HW_Gain_AAudio",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio),
+       },
+       {
+               .name = "Hostless_SRC_AAudio",
+               .stream_name = "Hostless_SRC_AAudio",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_src_aaudio),
+       },
+       /* Back End DAI links */
+       {
+               .name = "Primary Codec",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .init = mt8186_mt6366_init,
+               SND_SOC_DAILINK_REG(adda),
+       },
+       {
+               .name = "I2S3",
+               .no_pcm = 1,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                          SND_SOC_DAIFMT_IB_IF |
+                          SND_SOC_DAIFMT_CBM_CFM,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .init = mt8186_mt6366_da7219_max98357_hdmi_init,
+               .be_hw_params_fixup = mt8186_anx7625_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s3),
+       },
+       {
+               .name = "I2S0",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
+               .ops = &mt8186_da7219_i2s_ops,
+               SND_SOC_DAILINK_REG(i2s0),
+       },
+       {
+               .name = "I2S1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
+               .init = mt8186_da7219_init,
+               .ops = &mt8186_da7219_i2s_ops,
+               SND_SOC_DAILINK_REG(i2s1),
+       },
+       {
+               .name = "I2S2",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s2),
+       },
+       {
+               .name = "HW Gain 1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_gain1),
+       },
+       {
+               .name = "HW Gain 2",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_gain2),
+       },
+       {
+               .name = "HW_SRC_1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_src1),
+       },
+       {
+               .name = "HW_SRC_2",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_src2),
+       },
+       {
+               .name = "CONNSYS_I2S",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(connsys_i2s),
+       },
+       {
+               .name = "PCM 1",
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                          SND_SOC_DAIFMT_NB_IF,
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(pcm1),
+       },
+       {
+               .name = "TDM IN",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(tdm_in),
+       },
+       /* dummy BE for ul memif to record from dl memif */
+       {
+               .name = "Hostless_UL1",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul1),
+       },
+       {
+               .name = "Hostless_UL2",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul2),
+       },
+       {
+               .name = "Hostless_UL3",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul3),
+       },
+       {
+               .name = "Hostless_UL5",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul5),
+       },
+       {
+               .name = "Hostless_UL6",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul6),
+       },
+};
+
+static const struct snd_soc_dapm_widget
+mt8186_mt6366_da7219_max98357_widgets[] = {
+       SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_OUTPUT("HDMI1"),
+};
+
+static const struct snd_soc_dapm_route
+mt8186_mt6366_da7219_max98357_routes[] = {
+       /* SPK */
+       { "Speakers", NULL, "Speaker"},
+       /* HDMI */
+       { "HDMI1", NULL, "TX"},
+};
+
+static const struct snd_kcontrol_new
+mt8186_mt6366_da7219_max98357_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("HDMI1"),
+};
+
+static struct snd_soc_card mt8186_mt6366_da7219_max98357_soc_card = {
+       .name = "mt8186_mt6366_da7219_max98357",
+       .owner = THIS_MODULE,
+       .dai_link = mt8186_mt6366_da7219_max98357_dai_links,
+       .num_links = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_dai_links),
+       .controls = mt8186_mt6366_da7219_max98357_controls,
+       .num_controls = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_controls),
+       .dapm_widgets = mt8186_mt6366_da7219_max98357_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_widgets),
+       .dapm_routes = mt8186_mt6366_da7219_max98357_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_routes),
+       .codec_conf = mt8186_mt6366_da7219_max98357_codec_conf,
+       .num_configs = ARRAY_SIZE(mt8186_mt6366_da7219_max98357_codec_conf),
+};
+
+static int mt8186_mt6366_da7219_max98357_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct snd_soc_dai_link *dai_link;
+       struct mt8186_mt6366_da7219_max98357_priv *priv;
+       struct device_node *platform_node, *headset_codec, *playback_codec;
+       int ret, i;
+
+       card = (struct snd_soc_card *)device_get_match_data(&pdev->dev);
+       if (!card)
+               return -EINVAL;
+       card->dev = &pdev->dev;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
+       if (!platform_node) {
+               ret = -EINVAL;
+               dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
+               return ret;
+       }
+
+       playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs");
+       if (!playback_codec) {
+               ret = -EINVAL;
+               dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n");
+               goto err_playback_codec;
+       }
+
+       headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec");
+       if (!headset_codec) {
+               ret = -EINVAL;
+               dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n");
+               goto err_headset_codec;
+       }
+
+       for_each_card_prelinks(card, i, dai_link) {
+               ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3");
+               if (ret) {
+                       dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n",
+                                     dai_link->name);
+                       goto err_probe;
+               }
+
+               ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0");
+               if (ret) {
+                       dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+                                     dai_link->name);
+                       goto err_probe;
+               }
+
+               ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1");
+               if (ret) {
+                       dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+                                     dai_link->name);
+                       goto err_probe;
+               }
+
+               if (!dai_link->platforms->name)
+                       dai_link->platforms->of_node = platform_node;
+       }
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               ret = -ENOMEM;
+               goto err_probe;
+       }
+
+       snd_soc_card_set_drvdata(card, priv);
+
+       ret = mt8186_afe_gpio_init(&pdev->dev);
+       if (ret) {
+               dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__);
+               goto err_probe;
+       }
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret)
+               dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
+
+err_probe:
+       of_node_put(headset_codec);
+err_headset_codec:
+       of_node_put(playback_codec);
+err_playback_codec:
+       of_node_put(platform_node);
+
+       return ret;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt8186_mt6366_da7219_max98357_dt_match[] = {
+       {       .compatible = "mediatek,mt8186-mt6366-da7219-max98357-sound",
+               .data = &mt8186_mt6366_da7219_max98357_soc_card,
+       },
+       {}
+};
+#endif
+
+static struct platform_driver mt8186_mt6366_da7219_max98357_driver = {
+       .driver = {
+               .name = "mt8186_mt6366_da7219_max98357",
+#if IS_ENABLED(CONFIG_OF)
+               .of_match_table = mt8186_mt6366_da7219_max98357_dt_match,
+#endif
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = mt8186_mt6366_da7219_max98357_dev_probe,
+};
+
+module_platform_driver(mt8186_mt6366_da7219_max98357_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8186-MT6366-DA7219-MAX98357 ALSA SoC machine driver");
+MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt8186_mt6366_da7219_max98357 soc card");
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c b/sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
new file mode 100644 (file)
index 0000000..891146f
--- /dev/null
@@ -0,0 +1,978 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mt8186-mt6366-rt1019-rt5682s.c
+//     --  MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver
+//
+// Copyright (c) 2022 MediaTek Inc.
+// Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+//
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/jack.h>
+#include <sound/pcm_params.h>
+#include <sound/rt5682.h>
+#include <sound/soc.h>
+
+#include "../../codecs/mt6358.h"
+#include "../../codecs/rt5682.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "mt8186-afe-common.h"
+#include "mt8186-afe-clk.h"
+#include "mt8186-afe-gpio.h"
+#include "mt8186-mt6366-common.h"
+
+#define RT1019_CODEC_DAI       "HiFi"
+#define RT1019_DEV0_NAME       "rt1019p"
+
+#define RT5682S_CODEC_DAI      "rt5682s-aif1"
+#define RT5682S_DEV0_NAME      "rt5682s.5-001a"
+
+struct mt8186_mt6366_rt1019_rt5682s_priv {
+       struct snd_soc_jack headset_jack, hdmi_jack;
+};
+
+static struct snd_soc_codec_conf mt8186_mt6366_rt1019_rt5682s_codec_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF("mt6358-sound"),
+               .name_prefix = "Mt6366",
+       },
+       {
+               .dlc = COMP_CODEC_CONF("bt-sco"),
+               .name_prefix = "Mt8186 bt",
+       },
+       {
+               .dlc = COMP_CODEC_CONF("hdmi-audio-codec"),
+               .name_prefix = "Mt8186 hdmi",
+       },
+};
+
+static int mt8186_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct mt8186_mt6366_rt1019_rt5682s_priv *priv =
+               snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_jack *jack = &priv->headset_jack;
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       int ret;
+
+       ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                   SND_JACK_BTN_3,
+                                   jack);
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       return snd_soc_component_set_jack(cmpnt_codec, jack, NULL);
+}
+
+static int mt8186_rt5682s_i2s_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_card *card = rtd->card;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       unsigned int rate = params_rate(params);
+       unsigned int mclk_fs_ratio = 128;
+       unsigned int mclk_fs = rate * mclk_fs_ratio;
+       int bitwidth;
+       int ret;
+
+       bitwidth = snd_pcm_format_width(params_format(params));
+       if (bitwidth < 0) {
+               dev_err(card->dev, "invalid bit width: %d\n", bitwidth);
+               return bitwidth;
+       }
+
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x00, 0x0, 0x2, bitwidth);
+       if (ret) {
+               dev_err(card->dev, "failed to set tdm slot\n");
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1,
+                                 RT5682_PLL1_S_BCLK1,
+                                 params_rate(params) * 64,
+                                 params_rate(params) * 512);
+       if (ret) {
+               dev_err(card->dev, "failed to set pll\n");
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                    RT5682_SCLK_S_PLL1,
+                                    params_rate(params) * 512,
+                                    SND_SOC_CLOCK_IN);
+       if (ret) {
+               dev_err(card->dev, "failed to set sysclk\n");
+               return ret;
+       }
+
+       return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT);
+}
+
+static const struct snd_soc_ops mt8186_rt5682s_i2s_ops = {
+       .hw_params = mt8186_rt5682s_i2s_hw_params,
+};
+
+static int mt8186_mt6366_rt1019_rt5682s_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_component *cmpnt_codec =
+               asoc_rtd_to_codec(rtd, 0)->component;
+       struct mt8186_mt6366_rt1019_rt5682s_priv *priv =
+               snd_soc_card_get_drvdata(rtd->card);
+       int ret;
+
+       ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT, &priv->hdmi_jack);
+       if (ret) {
+               dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_component_set_jack(cmpnt_codec, &priv->hdmi_jack, NULL);
+}
+
+static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                 struct snd_pcm_hw_params *params,
+                                 snd_pcm_format_t fmt)
+{
+       struct snd_interval *channels = hw_param_interval(params,
+               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       dev_dbg(rtd->dev, "%s(), fix format to %d\n", __func__, fmt);
+
+       /* fix BE i2s channel to 2 channel */
+       channels->min = 2;
+       channels->max = 2;
+
+       /* clean param mask first */
+       snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
+                            0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+
+       params_set_format(params, fmt);
+
+       return 0;
+}
+
+static int mt8186_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                     struct snd_pcm_hw_params *params)
+{
+       return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
+}
+
+static int mt8186_it6505_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                            struct snd_pcm_hw_params *params)
+{
+       return mt8186_hw_params_fixup(rtd, params, SNDRV_PCM_FORMAT_S32_LE);
+}
+
+static int mt8186_mt6366_rt1019_rt5682s_playback_startup(struct snd_pcm_substream *substream)
+{
+       static const unsigned int rates[] = {
+               48000
+       };
+       static const unsigned int channels[] = {
+               2
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list  = rates,
+               .mask = 0,
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_channels = {
+               .count = ARRAY_SIZE(channels),
+               .list  = channels,
+               .mask = 0,
+       };
+
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_RATE,
+                                        &constraints_rates);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list rate failed\n");
+               return ret;
+       }
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_CHANNELS,
+                                        &constraints_channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list channel failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_playback_ops = {
+       .startup = mt8186_mt6366_rt1019_rt5682s_playback_startup,
+};
+
+static int mt8186_mt6366_rt1019_rt5682s_capture_startup(struct snd_pcm_substream *substream)
+{
+       static const unsigned int rates[] = {
+               48000
+       };
+       static const unsigned int channels[] = {
+               1, 2
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list  = rates,
+               .mask = 0,
+       };
+       static const struct snd_pcm_hw_constraint_list constraints_channels = {
+               .count = ARRAY_SIZE(channels),
+               .list  = channels,
+               .mask = 0,
+       };
+
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_RATE,
+                                        &constraints_rates);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list rate failed\n");
+               return ret;
+       }
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_CHANNELS,
+                                        &constraints_channels);
+       if (ret < 0) {
+               dev_err(rtd->dev, "hw_constraint_list channel failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_ops mt8186_mt6366_rt1019_rt5682s_capture_ops = {
+       .startup = mt8186_mt6366_rt1019_rt5682s_capture_startup,
+};
+
+/* FE */
+SND_SOC_DAILINK_DEFS(playback1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback12,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL12")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback4,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL4")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(playback8,
+                    DAILINK_COMP_ARRAY(COMP_CPU("DL8")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL3")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture4,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL4")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL5")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL6")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture7,
+                    DAILINK_COMP_ARRAY(COMP_CPU("UL7")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* hostless */
+SND_SOC_DAILINK_DEFS(hostless_lpbk,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless LPBK DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_fm,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless FM DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_src1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_1_DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_src_bargein,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_SRC_Bargein_DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* BE */
+SND_SOC_DAILINK_DEFS(adda,
+                    DAILINK_COMP_ARRAY(COMP_CPU("ADDA")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("mt6358-sound",
+                                                  "mt6358-snd-codec-aif1"),
+                                       COMP_CODEC("dmic-codec",
+                                                  "dmic-hifi")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s0,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S0")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S1")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(i2s3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("I2S3")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_gain1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_gain2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW Gain 2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_src1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_1")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hw_src2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("HW_SRC_2")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(connsys_i2s,
+                    DAILINK_COMP_ARRAY(COMP_CPU("CONNSYS_I2S")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(pcm1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("PCM 1")),
+                    DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm-wb")),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(tdm_in,
+                    DAILINK_COMP_ARRAY(COMP_CPU("TDM IN")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+/* hostless */
+SND_SOC_DAILINK_DEFS(hostless_ul1,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL1 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul2,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL2 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul3,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL3 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul5,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL5 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_ul6,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless_UL6 DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_hw_gain_aaudio,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless HW Gain AAudio DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(hostless_src_aaudio,
+                    DAILINK_COMP_ARRAY(COMP_CPU("Hostless SRC AAudio DAI")),
+                    DAILINK_COMP_ARRAY(COMP_DUMMY()),
+                    DAILINK_COMP_ARRAY(COMP_EMPTY()));
+static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
+       /* Front End DAI links */
+       {
+               .name = "Playback_1",
+               .stream_name = "Playback_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops,
+               SND_SOC_DAILINK_REG(playback1),
+       },
+       {
+               .name = "Playback_12",
+               .stream_name = "Playback_12",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback12),
+       },
+       {
+               .name = "Playback_2",
+               .stream_name = "Playback_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               SND_SOC_DAILINK_REG(playback2),
+       },
+       {
+               .name = "Playback_3",
+               .stream_name = "Playback_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_rt1019_rt5682s_playback_ops,
+               SND_SOC_DAILINK_REG(playback3),
+       },
+       {
+               .name = "Playback_4",
+               .stream_name = "Playback_4",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback4),
+       },
+       {
+               .name = "Playback_5",
+               .stream_name = "Playback_5",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback5),
+       },
+       {
+               .name = "Playback_6",
+               .stream_name = "Playback_6",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback6),
+       },
+       {
+               .name = "Playback_7",
+               .stream_name = "Playback_7",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback7),
+       },
+       {
+               .name = "Playback_8",
+               .stream_name = "Playback_8",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback8),
+       },
+       {
+               .name = "Capture_1",
+               .stream_name = "Capture_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture1),
+       },
+       {
+               .name = "Capture_2",
+               .stream_name = "Capture_2",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops,
+               SND_SOC_DAILINK_REG(capture2),
+       },
+       {
+               .name = "Capture_3",
+               .stream_name = "Capture_3",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture3),
+       },
+       {
+               .name = "Capture_4",
+               .stream_name = "Capture_4",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .ops = &mt8186_mt6366_rt1019_rt5682s_capture_ops,
+               SND_SOC_DAILINK_REG(capture4),
+       },
+       {
+               .name = "Capture_5",
+               .stream_name = "Capture_5",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture5),
+       },
+       {
+               .name = "Capture_6",
+               .stream_name = "Capture_6",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .dpcm_merged_format = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               SND_SOC_DAILINK_REG(capture6),
+       },
+       {
+               .name = "Capture_7",
+               .stream_name = "Capture_7",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture7),
+       },
+       {
+               .name = "Hostless_LPBK",
+               .stream_name = "Hostless_LPBK",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_lpbk),
+       },
+       {
+               .name = "Hostless_FM",
+               .stream_name = "Hostless_FM",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_fm),
+       },
+       {
+               .name = "Hostless_SRC_1",
+               .stream_name = "Hostless_SRC_1",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_src1),
+       },
+       {
+               .name = "Hostless_SRC_Bargein",
+               .stream_name = "Hostless_SRC_Bargein",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_src_bargein),
+       },
+       {
+               .name = "Hostless_HW_Gain_AAudio",
+               .stream_name = "Hostless_HW_Gain_AAudio",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio),
+       },
+       {
+               .name = "Hostless_SRC_AAudio",
+               .stream_name = "Hostless_SRC_AAudio",
+               .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
+                           SND_SOC_DPCM_TRIGGER_PRE},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_src_aaudio),
+       },
+       /* Back End DAI links */
+       {
+               .name = "Primary Codec",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .init = mt8186_mt6366_init,
+               SND_SOC_DAILINK_REG(adda),
+       },
+       {
+               .name = "I2S3",
+               .no_pcm = 1,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                          SND_SOC_DAIFMT_IB_IF |
+                          SND_SOC_DAIFMT_CBM_CFM,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .init = mt8186_mt6366_rt1019_rt5682s_hdmi_init,
+               .be_hw_params_fixup = mt8186_it6505_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s3),
+       },
+       {
+               .name = "I2S0",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
+               .ops = &mt8186_rt5682s_i2s_ops,
+               SND_SOC_DAILINK_REG(i2s0),
+       },
+       {
+               .name = "I2S1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
+               .init = mt8186_rt5682s_init,
+               .ops = &mt8186_rt5682s_i2s_ops,
+               SND_SOC_DAILINK_REG(i2s1),
+       },
+       {
+               .name = "I2S2",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               .be_hw_params_fixup = mt8186_i2s_hw_params_fixup,
+               SND_SOC_DAILINK_REG(i2s2),
+       },
+       {
+               .name = "HW Gain 1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_gain1),
+       },
+       {
+               .name = "HW Gain 2",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_gain2),
+       },
+       {
+               .name = "HW_SRC_1",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_src1),
+       },
+       {
+               .name = "HW_SRC_2",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hw_src2),
+       },
+       {
+               .name = "CONNSYS_I2S",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(connsys_i2s),
+       },
+       {
+               .name = "PCM 1",
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                          SND_SOC_DAIFMT_NB_IF,
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(pcm1),
+       },
+       {
+               .name = "TDM IN",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(tdm_in),
+       },
+       /* dummy BE for ul memif to record from dl memif */
+       {
+               .name = "Hostless_UL1",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul1),
+       },
+       {
+               .name = "Hostless_UL2",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul2),
+       },
+       {
+               .name = "Hostless_UL3",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul3),
+       },
+       {
+               .name = "Hostless_UL5",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul5),
+       },
+       {
+               .name = "Hostless_UL6",
+               .no_pcm = 1,
+               .dpcm_capture = 1,
+               .ignore_suspend = 1,
+               SND_SOC_DAILINK_REG(hostless_ul6),
+       },
+};
+
+static const struct snd_soc_dapm_widget
+mt8186_mt6366_rt1019_rt5682s_widgets[] = {
+       SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_OUTPUT("HDMI1"),
+};
+
+static const struct snd_soc_dapm_route
+mt8186_mt6366_rt1019_rt5682s_routes[] = {
+       /* SPK */
+       { "Speakers", NULL, "Speaker" },
+       /* HDMI */
+       { "HDMI1", NULL, "TX" },
+};
+
+static const struct snd_kcontrol_new
+mt8186_mt6366_rt1019_rt5682s_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("HDMI1"),
+};
+
+static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = {
+       .name = "mt8186_mt6366_rt1019_rt5682s",
+       .owner = THIS_MODULE,
+       .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
+       .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
+       .controls = mt8186_mt6366_rt1019_rt5682s_controls,
+       .num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls),
+       .dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets),
+       .dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes),
+       .codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
+       .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
+};
+
+static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct snd_soc_dai_link *dai_link;
+       struct mt8186_mt6366_rt1019_rt5682s_priv *priv;
+       struct device_node *platform_node, *headset_codec, *playback_codec;
+       int ret, i;
+
+       card = (struct snd_soc_card *)device_get_match_data(&pdev->dev);
+       if (!card)
+               return -EINVAL;
+       card->dev = &pdev->dev;
+
+       platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
+       if (!platform_node) {
+               ret = -EINVAL;
+               dev_err_probe(&pdev->dev, ret, "Property 'platform' missing or invalid\n");
+               return ret;
+       }
+
+       playback_codec = of_get_child_by_name(pdev->dev.of_node, "playback-codecs");
+       if (!playback_codec) {
+               ret = -EINVAL;
+               dev_err_probe(&pdev->dev, ret, "Property 'speaker-codecs' missing or invalid\n");
+               goto err_playback_codec;
+       }
+
+       headset_codec = of_get_child_by_name(pdev->dev.of_node, "headset-codec");
+       if (!headset_codec) {
+               ret = -EINVAL;
+               dev_err_probe(&pdev->dev, ret, "Property 'headset-codec' missing or invalid\n");
+               goto err_headset_codec;
+       }
+
+       for_each_card_prelinks(card, i, dai_link) {
+               ret = mt8186_mt6366_card_set_be_link(card, dai_link, playback_codec, "I2S3");
+               if (ret) {
+                       dev_err_probe(&pdev->dev, ret, "%s set speaker_codec fail\n",
+                                     dai_link->name);
+                       goto err_probe;
+               }
+
+               ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S0");
+               if (ret) {
+                       dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+                                     dai_link->name);
+                       goto err_probe;
+               }
+
+               ret = mt8186_mt6366_card_set_be_link(card, dai_link, headset_codec, "I2S1");
+               if (ret) {
+                       dev_err_probe(&pdev->dev, ret, "%s set headset_codec fail\n",
+                                     dai_link->name);
+                       goto err_probe;
+               }
+
+               if (!dai_link->platforms->name)
+                       dai_link->platforms->of_node = platform_node;
+       }
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               ret = -ENOMEM;
+               goto err_probe;
+       }
+
+       snd_soc_card_set_drvdata(card, priv);
+
+       ret = mt8186_afe_gpio_init(&pdev->dev);
+       if (ret) {
+               dev_err_probe(&pdev->dev, ret, "%s init gpio error\n", __func__);
+               goto err_probe;
+       }
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret)
+               dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
+
+err_probe:
+       of_node_put(headset_codec);
+err_headset_codec:
+       of_node_put(playback_codec);
+err_playback_codec:
+       of_node_put(platform_node);
+
+       return ret;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
+       {       .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
+               .data = &mt8186_mt6366_rt1019_rt5682s_soc_card,
+       },
+       {}
+};
+#endif
+
+static struct platform_driver mt8186_mt6366_rt1019_rt5682s_driver = {
+       .driver = {
+               .name = "mt8186_mt6366_rt1019_rt5682s",
+#if IS_ENABLED(CONFIG_OF)
+               .of_match_table = mt8186_mt6366_rt1019_rt5682s_dt_match,
+#endif
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = mt8186_mt6366_rt1019_rt5682s_dev_probe,
+};
+
+module_platform_driver(mt8186_mt6366_rt1019_rt5682s_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("MT8186-MT6366-RT1019-RT5682S ALSA SoC machine driver");
+MODULE_AUTHOR("Jiaxin Yu <jiaxin.yu@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt8186_mt6366_rt1019_rt5682s soc card");
diff --git a/sound/soc/mediatek/mt8186/mt8186-reg.h b/sound/soc/mediatek/mt8186/mt8186-reg.h
new file mode 100644 (file)
index 0000000..53c3eb7
--- /dev/null
@@ -0,0 +1,2913 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mt8186-reg.h  --  Mediatek 8186 audio driver reg definition
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
+ */
+
+#ifndef _MT8186_REG_H_
+#define _MT8186_REG_H_
+
+/* reg bit enum */
+enum {
+       MT8186_MEMIF_PBUF_SIZE_32_BYTES,
+       MT8186_MEMIF_PBUF_SIZE_64_BYTES,
+       MT8186_MEMIF_PBUF_SIZE_128_BYTES,
+       MT8186_MEMIF_PBUF_SIZE_256_BYTES,
+       MT8186_MEMIF_PBUF_SIZE_NUM,
+};
+
+/*****************************************************************************
+ *                  R E G I S T E R       D E F I N I T I O N
+ *****************************************************************************/
+/* AUDIO_TOP_CON0 */
+#define RESERVED_SFT                                   31
+#define RESERVED_MASK_SFT                              BIT(31)
+#define AHB_IDLE_EN_INT_SFT                            30
+#define AHB_IDLE_EN_INT_MASK_SFT                       BIT(30)
+#define AHB_IDLE_EN_EXT_SFT                            29
+#define AHB_IDLE_EN_EXT_MASK_SFT                       BIT(29)
+#define PDN_NLE_SFT                                    28
+#define PDN_NLE_MASK_SFT                               BIT(28)
+#define PDN_TML_SFT                                    27
+#define PDN_TML_MASK_SFT                               BIT(27)
+#define PDN_DAC_PREDIS_SFT                             26
+#define PDN_DAC_PREDIS_MASK_SFT                                BIT(26)
+#define PDN_DAC_SFT                                    25
+#define PDN_DAC_MASK_SFT                               BIT(25)
+#define PDN_ADC_SFT                                    24
+#define PDN_ADC_MASK_SFT                               BIT(24)
+#define PDN_TDM_CK_SFT                                 20
+#define PDN_TDM_CK_MASK_SFT                            BIT(20)
+#define PDN_APLL_TUNER_SFT                             19
+#define PDN_APLL_TUNER_MASK_SFT                                BIT(19)
+#define PDN_APLL2_TUNER_SFT                            18
+#define PDN_APLL2_TUNER_MASK_SFT                       BIT(18)
+#define APB3_SEL_SFT                                   14
+#define APB3_SEL_MASK_SFT                              BIT(14)
+#define APB_R2T_SFT                                    13
+#define APB_R2T_MASK_SFT                               BIT(13)
+#define APB_W2T_SFT                                    12
+#define APB_W2T_MASK_SFT                               BIT(12)
+#define PDN_24M_SFT                                    9
+#define PDN_24M_MASK_SFT                               BIT(9)
+#define PDN_22M_SFT                                    8
+#define PDN_22M_MASK_SFT                               BIT(8)
+#define PDN_AFE_SFT                                    2
+#define PDN_AFE_MASK_SFT                               BIT(2)
+
+/* AUDIO_TOP_CON1 */
+#define PDN_3RD_DAC_HIRES_SFT                          31
+#define PDN_3RD_DAC_HIRES_MASK_SFT                     BIT(31)
+#define PDN_3RD_DAC_TML_SFT                            30
+#define PDN_3RD_DAC_TML_MASK_SFT                       BIT(30)
+#define PDN_3RD_DAC_PREDIS_SFT                         29
+#define PDN_3RD_DAC_PREDIS_MASK_SFT                    BIT(29)
+#define PDN_3RD_DAC_SFT                                        28
+#define PDN_3RD_DAC_MASK_SFT                           BIT(28)
+#define I2S_SOFT_RST5_SFT                              22
+#define I2S_SOFT_RST5_MASK_SFT                         BIT(22)
+#define PDN_ADDA6_ADC_HIRES_SFT                                21
+#define PDN_ADDA6_ADC_HIRES_MASK_SFT                   BIT(21)
+#define PDN_ADDA6_ADC_SFT                              20
+#define PDN_ADDA6_ADC_MASK_SFT                         BIT(20)
+#define PDN_ADC_HIRES_TML_SFT                          17
+#define PDN_ADC_HIRES_TML_MASK_SFT                     BIT(17)
+#define PDN_ADC_HIRES_SFT                              16
+#define PDN_ADC_HIRES_MASK_SFT                         BIT(16)
+#define PDN_DAC_HIRES_SFT                              15
+#define PDN_DAC_HIRES_MASK_SFT                         BIT(15)
+#define PDN_GENERAL2_ASRC_SFT                          14
+#define PDN_GENERAL2_ASRC_MASK_SFT                     BIT(14)
+#define PDN_GENERAL1_ASRC_SFT                          13
+#define PDN_GENERAL1_ASRC_MASK_SFT                     BIT(13)
+#define PDN_CONNSYS_I2S_ASRC_SFT                       12
+#define PDN_CONNSYS_I2S_ASRC_MASK_SFT                  BIT(12)
+#define I2S4_BCLK_SW_CG_SFT                            7
+#define I2S4_BCLK_SW_CG_MASK_SFT                       BIT(7)
+#define I2S3_BCLK_SW_CG_SFT                            6
+#define I2S3_BCLK_SW_CG_MASK_SFT                       BIT(6)
+#define I2S2_BCLK_SW_CG_SFT                            5
+#define I2S2_BCLK_SW_CG_MASK_SFT                       BIT(5)
+#define I2S1_BCLK_SW_CG_SFT                            4
+#define I2S1_BCLK_SW_CG_MASK_SFT                       BIT(4)
+#define I2S_SOFT_RST2_SFT                              2
+#define I2S_SOFT_RST2_MASK_SFT                         BIT(2)
+#define I2S_SOFT_RST_SFT                               1
+#define I2S_SOFT_RST_MASK_SFT                          BIT(1)
+
+/* AUDIO_TOP_CON3 */
+#define BUSY_SFT                                       31
+#define BUSY_MASK_SFT                                  BIT(31)
+#define OS_DISABLE_SFT                                 30
+#define OS_DISABLE_MASK_SFT                            BIT(30)
+#define CG_DISABLE_SFT                                 29
+#define CG_DISABLE_MASK_SFT                            BIT(29)
+#define CLEAR_FLAG_SFT                                 0
+#define CLEAR_FLAG_MASK_SFT                            BIT(0)
+
+/* AFE_DAC_CON0 */
+#define VUL12_ON_SFT                                   31
+#define VUL12_ON_MASK_SFT                              BIT(31)
+#define MOD_DAI_ON_SFT                                 30
+#define MOD_DAI_ON_MASK_SFT                            BIT(30)
+#define DAI_ON_SFT                                     29
+#define DAI_ON_MASK_SFT                                        BIT(29)
+#define DAI2_ON_SFT                                    28
+#define DAI2_ON_MASK_SFT                               BIT(28)
+#define VUL6_ON_SFT                                    23
+#define VUL6_ON_MASK_SFT                               BIT(23)
+#define VUL5_ON_SFT                                    22
+#define VUL5_ON_MASK_SFT                               BIT(22)
+#define VUL4_ON_SFT                                    21
+#define VUL4_ON_MASK_SFT                               BIT(21)
+#define VUL3_ON_SFT                                    20
+#define VUL3_ON_MASK_SFT                               BIT(20)
+#define VUL2_ON_SFT                                    19
+#define VUL2_ON_MASK_SFT                               BIT(19)
+#define VUL_ON_SFT                                     18
+#define VUL_ON_MASK_SFT                                        BIT(18)
+#define AWB2_ON_SFT                                    17
+#define AWB2_ON_MASK_SFT                               BIT(17)
+#define AWB_ON_SFT                                     16
+#define AWB_ON_MASK_SFT                                        BIT(16)
+#define DL12_ON_SFT                                    15
+#define DL12_ON_MASK_SFT                               BIT(15)
+#define DL8_ON_SFT                                     11
+#define DL8_ON_MASK_SFT                                        BIT(11)
+#define DL7_ON_SFT                                     10
+#define DL7_ON_MASK_SFT                                        BIT(10)
+#define DL6_ON_SFT                                     9
+#define DL6_ON_MASK_SFT                                        BIT(9)
+#define DL5_ON_SFT                                     8
+#define DL5_ON_MASK_SFT                                        BIT(8)
+#define DL4_ON_SFT                                     7
+#define DL4_ON_MASK_SFT                                        BIT(7)
+#define DL3_ON_SFT                                     6
+#define DL3_ON_MASK_SFT                                        BIT(6)
+#define DL2_ON_SFT                                     5
+#define DL2_ON_MASK_SFT                                        BIT(5)
+#define DL1_ON_SFT                                     4
+#define DL1_ON_MASK_SFT                                        BIT(4)
+#define AUDIO_AFE_ON_SFT                               0
+#define AUDIO_AFE_ON_MASK_SFT                          BIT(0)
+
+/* AFE_DAC_MON */
+#define AFE_ON_RETM_SFT                                        0
+#define AFE_ON_RETM_MASK_SFT                           BIT(0)
+
+/* AFE_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT                           30
+#define BCK_NEG_EG_LATCH_MASK_SFT                      BIT(30)
+#define BCK_INV_SFT                                    29
+#define BCK_INV_MASK_SFT                               BIT(29)
+#define I2SIN_PAD_SEL_SFT                              28
+#define I2SIN_PAD_SEL_MASK_SFT                         BIT(28)
+#define I2S_LOOPBACK_SFT                               20
+#define I2S_LOOPBACK_MASK_SFT                          BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         BIT(17)
+#define I2S1_HD_EN_SFT                                 12
+#define I2S1_HD_EN_MASK_SFT                            BIT(12)
+#define I2S_OUT_MODE_SFT                               8
+#define I2S_OUT_MODE_MASK_SFT                          GENMASK(11, 8)
+#define INV_PAD_CTRL_SFT                               7
+#define INV_PAD_CTRL_MASK_SFT                          BIT(7)
+#define I2S_BYPSRC_SFT                                 6
+#define I2S_BYPSRC_MASK_SFT                            BIT(6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK_SFT                              BIT(5)
+#define I2S_FMT_SFT                                    3
+#define I2S_FMT_MASK_SFT                               BIT(3)
+#define I2S_SRC_SFT                                    2
+#define I2S_SRC_MASK_SFT                               BIT(2)
+#define I2S_WLEN_SFT                                   1
+#define I2S_WLEN_MASK_SFT                              BIT(1)
+#define I2S_EN_SFT                                     0
+#define I2S_EN_MASK_SFT                                        BIT(0)
+
+/* AFE_I2S_CON1 */
+#define I2S2_LR_SWAP_SFT                               31
+#define I2S2_LR_SWAP_MASK_SFT                          BIT(31)
+#define I2S2_SEL_O19_O20_SFT                           18
+#define I2S2_SEL_O19_O20_MASK_SFT                      BIT(18)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         BIT(17)
+#define I2S2_SEL_O03_O04_SFT                           16
+#define I2S2_SEL_O03_O04_MASK_SFT                      BIT(16)
+#define I2S2_HD_EN_SFT                                 12
+#define I2S2_HD_EN_MASK_SFT                            BIT(12)
+#define I2S2_OUT_MODE_SFT                              8
+#define I2S2_OUT_MODE_MASK_SFT                         GENMASK(11, 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK_SFT                              BIT(5)
+#define I2S2_FMT_SFT                                   3
+#define I2S2_FMT_MASK_SFT                              BIT(3)
+#define I2S2_WLEN_SFT                                  1
+#define I2S2_WLEN_MASK_SFT                             BIT(1)
+#define I2S2_EN_SFT                                    0
+#define I2S2_EN_MASK_SFT                               BIT(0)
+
+/* AFE_I2S_CON2 */
+#define I2S3_LR_SWAP_SFT                               31
+#define I2S3_LR_SWAP_MASK_SFT                          BIT(31)
+#define I2S3_UPDATE_WORD_SFT                           24
+#define I2S3_UPDATE_WORD_MASK_SFT                      GENMASK(28, 24)
+#define I2S3_BCK_INV_SFT                               23
+#define I2S3_BCK_INV_MASK_SFT                          BIT(23)
+#define I2S3_FPGA_BIT_TEST_SFT                         22
+#define I2S3_FPGA_BIT_TEST_MASK_SFT                    BIT(22)
+#define I2S3_FPGA_BIT_SFT                              21
+#define I2S3_FPGA_BIT_MASK_SFT                         BIT(21)
+#define I2S3_LOOPBACK_SFT                              20
+#define I2S3_LOOPBACK_MASK_SFT                         BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         BIT(17)
+#define I2S3_HD_EN_SFT                                 12
+#define I2S3_HD_EN_MASK_SFT                            BIT(12)
+#define I2S3_OUT_MODE_SFT                              8
+#define I2S3_OUT_MODE_MASK_SFT                         GENMASK(11, 8)
+#define I2S3_FMT_SFT                                   3
+#define I2S3_FMT_MASK_SFT                              BIT(3)
+#define I2S3_WLEN_SFT                                  1
+#define I2S3_WLEN_MASK_SFT                             BIT(1)
+#define I2S3_EN_SFT                                    0
+#define I2S3_EN_MASK_SFT                               BIT(0)
+
+/* AFE_I2S_CON3 */
+#define I2S4_LR_SWAP_SFT                               31
+#define I2S4_LR_SWAP_MASK_SFT                          BIT(31)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         BIT(17)
+#define I2S4_HD_EN_SFT                                 12
+#define I2S4_HD_EN_MASK_SFT                            BIT(12)
+#define I2S4_OUT_MODE_SFT                              8
+#define I2S4_OUT_MODE_MASK_SFT                         GENMASK(11, 8)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK_SFT                              BIT(5)
+#define I2S4_FMT_SFT                                   3
+#define I2S4_FMT_MASK_SFT                              BIT(3)
+#define I2S4_WLEN_SFT                                  1
+#define I2S4_WLEN_MASK_SFT                             BIT(1)
+#define I2S4_EN_SFT                                    0
+#define I2S4_EN_MASK_SFT                               BIT(0)
+
+/* AFE_I2S_CON4 */
+#define I2S_LOOPBACK_SFT                               20
+#define I2S_LOOPBACK_MASK                              0x1
+#define I2S_LOOPBACK_MASK_SFT                          BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK             0x1
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         BIT(17)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK                                  0x1
+#define INV_LRCK_MASK_SFT                              BIT(5)
+
+/* AFE_CONNSYS_I2S_CON */
+#define BCK_NEG_EG_LATCH_SFT                           30
+#define BCK_NEG_EG_LATCH_MASK_SFT                      BIT(30)
+#define BCK_INV_SFT                                    29
+#define BCK_INV_MASK_SFT                               BIT(29)
+#define I2SIN_PAD_SEL_SFT                              28
+#define I2SIN_PAD_SEL_MASK_SFT                         BIT(28)
+#define I2S_LOOPBACK_SFT                               20
+#define I2S_LOOPBACK_MASK_SFT                          BIT(20)
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT              17
+#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT         BIT(17)
+#define I2S_MODE_SFT                                   8
+#define I2S_MODE_MASK_SFT                              GENMASK(11, 8)
+#define INV_PAD_CTRL_SFT                               7
+#define INV_PAD_CTRL_MASK_SFT                          BIT(7)
+#define I2S_BYPSRC_SFT                                 6
+#define I2S_BYPSRC_MASK_SFT                            BIT(6)
+#define INV_LRCK_SFT                                   5
+#define INV_LRCK_MASK_SFT                              BIT(5)
+#define I2S_FMT_SFT                                    3
+#define I2S_FMT_MASK_SFT                               BIT(3)
+#define I2S_SRC_SFT                                    2
+#define I2S_SRC_MASK_SFT                               BIT(2)
+#define I2S_WLEN_SFT                                   1
+#define I2S_WLEN_MASK_SFT                              BIT(1)
+#define I2S_EN_SFT                                     0
+#define I2S_EN_MASK_SFT                                        BIT(0)
+
+/* AFE_ASRC_2CH_CON2 */
+#define CHSET_O16BIT_SFT                               19
+#define CHSET_O16BIT_MASK_SFT                          BIT(19)
+#define CHSET_CLR_IIR_HISTORY_SFT                      17
+#define CHSET_CLR_IIR_HISTORY_MASK_SFT                 BIT(17)
+#define CHSET_IS_MONO_SFT                              16
+#define CHSET_IS_MONO_MASK_SFT                         BIT(16)
+#define CHSET_IIR_EN_SFT                               11
+#define CHSET_IIR_EN_MASK_SFT                          BIT(11)
+#define CHSET_IIR_STAGE_SFT                            8
+#define CHSET_IIR_STAGE_MASK_SFT                       GENMASK(10, 8)
+#define CHSET_STR_CLR_SFT                              5
+#define CHSET_STR_CLR_MASK_SFT                         BIT(5)
+#define CHSET_ON_SFT                                   2
+#define CHSET_ON_MASK_SFT                              BIT(2)
+#define COEFF_SRAM_CTRL_SFT                            1
+#define COEFF_SRAM_CTRL_MASK_SFT                       BIT(1)
+#define ASM_ON_SFT                                     0
+#define ASM_ON_MASK_SFT                                        BIT(0)
+
+/* AFE_GAIN1_CON0 */
+#define GAIN1_SAMPLE_PER_STEP_SFT                      8
+#define GAIN1_SAMPLE_PER_STEP_MASK_SFT                 GENMASK(15, 8)
+#define GAIN1_MODE_SFT                                 4
+#define GAIN1_MODE_MASK_SFT                            GENMASK(7, 4)
+#define GAIN1_ON_SFT                                   0
+#define GAIN1_ON_MASK_SFT                              BIT(0)
+
+/* AFE_GAIN1_CON1 */
+#define GAIN1_TARGET_SFT                               0
+#define GAIN1_TARGET_MASK                              0xfffffff
+#define GAIN1_TARGET_MASK_SFT                          GENMASK(27, 0)
+
+/* AFE_GAIN2_CON0 */
+#define GAIN2_SAMPLE_PER_STEP_SFT                      8
+#define GAIN2_SAMPLE_PER_STEP_MASK_SFT                 GENMASK(15, 8)
+#define GAIN2_MODE_SFT                                 4
+#define GAIN2_MODE_MASK_SFT                            GENMASK(7, 4)
+#define GAIN2_ON_SFT                                   0
+#define GAIN2_ON_MASK_SFT                              BIT(0)
+
+/* AFE_GAIN2_CON1 */
+#define GAIN2_TARGET_SFT                               0
+#define GAIN2_TARGET_MASK                              0xfffffff
+#define GAIN2_TARGET_MASK_SFT                          GENMASK(27, 0)
+
+/* AFE_GAIN1_CUR */
+#define AFE_GAIN1_CUR_SFT                              0
+#define AFE_GAIN1_CUR_MASK_SFT                         GENMASK(27, 0)
+
+/* AFE_GAIN2_CUR */
+#define AFE_GAIN2_CUR_SFT                              0
+#define AFE_GAIN2_CUR_MASK_SFT                         GENMASK(27, 0)
+
+/* PCM_INTF_CON1 */
+#define PCM_FIX_VALUE_SEL_SFT                          31
+#define PCM_FIX_VALUE_SEL_MASK_SFT                     BIT(31)
+#define PCM_BUFFER_LOOPBACK_SFT                                30
+#define PCM_BUFFER_LOOPBACK_MASK_SFT                   BIT(30)
+#define PCM_PARALLEL_LOOPBACK_SFT                      29
+#define PCM_PARALLEL_LOOPBACK_MASK_SFT                 BIT(29)
+#define PCM_SERIAL_LOOPBACK_SFT                                28
+#define PCM_SERIAL_LOOPBACK_MASK_SFT                   BIT(28)
+#define PCM_DAI_PCM_LOOPBACK_SFT                       27
+#define PCM_DAI_PCM_LOOPBACK_MASK_SFT                  BIT(27)
+#define PCM_I2S_PCM_LOOPBACK_SFT                       26
+#define PCM_I2S_PCM_LOOPBACK_MASK_SFT                  BIT(26)
+#define PCM_SYNC_DELSEL_SFT                            25
+#define PCM_SYNC_DELSEL_MASK_SFT                       BIT(25)
+#define PCM_TX_LR_SWAP_SFT                             24
+#define PCM_TX_LR_SWAP_MASK_SFT                                BIT(24)
+#define PCM_SYNC_OUT_INV_SFT                           23
+#define PCM_SYNC_OUT_INV_MASK_SFT                      BIT(23)
+#define PCM_BCLK_OUT_INV_SFT                           22
+#define PCM_BCLK_OUT_INV_MASK_SFT                      BIT(22)
+#define PCM_SYNC_IN_INV_SFT                            21
+#define PCM_SYNC_IN_INV_MASK_SFT                       BIT(21)
+#define PCM_BCLK_IN_INV_SFT                            20
+#define PCM_BCLK_IN_INV_MASK_SFT                       BIT(20)
+#define PCM_TX_LCH_RPT_SFT                             19
+#define PCM_TX_LCH_RPT_MASK_SFT                                BIT(19)
+#define PCM_VBT_16K_MODE_SFT                           18
+#define PCM_VBT_16K_MODE_MASK_SFT                      BIT(18)
+#define PCM_EXT_MODEM_SFT                              17
+#define PCM_EXT_MODEM_MASK_SFT                         BIT(17)
+#define PCM_24BIT_SFT                                  16
+#define PCM_24BIT_MASK_SFT                             BIT(16)
+#define PCM_WLEN_SFT                                   14
+#define PCM_WLEN_MASK_SFT                              GENMASK(15, 14)
+#define PCM_SYNC_LENGTH_SFT                            9
+#define PCM_SYNC_LENGTH_MASK_SFT                       GENMASK(13, 9)
+#define PCM_SYNC_TYPE_SFT                              8
+#define PCM_SYNC_TYPE_MASK_SFT                         BIT(8)
+#define PCM_BT_MODE_SFT                                        7
+#define PCM_BT_MODE_MASK_SFT                           BIT(7)
+#define PCM_BYP_ASRC_SFT                               6
+#define PCM_BYP_ASRC_MASK_SFT                          BIT(6)
+#define PCM_SLAVE_SFT                                  5
+#define PCM_SLAVE_MASK_SFT                             BIT(5)
+#define PCM_MODE_SFT                                   3
+#define PCM_MODE_MASK_SFT                              GENMASK(4, 3)
+#define PCM_FMT_SFT                                    1
+#define PCM_FMT_MASK_SFT                               GENMASK(2, 1)
+#define PCM_EN_SFT                                     0
+#define PCM_EN_MASK_SFT                                        BIT(0)
+
+/* PCM_INTF_CON2 */
+#define PCM1_TX_FIFO_OV_SFT                            31
+#define PCM1_TX_FIFO_OV_MASK_SFT                       BIT(31)
+#define PCM1_RX_FIFO_OV_SFT                            30
+#define PCM1_RX_FIFO_OV_MASK_SFT                       BIT(30)
+#define PCM2_TX_FIFO_OV_SFT                            29
+#define PCM2_TX_FIFO_OV_MASK_SFT                       BIT(29)
+#define PCM2_RX_FIFO_OV_SFT                            28
+#define PCM2_RX_FIFO_OV_MASK_SFT                       BIT(28)
+#define PCM1_SYNC_GLITCH_SFT                           27
+#define PCM1_SYNC_GLITCH_MASK_SFT                      BIT(27)
+#define PCM2_SYNC_GLITCH_SFT                           26
+#define PCM2_SYNC_GLITCH_MASK_SFT                      BIT(26)
+#define TX3_RCH_DBG_MODE_SFT                           17
+#define TX3_RCH_DBG_MODE_MASK_SFT                      BIT(17)
+#define PCM1_PCM2_LOOPBACK_SFT                         16
+#define PCM1_PCM2_LOOPBACK_MASK_SFT                    BIT(16)
+#define DAI_PCM_LOOPBACK_CH_SFT                                14
+#define DAI_PCM_LOOPBACK_CH_MASK_SFT                   GENMASK(15, 14)
+#define I2S_PCM_LOOPBACK_CH_SFT                                12
+#define I2S_PCM_LOOPBACK_CH_MASK_SFT                   GENMASK(13, 12)
+#define TX_FIX_VALUE_SFT                               0
+#define TX_FIX_VALUE_MASK_SFT                          GENMASK(7, 0)
+
+/* PCM2_INTF_CON */
+#define PCM2_TX_FIX_VALUE_SFT                          24
+#define PCM2_TX_FIX_VALUE_MASK_SFT                     GENMASK(31, 24)
+#define PCM2_FIX_VALUE_SEL_SFT                         23
+#define PCM2_FIX_VALUE_SEL_MASK_SFT                    BIT(23)
+#define PCM2_BUFFER_LOOPBACK_SFT                       22
+#define PCM2_BUFFER_LOOPBACK_MASK_SFT                  BIT(22)
+#define PCM2_PARALLEL_LOOPBACK_SFT                     21
+#define PCM2_PARALLEL_LOOPBACK_MASK_SFT                        BIT(21)
+#define PCM2_SERIAL_LOOPBACK_SFT                       20
+#define PCM2_SERIAL_LOOPBACK_MASK_SFT                  BIT(20)
+#define PCM2_DAI_PCM_LOOPBACK_SFT                      19
+#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT                 BIT(19)
+#define PCM2_I2S_PCM_LOOPBACK_SFT                      18
+#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT                 BIT(18)
+#define PCM2_SYNC_DELSEL_SFT                           17
+#define PCM2_SYNC_DELSEL_MASK_SFT                      BIT(17)
+#define PCM2_TX_LR_SWAP_SFT                            16
+#define PCM2_TX_LR_SWAP_MASK_SFT                       BIT(16)
+#define PCM2_SYNC_IN_INV_SFT                           15
+#define PCM2_SYNC_IN_INV_MASK_SFT                      BIT(15)
+#define PCM2_BCLK_IN_INV_SFT                           14
+#define PCM2_BCLK_IN_INV_MASK_SFT                      BIT(14)
+#define PCM2_TX_LCH_RPT_SFT                            13
+#define PCM2_TX_LCH_RPT_MASK_SFT                       BIT(13)
+#define PCM2_VBT_16K_MODE_SFT                          12
+#define PCM2_VBT_16K_MODE_MASK_SFT                     BIT(12)
+#define PCM2_LOOPBACK_CH_SEL_SFT                       10
+#define PCM2_LOOPBACK_CH_SEL_MASK_SFT                  GENMASK(11, 10)
+#define PCM2_TX2_BT_MODE_SFT                           8
+#define PCM2_TX2_BT_MODE_MASK_SFT                      BIT(8)
+#define PCM2_BT_MODE_SFT                               7
+#define PCM2_BT_MODE_MASK_SFT                          BIT(7)
+#define PCM2_AFIFO_SFT                                 6
+#define PCM2_AFIFO_MASK_SFT                            BIT(6)
+#define PCM2_WLEN_SFT                                  5
+#define PCM2_WLEN_MASK_SFT                             BIT(5)
+#define PCM2_MODE_SFT                                  3
+#define PCM2_MODE_MASK_SFT                             GENMASK(4, 3)
+#define PCM2_FMT_SFT                                   1
+#define PCM2_FMT_MASK_SFT                              GENMASK(2, 1)
+#define PCM2_EN_SFT                                    0
+#define PCM2_EN_MASK_SFT                               BIT(0)
+
+// AFE_CM1_CON
+#define CHANNEL_MERGE0_DEBUG_MODE_SFT                  (31)
+#define CHANNEL_MERGE0_DEBUG_MODE_MASK_SFT             BIT(31)
+#define VUL3_BYPASS_CM_SFT                             (30)
+#define VUL3_BYPASS_CM_MASK                            (0x1)
+#define VUL3_BYPASS_CM_MASK_SFT                                BIT(30)
+#define CM1_DEBUG_MODE_SEL_SFT                         (29)
+#define CM1_DEBUG_MODE_SEL_MASK_SFT                    BIT(29)
+#define CHANNEL_MERGE0_UPDATE_CNT_SFT                  (16)
+#define CHANNEL_MERGE0_UPDATE_CNT_MASK_SFT             GENMASK(28, 16)
+#define CM1_FS_SELECT_SFT                              (8)
+#define CM1_FS_SELECT_MASK_SFT                         GENMASK(12, 8)
+#define CHANNEL_MERGE0_CHNUM_SFT                       (3)
+#define CHANNEL_MERGE0_CHNUM_MASK_SFT                  GENMASK(7, 3)
+#define CHANNEL_MERGE0_BYTE_SWAP_SFT                   (1)
+#define CHANNEL_MERGE0_BYTE_SWAP_MASK_SFT              BIT(1)
+#define CHANNEL_MERGE0_EN_SFT                          (0)
+#define CHANNEL_MERGE0_EN_MASK_SFT                     BIT(0)
+
+/* AFE_ADDA_MTKAIF_CFG0 */
+#define MTKAIF_RXIF_CLKINV_ADC_SFT                     31
+#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT                        BIT(31)
+#define MTKAIF_RXIF_BYPASS_SRC_SFT                     17
+#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT                        BIT(17)
+#define MTKAIF_RXIF_PROTOCOL2_SFT                      16
+#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT                 BIT(16)
+#define MTKAIF_TXIF_BYPASS_SRC_SFT                     5
+#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT                        BIT(5)
+#define MTKAIF_TXIF_PROTOCOL2_SFT                      4
+#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT                 BIT(4)
+#define MTKAIF_TXIF_8TO5_SFT                           2
+#define MTKAIF_TXIF_8TO5_MASK_SFT                      BIT(2)
+#define MTKAIF_RXIF_8TO5_SFT                           1
+#define MTKAIF_RXIF_8TO5_MASK_SFT                      BIT(1)
+#define MTKAIF_IF_LOOPBACK1_SFT                                0
+#define MTKAIF_IF_LOOPBACK1_MASK_SFT                   BIT(0)
+
+/* AFE_ADDA_MTKAIF_RX_CFG2 */
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT            16
+#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT       BIT(16)
+#define MTKAIF_RXIF_DELAY_CYCLE_SFT                    12
+#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT               GENMASK(15, 12)
+#define MTKAIF_RXIF_DELAY_DATA_SFT                     8
+#define MTKAIF_RXIF_DELAY_DATA_MASK                    0x1
+#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT                        BIT(8)
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT             4
+#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT                GENMASK(6, 4)
+
+/* AFE_ADDA_DL_SRC2_CON0 */
+#define DL_2_INPUT_MODE_CTL_SFT                                28
+#define DL_2_INPUT_MODE_CTL_MASK_SFT                   GENMASK(31, 28)
+#define DL_2_CH1_SATURATION_EN_CTL_SFT                 27
+#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT            BIT(27)
+#define DL_2_CH2_SATURATION_EN_CTL_SFT                 26
+#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT            BIT(26)
+#define DL_2_OUTPUT_SEL_CTL_SFT                                24
+#define DL_2_OUTPUT_SEL_CTL_MASK_SFT                   GENMASK(25, 24)
+#define DL_2_FADEIN_0START_EN_SFT                      16
+#define DL_2_FADEIN_0START_EN_MASK_SFT                 GENMASK(17, 16)
+#define DL_DISABLE_HW_CG_CTL_SFT                       15
+#define DL_DISABLE_HW_CG_CTL_MASK_SFT                  BIT(15)
+#define C_DATA_EN_SEL_CTL_PRE_SFT                      14
+#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT                 BIT(14)
+#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT                  13
+#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT             BIT(13)
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT                  12
+#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT             BIT(12)
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT                  11
+#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT             BIT(11)
+#define DL2_ARAMPSP_CTL_PRE_SFT                                9
+#define DL2_ARAMPSP_CTL_PRE_MASK_SFT                   GENMASK(10, 9)
+#define DL_2_IIRMODE_CTL_PRE_SFT                       6
+#define DL_2_IIRMODE_CTL_PRE_MASK_SFT                  GENMASK(8, 6)
+#define DL_2_VOICE_MODE_CTL_PRE_SFT                    5
+#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT               BIT(5)
+#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT                   4
+#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT              BIT(4)
+#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT                   3
+#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT              BIT(3)
+#define DL_2_IIR_ON_CTL_PRE_SFT                                2
+#define DL_2_IIR_ON_CTL_PRE_MASK_SFT                   BIT(2)
+#define DL_2_GAIN_ON_CTL_PRE_SFT                       1
+#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT                  BIT(1)
+#define DL_2_SRC_ON_CTL_PRE_SFT                                0
+#define DL_2_SRC_ON_CTL_PRE_MASK_SFT                   BIT(0)
+
+/* AFE_ADDA_DL_SRC2_CON1 */
+#define DL_2_GAIN_CTL_PRE_SFT                          16
+#define DL_2_GAIN_CTL_PRE_MASK                         0xffff
+#define DL_2_GAIN_CTL_PRE_MASK_SFT                     GENMASK(31, 16)
+#define DL_2_GAIN_MODE_CTL_SFT                         0
+#define DL_2_GAIN_MODE_CTL_MASK_SFT                    BIT(0)
+
+/* AFE_ADDA_UL_SRC_CON0 */
+#define ULCF_CFG_EN_CTL_SFT                            31
+#define ULCF_CFG_EN_CTL_MASK_SFT                       BIT(31)
+#define UL_DMIC_PHASE_SEL_CH1_SFT                      27
+#define UL_DMIC_PHASE_SEL_CH1_MASK_SFT                 GENMASK(29, 27)
+#define UL_DMIC_PHASE_SEL_CH2_SFT                      24
+#define UL_DMIC_PHASE_SEL_CH2_MASK_SFT                 GENMASK(26, 24)
+#define UL_MODE_3P25M_CH2_CTL_SFT                      22
+#define UL_MODE_3P25M_CH2_CTL_MASK_SFT                 BIT(22)
+#define UL_MODE_3P25M_CH1_CTL_SFT                      21
+#define UL_MODE_3P25M_CH1_CTL_MASK_SFT                 BIT(21)
+#define UL_VOICE_MODE_CH1_CH2_CTL_SFT                  17
+#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT             GENMASK(19, 17)
+#define UL_AP_DMIC_ON_SFT                              16
+#define UL_AP_DMIC_ON_MASK_SFT                         BIT(16)
+#define DMIC_LOW_POWER_CTL_SFT                         14
+#define DMIC_LOW_POWER_CTL_MASK_SFT                    GENMASK(15, 14)
+#define UL_DISABLE_HW_CG_CTL_SFT                       12
+#define UL_DISABLE_HW_CG_CTL_MASK_SFT                  BIT(12)
+#define UL_IIR_ON_TMP_CTL_SFT                          10
+#define UL_IIR_ON_TMP_CTL_MASK_SFT                     BIT(10)
+#define UL_IIRMODE_CTL_SFT                             7
+#define UL_IIRMODE_CTL_MASK_SFT                                GENMASK(9, 7)
+#define DIGMIC_4P33M_SEL_SFT                           6
+#define DIGMIC_4P33M_SEL_MASK_SFT                      BIT(6)
+#define DIGMIC_3P25M_1P625M_SEL_SFT                    5
+#define DIGMIC_3P25M_1P625M_SEL_MASK_SFT               BIT(5)
+#define UL_LOOP_BACK_MODE_SFT                          2
+#define UL_LOOP_BACK_MODE_MASK_SFT                     BIT(2)
+#define UL_SDM_3_LEVEL_SFT                             1
+#define UL_SDM_3_LEVEL_MASK_SFT                                BIT(1)
+#define UL_SRC_ON_CTL_SFT                              0
+#define UL_SRC_ON_CTL_MASK_SFT                         BIT(0)
+
+/* AFE_ADDA_UL_SRC_CON1 */
+#define C_DAC_EN_CTL_SFT                               27
+#define C_DAC_EN_CTL_MASK_SFT                          BIT(27)
+#define C_MUTE_SW_CTL_SFT                              26
+#define C_MUTE_SW_CTL_MASK_SFT                         BIT(26)
+#define ASDM_SRC_SEL_CTL_SFT                           25
+#define ASDM_SRC_SEL_CTL_MASK_SFT                      BIT(25)
+#define C_AMP_DIV_CH2_CTL_SFT                          21
+#define C_AMP_DIV_CH2_CTL_MASK_SFT                     GENMASK(23, 21)
+#define C_FREQ_DIV_CH2_CTL_SFT                         16
+#define C_FREQ_DIV_CH2_CTL_MASK_SFT                    GENMASK(20, 16)
+#define C_SINE_MODE_CH2_CTL_SFT                                12
+#define C_SINE_MODE_CH2_CTL_MASK_SFT                   GENMASK(15, 12)
+#define C_AMP_DIV_CH1_CTL_SFT                          9
+#define C_AMP_DIV_CH1_CTL_MASK_SFT                     GENMASK(11, 9)
+#define C_FREQ_DIV_CH1_CTL_SFT                         4
+#define C_FREQ_DIV_CH1_CTL_MASK_SFT                    GENMASK(8, 4)
+#define C_SINE_MODE_CH1_CTL_SFT                                0
+#define C_SINE_MODE_CH1_CTL_MASK_SFT                   GENMASK(3, 0)
+
+/* AFE_ADDA_TOP_CON0 */
+#define C_LOOP_BACK_MODE_CTL_SFT                       12
+#define C_LOOP_BACK_MODE_CTL_MASK_SFT                  GENMASK(15, 12)
+#define ADDA_UL_GAIN_MODE_SFT                          8
+#define ADDA_UL_GAIN_MODE_MASK_SFT                     GENMASK(9, 8)
+#define C_EXT_ADC_CTL_SFT                              0
+#define C_EXT_ADC_CTL_MASK_SFT                         BIT(0)
+
+/* AFE_ADDA_UL_DL_CON0 */
+#define AFE_ADDA_UL_LR_SWAP_SFT                                31
+#define AFE_ADDA_UL_LR_SWAP_MASK_SFT                   BIT(31)
+#define AFE_ADDA_CKDIV_RST_SFT                         30
+#define AFE_ADDA_CKDIV_RST_MASK_SFT                    BIT(30)
+#define AFE_ADDA_FIFO_AUTO_RST_SFT                     29
+#define AFE_ADDA_FIFO_AUTO_RST_MASK_SFT                        BIT(29)
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_SFT             21
+#define AFE_ADDA_UL_FIFO_DIGMIC_TESTIN_MASK_SFT                GENMASK(22, 21)
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT       20
+#define AFE_ADDA_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT  BIT(20)
+#define AFE_ADDA6_UL_LR_SWAP_SFT                       15
+#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT                  BIT(15)
+#define AFE_ADDA6_CKDIV_RST_SFT                                14
+#define AFE_ADDA6_CKDIV_RST_MASK_SFT                   BIT(14)
+#define AFE_ADDA6_FIFO_AUTO_RST_SFT                    13
+#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT               BIT(13)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_SFT            5
+#define AFE_ADDA6_UL_FIFO_DIGMIC_TESTIN_MASK_SFT       GENMASK(6, 5)
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_SFT      4
+#define AFE_ADDA6_UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT BIT(4)
+#define ADDA_AFE_ON_SFT                                        0
+#define ADDA_AFE_ON_MASK_SFT                           BIT(0)
+
+/* AFE_SIDETONE_CON0 */
+#define R_RDY_SFT                                      30
+#define R_RDY_MASK_SFT                                 BIT(30)
+#define W_RDY_SFT                                      29
+#define W_RDY_MASK_SFT                                 BIT(29)
+#define R_W_EN_SFT                                     25
+#define R_W_EN_MASK_SFT                                        BIT(25)
+#define R_W_SEL_SFT                                    24
+#define R_W_SEL_MASK_SFT                               BIT(24)
+#define SEL_CH2_SFT                                    23
+#define SEL_CH2_MASK_SFT                               BIT(23)
+#define SIDE_TONE_COEFFICIENT_ADDR_SFT                 16
+#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT            GENMASK(20, 16)
+#define SIDE_TONE_COEFFICIENT_SFT                      0
+#define SIDE_TONE_COEFFICIENT_MASK_SFT                 GENMASK(15, 0)
+
+/* AFE_SIDETONE_COEFF */
+#define SIDE_TONE_COEFF_SFT                            0
+#define SIDE_TONE_COEFF_MASK_SFT                       GENMASK(15, 0)
+
+/* AFE_SIDETONE_CON1 */
+#define STF_BYPASS_MODE_SFT                            31
+#define STF_BYPASS_MODE_MASK_SFT                       BIT(31)
+#define STF_BYPASS_MODE_O28_O29_SFT                    30
+#define STF_BYPASS_MODE_O28_O29_MASK_SFT               BIT(30)
+#define STF_BYPASS_MODE_I2S4_SFT                       29
+#define STF_BYPASS_MODE_I2S4_MASK_SFT                  BIT(29)
+#define STF_BYPASS_MODE_DL3_SFT                                27
+#define STF_BYPASS_MODE_DL3_MASK_SFT                   BIT(27)
+#define STF_BYPASS_MODE_I2S7_SFT                       26
+#define STF_BYPASS_MODE_I2S7_MASK_SFT                  BIT(26)
+#define STF_BYPASS_MODE_I2S9_SFT                       25
+#define STF_BYPASS_MODE_I2S9_MASK_SFT                  BIT(25)
+#define STF_O19O20_OUT_EN_SEL_SFT                      13
+#define STF_O19O20_OUT_EN_SEL_MASK_SFT                 BIT(13)
+#define STF_SOURCE_FROM_O19O20_SFT                     12
+#define STF_SOURCE_FROM_O19O20_MASK_SFT                        BIT(12)
+#define SIDE_TONE_ON_SFT                               8
+#define SIDE_TONE_ON_MASK_SFT                          BIT(8)
+#define SIDE_TONE_HALF_TAP_NUM_SFT                     0
+#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT                        GENMASK(5, 0)
+
+/* AFE_SIDETONE_GAIN */
+#define POSITIVE_GAIN_SFT                              16
+#define POSITIVE_GAIN_MASK_SFT                         GENMASK(18, 16)
+#define SIDE_TONE_GAIN_SFT                             0
+#define SIDE_TONE_GAIN_MASK_SFT                                GENMASK(15, 0)
+
+/* AFE_ADDA_DL_SDM_DCCOMP_CON */
+#define USE_3RD_SDM_SFT                                        28
+#define USE_3RD_SDM_MASK_SFT                           BIT(28)
+#define DL_FIFO_START_POINT_SFT                                24
+#define DL_FIFO_START_POINT_MASK_SFT                   GENMASK(26, 24)
+#define DL_FIFO_SWAP_SFT                               20
+#define DL_FIFO_SWAP_MASK_SFT                          BIT(20)
+#define C_AUDSDM1ORDSELECT_CTL_SFT                     19
+#define C_AUDSDM1ORDSELECT_CTL_MASK_SFT                        BIT(19)
+#define C_SDM7BITSEL_CTL_SFT                           18
+#define C_SDM7BITSEL_CTL_MASK_SFT                      BIT(18)
+#define GAIN_AT_SDM_RST_PRE_CTL_SFT                    15
+#define GAIN_AT_SDM_RST_PRE_CTL_MASK_SFT               BIT(15)
+#define DL_DCM_AUTO_IDLE_EN_SFT                                14
+#define DL_DCM_AUTO_IDLE_EN_MASK_SFT                   BIT(14)
+#define AFE_DL_SRC_DCM_EN_SFT                          13
+#define AFE_DL_SRC_DCM_EN_MASK_SFT                     BIT(13)
+#define AFE_DL_POST_SRC_DCM_EN_SFT                     12
+#define AFE_DL_POST_SRC_DCM_EN_MASK_SFT                        BIT(12)
+#define AUD_SDM_MONO_SFT                               9
+#define AUD_SDM_MONO_MASK_SFT                          BIT(9)
+#define AUD_DC_COMP_EN_SFT                             8
+#define AUD_DC_COMP_EN_MASK_SFT                                BIT(8)
+#define ATTGAIN_CTL_SFT                                        0
+#define ATTGAIN_CTL_MASK_SFT                           GENMASK(5, 0)
+
+/* AFE_SINEGEN_CON0 */
+#define DAC_EN_SFT                                     26
+#define DAC_EN_MASK                                    0x1
+#define DAC_EN_MASK_SFT                                        BIT(26)
+#define MUTE_SW_CH2_SFT                                        25
+#define MUTE_SW_CH2_MASK                               0x1
+#define MUTE_SW_CH2_MASK_SFT                           BIT(25)
+#define MUTE_SW_CH1_SFT                                        24
+#define MUTE_SW_CH1_MASK                               0x1
+#define MUTE_SW_CH1_MASK_SFT                           BIT(24)
+#define SINE_MODE_CH2_SFT                              20
+#define SINE_MODE_CH2_MASK                             0xf
+#define SINE_MODE_CH2_MASK_SFT                         GENMASK(23, 20)
+#define AMP_DIV_CH2_SFT                                        17
+#define AMP_DIV_CH2_MASK                               0x7
+#define AMP_DIV_CH2_MASK_SFT                           GENMASK(19, 17)
+#define FREQ_DIV_CH2_SFT                               12
+#define FREQ_DIV_CH2_MASK                              0x1f
+#define FREQ_DIV_CH2_MASK_SFT                          GENMASK(16, 12)
+#define SINE_MODE_CH1_SFT                              8
+#define SINE_MODE_CH1_MASK                             0xf
+#define SINE_MODE_CH1_MASK_SFT                         GENMASK(11, 8)
+#define AMP_DIV_CH1_SFT                                        5
+#define AMP_DIV_CH1_MASK                               0x7
+#define AMP_DIV_CH1_MASK_SFT                           GENMASK(7, 5)
+#define FREQ_DIV_CH1_SFT                               0
+#define FREQ_DIV_CH1_MASK                              0x1f
+#define FREQ_DIV_CH1_MASK_SFT                          GENMASK(4, 0)
+
+/* AFE_SINEGEN_CON2 */
+#define INNER_LOOP_BACK_MODE_SFT                       0
+#define INNER_LOOP_BACK_MODE_MASK_SFT                  GENMASK(7, 0)
+
+/* AFE_HD_ENGEN_ENABLE */
+#define AFE_24M_ON_SFT                                 1
+#define AFE_24M_ON_MASK_SFT                            BIT(1)
+#define AFE_22M_ON_SFT                                 0
+#define AFE_22M_ON_MASK_SFT                            BIT(0)
+
+/* AFE_ADDA_DL_NLE_FIFO_MON */
+#define DL_NLE_FIFO_WBIN_SFT                           8
+#define DL_NLE_FIFO_WBIN_MASK_SFT                      GENMASK(11, 8)
+#define DL_NLE_FIFO_RBIN_SFT                           4
+#define DL_NLE_FIFO_RBIN_MASK_SFT                      GENMASK(7, 4)
+#define DL_NLE_FIFO_RDACTIVE_SFT                       3
+#define DL_NLE_FIFO_RDACTIVE_MASK_SFT                  BIT(3)
+#define DL_NLE_FIFO_STARTRD_SFT                                2
+#define DL_NLE_FIFO_STARTRD_MASK_SFT                   BIT(2)
+#define DL_NLE_FIFO_RD_EMPTY_SFT                       1
+#define DL_NLE_FIFO_RD_EMPTY_MASK_SFT                  BIT(1)
+#define DL_NLE_FIFO_WR_FULL_SFT                                0
+#define DL_NLE_FIFO_WR_FULL_MASK_SFT                   BIT(0)
+
+/* AFE_DL1_CON0 */
+#define DL1_MODE_SFT                                   24
+#define DL1_MODE_MASK                                  0xf
+#define DL1_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL1_MINLEN_SFT                                 20
+#define DL1_MINLEN_MASK                                        0xf
+#define DL1_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL1_MAXLEN_SFT                                 16
+#define DL1_MAXLEN_MASK                                        0xf
+#define DL1_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL1_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL1_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL1_PBUF_SIZE_SFT                              12
+#define DL1_PBUF_SIZE_MASK                             0x3
+#define DL1_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL1_MONO_SFT                                   8
+#define DL1_MONO_MASK                                  0x1
+#define DL1_MONO_MASK_SFT                              BIT(8)
+#define DL1_NORMAL_MODE_SFT                            5
+#define DL1_NORMAL_MODE_MASK                           0x1
+#define DL1_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL1_HALIGN_SFT                                 4
+#define DL1_HALIGN_MASK                                        0x1
+#define DL1_HALIGN_MASK_SFT                            BIT(4)
+#define DL1_HD_MODE_SFT                                        0
+#define DL1_HD_MODE_MASK                               0x3
+#define DL1_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL2_CON0 */
+#define DL2_MODE_SFT                                   24
+#define DL2_MODE_MASK                                  0xf
+#define DL2_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL2_MINLEN_SFT                                 20
+#define DL2_MINLEN_MASK                                        0xf
+#define DL2_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL2_MAXLEN_SFT                                 16
+#define DL2_MAXLEN_MASK                                        0xf
+#define DL2_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL2_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL2_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL2_PBUF_SIZE_SFT                              12
+#define DL2_PBUF_SIZE_MASK                             0x3
+#define DL2_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL2_MONO_SFT                                   8
+#define DL2_MONO_MASK                                  0x1
+#define DL2_MONO_MASK_SFT                              BIT(8)
+#define DL2_NORMAL_MODE_SFT                            5
+#define DL2_NORMAL_MODE_MASK                           0x1
+#define DL2_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL2_HALIGN_SFT                                 4
+#define DL2_HALIGN_MASK                                        0x1
+#define DL2_HALIGN_MASK_SFT                            BIT(4)
+#define DL2_HD_MODE_SFT                                        0
+#define DL2_HD_MODE_MASK                               0x3
+#define DL2_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL3_CON0 */
+#define DL3_MODE_SFT                                   24
+#define DL3_MODE_MASK                                  0xf
+#define DL3_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL3_MINLEN_SFT                                 20
+#define DL3_MINLEN_MASK                                        0xf
+#define DL3_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL3_MAXLEN_SFT                                 16
+#define DL3_MAXLEN_MASK                                        0xf
+#define DL3_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL3_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL3_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL3_PBUF_SIZE_SFT                              12
+#define DL3_PBUF_SIZE_MASK                             0x3
+#define DL3_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL3_MONO_SFT                                   8
+#define DL3_MONO_MASK                                  0x1
+#define DL3_MONO_MASK_SFT                              BIT(8)
+#define DL3_NORMAL_MODE_SFT                            5
+#define DL3_NORMAL_MODE_MASK                           0x1
+#define DL3_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL3_HALIGN_SFT                                 4
+#define DL3_HALIGN_MASK                                        0x1
+#define DL3_HALIGN_MASK_SFT                            BIT(4)
+#define DL3_HD_MODE_SFT                                        0
+#define DL3_HD_MODE_MASK                               0x3
+#define DL3_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL4_CON0 */
+#define DL4_MODE_SFT                                   24
+#define DL4_MODE_MASK                                  0xf
+#define DL4_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL4_MINLEN_SFT                                 20
+#define DL4_MINLEN_MASK                                        0xf
+#define DL4_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL4_MAXLEN_SFT                                 16
+#define DL4_MAXLEN_MASK                                        0xf
+#define DL4_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL4_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL4_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL4_PBUF_SIZE_SFT                              12
+#define DL4_PBUF_SIZE_MASK                             0x3
+#define DL4_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL4_MONO_SFT                                   8
+#define DL4_MONO_MASK                                  0x1
+#define DL4_MONO_MASK_SFT                              BIT(8)
+#define DL4_NORMAL_MODE_SFT                            5
+#define DL4_NORMAL_MODE_MASK                           0x1
+#define DL4_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL4_HALIGN_SFT                                 4
+#define DL4_HALIGN_MASK                                        0x1
+#define DL4_HALIGN_MASK_SFT                            BIT(4)
+#define DL4_HD_MODE_SFT                                        0
+#define DL4_HD_MODE_MASK                               0x3
+#define DL4_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL5_CON0 */
+#define DL5_MODE_SFT                                   24
+#define DL5_MODE_MASK                                  0xf
+#define DL5_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL5_MINLEN_SFT                                 20
+#define DL5_MINLEN_MASK                                        0xf
+#define DL5_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL5_MAXLEN_SFT                                 16
+#define DL5_MAXLEN_MASK                                        0xf
+#define DL5_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL5_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL5_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL5_PBUF_SIZE_SFT                              12
+#define DL5_PBUF_SIZE_MASK                             0x3
+#define DL5_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL5_MONO_SFT                                   8
+#define DL5_MONO_MASK                                  0x1
+#define DL5_MONO_MASK_SFT                              BIT(8)
+#define DL5_NORMAL_MODE_SFT                            5
+#define DL5_NORMAL_MODE_MASK                           0x1
+#define DL5_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL5_HALIGN_SFT                                 4
+#define DL5_HALIGN_MASK                                        0x1
+#define DL5_HALIGN_MASK_SFT                            BIT(4)
+#define DL5_HD_MODE_SFT                                        0
+#define DL5_HD_MODE_MASK                               0x3
+#define DL5_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL6_CON0 */
+#define DL6_MODE_SFT                                   24
+#define DL6_MODE_MASK                                  0xf
+#define DL6_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL6_MINLEN_SFT                                 20
+#define DL6_MINLEN_MASK                                        0xf
+#define DL6_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL6_MAXLEN_SFT                                 16
+#define DL6_MAXLEN_MASK                                        0xf
+#define DL6_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL6_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL6_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL6_PBUF_SIZE_SFT                              12
+#define DL6_PBUF_SIZE_MASK                             0x3
+#define DL6_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL6_MONO_SFT                                   8
+#define DL6_MONO_MASK                                  0x1
+#define DL6_MONO_MASK_SFT                              BIT(8)
+#define DL6_NORMAL_MODE_SFT                            5
+#define DL6_NORMAL_MODE_MASK                           0x1
+#define DL6_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL6_HALIGN_SFT                                 4
+#define DL6_HALIGN_MASK                                        0x1
+#define DL6_HALIGN_MASK_SFT                            BIT(4)
+#define DL6_HD_MODE_SFT                                        0
+#define DL6_HD_MODE_MASK                               0x3
+#define DL6_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL7_CON0 */
+#define DL7_MODE_SFT                                   24
+#define DL7_MODE_MASK                                  0xf
+#define DL7_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL7_MINLEN_SFT                                 20
+#define DL7_MINLEN_MASK                                        0xf
+#define DL7_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL7_MAXLEN_SFT                                 16
+#define DL7_MAXLEN_MASK                                        0xf
+#define DL7_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL7_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL7_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL7_PBUF_SIZE_SFT                              12
+#define DL7_PBUF_SIZE_MASK                             0x3
+#define DL7_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL7_MONO_SFT                                   8
+#define DL7_MONO_MASK                                  0x1
+#define DL7_MONO_MASK_SFT                              BIT(8)
+#define DL7_NORMAL_MODE_SFT                            5
+#define DL7_NORMAL_MODE_MASK                           0x1
+#define DL7_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL7_HALIGN_SFT                                 4
+#define DL7_HALIGN_MASK                                        0x1
+#define DL7_HALIGN_MASK_SFT                            BIT(4)
+#define DL7_HD_MODE_SFT                                        0
+#define DL7_HD_MODE_MASK                               0x3
+#define DL7_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL8_CON0 */
+#define DL8_MODE_SFT                                   24
+#define DL8_MODE_MASK                                  0xf
+#define DL8_MODE_MASK_SFT                              GENMASK(27, 24)
+#define DL8_MINLEN_SFT                                 20
+#define DL8_MINLEN_MASK                                        0xf
+#define DL8_MINLEN_MASK_SFT                            GENMASK(23, 20)
+#define DL8_MAXLEN_SFT                                 16
+#define DL8_MAXLEN_MASK                                        0xf
+#define DL8_MAXLEN_MASK_SFT                            GENMASK(19, 16)
+#define DL8_SW_CLEAR_BUF_EMPTY_SFT                     15
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK                    0x1
+#define DL8_SW_CLEAR_BUF_EMPTY_MASK_SFT                        BIT(15)
+#define DL8_PBUF_SIZE_SFT                              12
+#define DL8_PBUF_SIZE_MASK                             0x3
+#define DL8_PBUF_SIZE_MASK_SFT                         GENMASK(13, 12)
+#define DL8_MONO_SFT                                   8
+#define DL8_MONO_MASK                                  0x1
+#define DL8_MONO_MASK_SFT                              BIT(8)
+#define DL8_NORMAL_MODE_SFT                            5
+#define DL8_NORMAL_MODE_MASK                           0x1
+#define DL8_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DL8_HALIGN_SFT                                 4
+#define DL8_HALIGN_MASK                                        0x1
+#define DL8_HALIGN_MASK_SFT                            BIT(4)
+#define DL8_HD_MODE_SFT                                        0
+#define DL8_HD_MODE_MASK                               0x3
+#define DL8_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_DL12_CON0 */
+#define DL12_MODE_SFT                                  24
+#define DL12_MODE_MASK                                 0xf
+#define DL12_MODE_MASK_SFT                             GENMASK(27, 24)
+#define DL12_MINLEN_SFT                                        20
+#define DL12_MINLEN_MASK                               0xf
+#define DL12_MINLEN_MASK_SFT                           GENMASK(23, 20)
+#define DL12_MAXLEN_SFT                                        16
+#define DL12_MAXLEN_MASK                               0xf
+#define DL12_MAXLEN_MASK_SFT                           GENMASK(19, 16)
+#define DL12_SW_CLEAR_BUF_EMPTY_SFT                    15
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK                   0x1
+#define DL12_SW_CLEAR_BUF_EMPTY_MASK_SFT               BIT(15)
+#define DL12_PBUF_SIZE_SFT                             12
+#define DL12_PBUF_SIZE_MASK                            0x3
+#define DL12_PBUF_SIZE_MASK_SFT                                GENMASK(13, 12)
+#define DL12_4CH_EN_SFT                                        11
+#define DL12_4CH_EN_MASK                               0x1
+#define DL12_4CH_EN_MASK_SFT                           BIT(11)
+#define DL12_MONO_SFT                                  8
+#define DL12_MONO_MASK                                 0x1
+#define DL12_MONO_MASK_SFT                             BIT(8)
+#define DL12_NORMAL_MODE_SFT                           5
+#define DL12_NORMAL_MODE_MASK                          0x1
+#define DL12_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define DL12_HALIGN_SFT                                        4
+#define DL12_HALIGN_MASK                               0x1
+#define DL12_HALIGN_MASK_SFT                           BIT(4)
+#define DL12_HD_MODE_SFT                               0
+#define DL12_HD_MODE_MASK                              0x3
+#define DL12_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_AWB_CON0 */
+#define AWB_MODE_SFT                                   24
+#define AWB_MODE_MASK                                  0xf
+#define AWB_MODE_MASK_SFT                              GENMASK(27, 24)
+#define AWB_SW_CLEAR_BUF_FULL_SFT                      15
+#define AWB_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define AWB_SW_CLEAR_BUF_FULL_MASK_SFT                 BIT(15)
+#define AWB_R_MONO_SFT                                 9
+#define AWB_R_MONO_MASK                                        0x1
+#define AWB_R_MONO_MASK_SFT                            BIT(9)
+#define AWB_MONO_SFT                                   8
+#define AWB_MONO_MASK                                  0x1
+#define AWB_MONO_MASK_SFT                              BIT(8)
+#define AWB_WR_SIGN_SFT                                        6
+#define AWB_WR_SIGN_MASK                               0x1
+#define AWB_WR_SIGN_MASK_SFT                           BIT(6)
+#define AWB_NORMAL_MODE_SFT                            5
+#define AWB_NORMAL_MODE_MASK                           0x1
+#define AWB_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define AWB_HALIGN_SFT                                 4
+#define AWB_HALIGN_MASK                                        0x1
+#define AWB_HALIGN_MASK_SFT                            BIT(4)
+#define AWB_HD_MODE_SFT                                        0
+#define AWB_HD_MODE_MASK                               0x3
+#define AWB_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_AWB2_CON0 */
+#define AWB2_MODE_SFT                                  24
+#define AWB2_MODE_MASK                                 0xf
+#define AWB2_MODE_MASK_SFT                             GENMASK(27, 24)
+#define AWB2_SW_CLEAR_BUF_FULL_SFT                     15
+#define AWB2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define AWB2_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define AWB2_R_MONO_SFT                                        9
+#define AWB2_R_MONO_MASK                               0x1
+#define AWB2_R_MONO_MASK_SFT                           BIT(9)
+#define AWB2_MONO_SFT                                  8
+#define AWB2_MONO_MASK                                 0x1
+#define AWB2_MONO_MASK_SFT                             BIT(8)
+#define AWB2_WR_SIGN_SFT                               6
+#define AWB2_WR_SIGN_MASK                              0x1
+#define AWB2_WR_SIGN_MASK_SFT                          BIT(6)
+#define AWB2_NORMAL_MODE_SFT                           5
+#define AWB2_NORMAL_MODE_MASK                          0x1
+#define AWB2_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define AWB2_HALIGN_SFT                                        4
+#define AWB2_HALIGN_MASK                               0x1
+#define AWB2_HALIGN_MASK_SFT                           BIT(4)
+#define AWB2_HD_MODE_SFT                               0
+#define AWB2_HD_MODE_MASK                              0x3
+#define AWB2_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_VUL_CON0 */
+#define VUL_MODE_SFT                                   24
+#define VUL_MODE_MASK                                  0xf
+#define VUL_MODE_MASK_SFT                              GENMASK(27, 24)
+#define VUL_SW_CLEAR_BUF_FULL_SFT                      15
+#define VUL_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define VUL_SW_CLEAR_BUF_FULL_MASK_SFT                 BIT(15)
+#define VUL_R_MONO_SFT                                 9
+#define VUL_R_MONO_MASK                                        0x1
+#define VUL_R_MONO_MASK_SFT                            BIT(9)
+#define VUL_MONO_SFT                                   8
+#define VUL_MONO_MASK                                  0x1
+#define VUL_MONO_MASK_SFT                              BIT(8)
+#define VUL_WR_SIGN_SFT                                        6
+#define VUL_WR_SIGN_MASK                               0x1
+#define VUL_WR_SIGN_MASK_SFT                           BIT(6)
+#define VUL_NORMAL_MODE_SFT                            5
+#define VUL_NORMAL_MODE_MASK                           0x1
+#define VUL_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define VUL_HALIGN_SFT                                 4
+#define VUL_HALIGN_MASK                                        0x1
+#define VUL_HALIGN_MASK_SFT                            BIT(4)
+#define VUL_HD_MODE_SFT                                        0
+#define VUL_HD_MODE_MASK                               0x3
+#define VUL_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_VUL12_CON0 */
+#define VUL12_MODE_SFT                                 24
+#define VUL12_MODE_MASK                                        0xf
+#define VUL12_MODE_MASK_SFT                            GENMASK(27, 24)
+#define VUL12_SW_CLEAR_BUF_FULL_SFT                    15
+#define VUL12_SW_CLEAR_BUF_FULL_MASK                   0x1
+#define VUL12_SW_CLEAR_BUF_FULL_MASK_SFT               BIT(15)
+#define VUL12_4CH_EN_SFT                               11
+#define VUL12_4CH_EN_MASK                              0x1
+#define VUL12_4CH_EN_MASK_SFT                          BIT(11)
+#define VUL12_R_MONO_SFT                               9
+#define VUL12_R_MONO_MASK                              0x1
+#define VUL12_R_MONO_MASK_SFT                          BIT(9)
+#define VUL12_MONO_SFT                                 8
+#define VUL12_MONO_MASK                                        0x1
+#define VUL12_MONO_MASK_SFT                            BIT(8)
+#define VUL12_WR_SIGN_SFT                              6
+#define VUL12_WR_SIGN_MASK                             0x1
+#define VUL12_WR_SIGN_MASK_SFT                         BIT(6)
+#define VUL12_NORMAL_MODE_SFT                          5
+#define VUL12_NORMAL_MODE_MASK                         0x1
+#define VUL12_NORMAL_MODE_MASK_SFT                     BIT(5)
+#define VUL12_HALIGN_SFT                               4
+#define VUL12_HALIGN_MASK                              0x1
+#define VUL12_HALIGN_MASK_SFT                          BIT(4)
+#define VUL12_HD_MODE_SFT                              0
+#define VUL12_HD_MODE_MASK                             0x3
+#define VUL12_HD_MODE_MASK_SFT                         GENMASK(1, 0)
+
+/* AFE_VUL2_CON0 */
+#define VUL2_MODE_SFT                                  24
+#define VUL2_MODE_MASK                                 0xf
+#define VUL2_MODE_MASK_SFT                             GENMASK(27, 24)
+#define VUL2_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL2_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define VUL2_R_MONO_SFT                                        9
+#define VUL2_R_MONO_MASK                               0x1
+#define VUL2_R_MONO_MASK_SFT                           BIT(9)
+#define VUL2_MONO_SFT                                  8
+#define VUL2_MONO_MASK                                 0x1
+#define VUL2_MONO_MASK_SFT                             BIT(8)
+#define VUL2_WR_SIGN_SFT                               6
+#define VUL2_WR_SIGN_MASK                              0x1
+#define VUL2_WR_SIGN_MASK_SFT                          BIT(6)
+#define VUL2_NORMAL_MODE_SFT                           5
+#define VUL2_NORMAL_MODE_MASK                          0x1
+#define VUL2_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define VUL2_HALIGN_SFT                                        4
+#define VUL2_HALIGN_MASK                               0x1
+#define VUL2_HALIGN_MASK_SFT                           BIT(4)
+#define VUL2_HD_MODE_SFT                               0
+#define VUL2_HD_MODE_MASK                              0x3
+#define VUL2_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_VUL3_CON0 */
+#define VUL3_MODE_SFT                                  24
+#define VUL3_MODE_MASK                                 0xf
+#define VUL3_MODE_MASK_SFT                             GENMASK(27, 24)
+#define VUL3_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL3_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL3_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define VUL3_R_MONO_SFT                                        9
+#define VUL3_R_MONO_MASK                               0x1
+#define VUL3_R_MONO_MASK_SFT                           BIT(9)
+#define VUL3_MONO_SFT                                  8
+#define VUL3_MONO_MASK                                 0x1
+#define VUL3_MONO_MASK_SFT                             BIT(8)
+#define VUL3_WR_SIGN_SFT                               6
+#define VUL3_WR_SIGN_MASK                              0x1
+#define VUL3_WR_SIGN_MASK_SFT                          BIT(6)
+#define VUL3_NORMAL_MODE_SFT                           5
+#define VUL3_NORMAL_MODE_MASK                          0x1
+#define VUL3_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define VUL3_HALIGN_SFT                                        4
+#define VUL3_HALIGN_MASK                               0x1
+#define VUL3_HALIGN_MASK_SFT                           BIT(4)
+#define VUL3_HD_MODE_SFT                               0
+#define VUL3_HD_MODE_MASK                              0x3
+#define VUL3_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_VUL4_CON0 */
+#define VUL4_MODE_SFT                                  24
+#define VUL4_MODE_MASK                                 0xf
+#define VUL4_MODE_MASK_SFT                             GENMASK(27, 24)
+#define VUL4_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL4_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL4_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define VUL4_R_MONO_SFT                                        9
+#define VUL4_R_MONO_MASK                               0x1
+#define VUL4_R_MONO_MASK_SFT                           BIT(9)
+#define VUL4_MONO_SFT                                  8
+#define VUL4_MONO_MASK                                 0x1
+#define VUL4_MONO_MASK_SFT                             BIT(8)
+#define VUL4_WR_SIGN_SFT                               6
+#define VUL4_WR_SIGN_MASK                              0x1
+#define VUL4_WR_SIGN_MASK_SFT                          BIT(6)
+#define VUL4_NORMAL_MODE_SFT                           5
+#define VUL4_NORMAL_MODE_MASK                          0x1
+#define VUL4_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define VUL4_HALIGN_SFT                                        4
+#define VUL4_HALIGN_MASK                               0x1
+#define VUL4_HALIGN_MASK_SFT                           BIT(4)
+#define VUL4_HD_MODE_SFT                               0
+#define VUL4_HD_MODE_MASK                              0x3
+#define VUL4_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_VUL5_CON0 */
+#define VUL5_MODE_SFT                                  24
+#define VUL5_MODE_MASK                                 0xf
+#define VUL5_MODE_MASK_SFT                             GENMASK(27, 24)
+#define VUL5_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL5_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL5_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define VUL5_R_MONO_SFT                                        9
+#define VUL5_R_MONO_MASK                               0x1
+#define VUL5_R_MONO_MASK_SFT                           BIT(9)
+#define VUL5_MONO_SFT                                  8
+#define VUL5_MONO_MASK                                 0x1
+#define VUL5_MONO_MASK_SFT                             BIT(8)
+#define VUL5_WR_SIGN_SFT                               6
+#define VUL5_WR_SIGN_MASK                              0x1
+#define VUL5_WR_SIGN_MASK_SFT                          BIT(6)
+#define VUL5_NORMAL_MODE_SFT                           5
+#define VUL5_NORMAL_MODE_MASK                          0x1
+#define VUL5_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define VUL5_HALIGN_SFT                                        4
+#define VUL5_HALIGN_MASK                               0x1
+#define VUL5_HALIGN_MASK_SFT                           BIT(4)
+#define VUL5_HD_MODE_SFT                               0
+#define VUL5_HD_MODE_MASK                              0x3
+#define VUL5_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_VUL6_CON0 */
+#define VUL6_MODE_SFT                                  24
+#define VUL6_MODE_MASK                                 0xf
+#define VUL6_MODE_MASK_SFT                             GENMASK(27, 24)
+#define VUL6_SW_CLEAR_BUF_FULL_SFT                     15
+#define VUL6_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define VUL6_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define VUL6_R_MONO_SFT                                        9
+#define VUL6_R_MONO_MASK                               0x1
+#define VUL6_R_MONO_MASK_SFT                           BIT(9)
+#define VUL6_MONO_SFT                                  8
+#define VUL6_MONO_MASK                                 0x1
+#define VUL6_MONO_MASK_SFT                             BIT(8)
+#define VUL6_WR_SIGN_SFT                               6
+#define VUL6_WR_SIGN_MASK                              0x1
+#define VUL6_WR_SIGN_MASK_SFT                          BIT(6)
+#define VUL6_NORMAL_MODE_SFT                           5
+#define VUL6_NORMAL_MODE_MASK                          0x1
+#define VUL6_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define VUL6_HALIGN_SFT                                        4
+#define VUL6_HALIGN_MASK                               0x1
+#define VUL6_HALIGN_MASK_SFT                           BIT(4)
+#define VUL6_HD_MODE_SFT                               0
+#define VUL6_HD_MODE_MASK                              0x3
+#define VUL6_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_DAI_CON0 */
+#define DAI_MODE_SFT                                   24
+#define DAI_MODE_MASK                                  0x3
+#define DAI_MODE_MASK_SFT                              GENMASK(25, 24)
+#define DAI_SW_CLEAR_BUF_FULL_SFT                      15
+#define DAI_SW_CLEAR_BUF_FULL_MASK                     0x1
+#define DAI_SW_CLEAR_BUF_FULL_MASK_SFT                 BIT(15)
+#define DAI_DUPLICATE_WR_SFT                           10
+#define DAI_DUPLICATE_WR_MASK                          0x1
+#define DAI_DUPLICATE_WR_MASK_SFT                      BIT(10)
+#define DAI_MONO_SFT                                   8
+#define DAI_MONO_MASK                                  0x1
+#define DAI_MONO_MASK_SFT                              BIT(8)
+#define DAI_WR_SIGN_SFT                                        6
+#define DAI_WR_SIGN_MASK                               0x1
+#define DAI_WR_SIGN_MASK_SFT                           BIT(6)
+#define DAI_NORMAL_MODE_SFT                            5
+#define DAI_NORMAL_MODE_MASK                           0x1
+#define DAI_NORMAL_MODE_MASK_SFT                       BIT(5)
+#define DAI_HALIGN_SFT                                 4
+#define DAI_HALIGN_MASK                                        0x1
+#define DAI_HALIGN_MASK_SFT                            BIT(4)
+#define DAI_HD_MODE_SFT                                        0
+#define DAI_HD_MODE_MASK                               0x3
+#define DAI_HD_MODE_MASK_SFT                           GENMASK(1, 0)
+
+/* AFE_MOD_DAI_CON0 */
+#define MOD_DAI_MODE_SFT                               24
+#define MOD_DAI_MODE_MASK                              0x3
+#define MOD_DAI_MODE_MASK_SFT                          GENMASK(25, 24)
+#define MOD_DAI_SW_CLEAR_BUF_FULL_SFT                  15
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK                 0x1
+#define MOD_DAI_SW_CLEAR_BUF_FULL_MASK_SFT             BIT(15)
+#define MOD_DAI_DUPLICATE_WR_SFT                       10
+#define MOD_DAI_DUPLICATE_WR_MASK                      0x1
+#define MOD_DAI_DUPLICATE_WR_MASK_SFT                  BIT(10)
+#define MOD_DAI_MONO_SFT                               8
+#define MOD_DAI_MONO_MASK                              0x1
+#define MOD_DAI_MONO_MASK_SFT                          BIT(8)
+#define MOD_DAI_WR_SIGN_SFT                            6
+#define MOD_DAI_WR_SIGN_MASK                           0x1
+#define MOD_DAI_WR_SIGN_MASK_SFT                       BIT(6)
+#define MOD_DAI_NORMAL_MODE_SFT                                5
+#define MOD_DAI_NORMAL_MODE_MASK                       0x1
+#define MOD_DAI_NORMAL_MODE_MASK_SFT                   BIT(5)
+#define MOD_DAI_HALIGN_SFT                             4
+#define MOD_DAI_HALIGN_MASK                            0x1
+#define MOD_DAI_HALIGN_MASK_SFT                                BIT(4)
+#define MOD_DAI_HD_MODE_SFT                            0
+#define MOD_DAI_HD_MODE_MASK                           0x3
+#define MOD_DAI_HD_MODE_MASK_SFT                       GENMASK(1, 0)
+
+/* AFE_DAI2_CON0 */
+#define DAI2_MODE_SFT                                  24
+#define DAI2_MODE_MASK                                 0xf
+#define DAI2_MODE_MASK_SFT                             GENMASK(27, 24)
+#define DAI2_SW_CLEAR_BUF_FULL_SFT                     15
+#define DAI2_SW_CLEAR_BUF_FULL_MASK                    0x1
+#define DAI2_SW_CLEAR_BUF_FULL_MASK_SFT                        BIT(15)
+#define DAI2_DUPLICATE_WR_SFT                          10
+#define DAI2_DUPLICATE_WR_MASK                         0x1
+#define DAI2_DUPLICATE_WR_MASK_SFT                     BIT(10)
+#define DAI2_MONO_SFT                                  8
+#define DAI2_MONO_MASK                                 0x1
+#define DAI2_MONO_MASK_SFT                             BIT(8)
+#define DAI2_WR_SIGN_SFT                               6
+#define DAI2_WR_SIGN_MASK                              0x1
+#define DAI2_WR_SIGN_MASK_SFT                          BIT(6)
+#define DAI2_NORMAL_MODE_SFT                           5
+#define DAI2_NORMAL_MODE_MASK                          0x1
+#define DAI2_NORMAL_MODE_MASK_SFT                      BIT(5)
+#define DAI2_HALIGN_SFT                                        4
+#define DAI2_HALIGN_MASK                               0x1
+#define DAI2_HALIGN_MASK_SFT                           BIT(4)
+#define DAI2_HD_MODE_SFT                               0
+#define DAI2_HD_MODE_MASK                              0x3
+#define DAI2_HD_MODE_MASK_SFT                          GENMASK(1, 0)
+
+/* AFE_MEMIF_CON0 */
+#define CPU_COMPACT_MODE_SFT                           2
+#define CPU_COMPACT_MODE_MASK_SFT                      BIT(2)
+#define CPU_HD_ALIGN_SFT                               1
+#define CPU_HD_ALIGN_MASK_SFT                          BIT(1)
+#define SYSRAM_SIGN_SFT                                        0
+#define SYSRAM_SIGN_MASK_SFT                           BIT(0)
+
+/* AFE_IRQ_MCU_CON0 */
+#define IRQ31_MCU_ON_SFT                               31
+#define IRQ31_MCU_ON_MASK                              0x1
+#define IRQ31_MCU_ON_MASK_SFT                          BIT(31)
+#define IRQ26_MCU_ON_SFT                               26
+#define IRQ26_MCU_ON_MASK                              0x1
+#define IRQ26_MCU_ON_MASK_SFT                          BIT(26)
+#define IRQ25_MCU_ON_SFT                               25
+#define IRQ25_MCU_ON_MASK                              0x1
+#define IRQ25_MCU_ON_MASK_SFT                          BIT(25)
+#define IRQ24_MCU_ON_SFT                               24
+#define IRQ24_MCU_ON_MASK                              0x1
+#define IRQ24_MCU_ON_MASK_SFT                          BIT(24)
+#define IRQ23_MCU_ON_SFT                               23
+#define IRQ23_MCU_ON_MASK                              0x1
+#define IRQ23_MCU_ON_MASK_SFT                          BIT(23)
+#define IRQ22_MCU_ON_SFT                               22
+#define IRQ22_MCU_ON_MASK                              0x1
+#define IRQ22_MCU_ON_MASK_SFT                          BIT(22)
+#define IRQ21_MCU_ON_SFT                               21
+#define IRQ21_MCU_ON_MASK                              0x1
+#define IRQ21_MCU_ON_MASK_SFT                          BIT(21)
+#define IRQ20_MCU_ON_SFT                               20
+#define IRQ20_MCU_ON_MASK                              0x1
+#define IRQ20_MCU_ON_MASK_SFT                          BIT(20)
+#define IRQ19_MCU_ON_SFT                               19
+#define IRQ19_MCU_ON_MASK                              0x1
+#define IRQ19_MCU_ON_MASK_SFT                          BIT(19)
+#define IRQ18_MCU_ON_SFT                               18
+#define IRQ18_MCU_ON_MASK                              0x1
+#define IRQ18_MCU_ON_MASK_SFT                          BIT(18)
+#define IRQ17_MCU_ON_SFT                               17
+#define IRQ17_MCU_ON_MASK                              0x1
+#define IRQ17_MCU_ON_MASK_SFT                          BIT(17)
+#define IRQ16_MCU_ON_SFT                               16
+#define IRQ16_MCU_ON_MASK                              0x1
+#define IRQ16_MCU_ON_MASK_SFT                          BIT(16)
+#define IRQ15_MCU_ON_SFT                               15
+#define IRQ15_MCU_ON_MASK                              0x1
+#define IRQ15_MCU_ON_MASK_SFT                          BIT(15)
+#define IRQ14_MCU_ON_SFT                               14
+#define IRQ14_MCU_ON_MASK                              0x1
+#define IRQ14_MCU_ON_MASK_SFT                          BIT(14)
+#define IRQ13_MCU_ON_SFT                               13
+#define IRQ13_MCU_ON_MASK                              0x1
+#define IRQ13_MCU_ON_MASK_SFT                          BIT(13)
+#define IRQ12_MCU_ON_SFT                               12
+#define IRQ12_MCU_ON_MASK                              0x1
+#define IRQ12_MCU_ON_MASK_SFT                          BIT(12)
+#define IRQ11_MCU_ON_SFT                               11
+#define IRQ11_MCU_ON_MASK                              0x1
+#define IRQ11_MCU_ON_MASK_SFT                          BIT(11)
+#define IRQ10_MCU_ON_SFT                               10
+#define IRQ10_MCU_ON_MASK                              0x1
+#define IRQ10_MCU_ON_MASK_SFT                          BIT(10)
+#define IRQ9_MCU_ON_SFT                                        9
+#define IRQ9_MCU_ON_MASK                               0x1
+#define IRQ9_MCU_ON_MASK_SFT                           BIT(9)
+#define IRQ8_MCU_ON_SFT                                        8
+#define IRQ8_MCU_ON_MASK                               0x1
+#define IRQ8_MCU_ON_MASK_SFT                           BIT(8)
+#define IRQ7_MCU_ON_SFT                                        7
+#define IRQ7_MCU_ON_MASK                               0x1
+#define IRQ7_MCU_ON_MASK_SFT                           BIT(7)
+#define IRQ6_MCU_ON_SFT                                        6
+#define IRQ6_MCU_ON_MASK                               0x1
+#define IRQ6_MCU_ON_MASK_SFT                           BIT(6)
+#define IRQ5_MCU_ON_SFT                                        5
+#define IRQ5_MCU_ON_MASK                               0x1
+#define IRQ5_MCU_ON_MASK_SFT                           BIT(5)
+#define IRQ4_MCU_ON_SFT                                        4
+#define IRQ4_MCU_ON_MASK                               0x1
+#define IRQ4_MCU_ON_MASK_SFT                           BIT(4)
+#define IRQ3_MCU_ON_SFT                                        3
+#define IRQ3_MCU_ON_MASK                               0x1
+#define IRQ3_MCU_ON_MASK_SFT                           BIT(3)
+#define IRQ2_MCU_ON_SFT                                        2
+#define IRQ2_MCU_ON_MASK                               0x1
+#define IRQ2_MCU_ON_MASK_SFT                           BIT(2)
+#define IRQ1_MCU_ON_SFT                                        1
+#define IRQ1_MCU_ON_MASK                               0x1
+#define IRQ1_MCU_ON_MASK_SFT                           BIT(1)
+#define IRQ0_MCU_ON_SFT                                        0
+#define IRQ0_MCU_ON_MASK                               0x1
+#define IRQ0_MCU_ON_MASK_SFT                           BIT(0)
+
+/* AFE_IRQ_MCU_CON1 */
+#define IRQ7_MCU_MODE_SFT                              28
+#define IRQ7_MCU_MODE_MASK                             0xf
+#define IRQ7_MCU_MODE_MASK_SFT                         GENMASK(31, 28)
+#define IRQ6_MCU_MODE_SFT                              24
+#define IRQ6_MCU_MODE_MASK                             0xf
+#define IRQ6_MCU_MODE_MASK_SFT                         GENMASK(27, 24)
+#define IRQ5_MCU_MODE_SFT                              20
+#define IRQ5_MCU_MODE_MASK                             0xf
+#define IRQ5_MCU_MODE_MASK_SFT                         GENMASK(23, 20)
+#define IRQ4_MCU_MODE_SFT                              16
+#define IRQ4_MCU_MODE_MASK                             0xf
+#define IRQ4_MCU_MODE_MASK_SFT                         GENMASK(19, 16)
+#define IRQ3_MCU_MODE_SFT                              12
+#define IRQ3_MCU_MODE_MASK                             0xf
+#define IRQ3_MCU_MODE_MASK_SFT                         GENMASK(15, 12)
+#define IRQ2_MCU_MODE_SFT                              8
+#define IRQ2_MCU_MODE_MASK                             0xf
+#define IRQ2_MCU_MODE_MASK_SFT                         GENMASK(11, 8)
+#define IRQ1_MCU_MODE_SFT                              4
+#define IRQ1_MCU_MODE_MASK                             0xf
+#define IRQ1_MCU_MODE_MASK_SFT                         GENMASK(7, 4)
+#define IRQ0_MCU_MODE_SFT                              0
+#define IRQ0_MCU_MODE_MASK                             0xf
+#define IRQ0_MCU_MODE_MASK_SFT                         GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CON2 */
+#define IRQ15_MCU_MODE_SFT                             28
+#define IRQ15_MCU_MODE_MASK                            0xf
+#define IRQ15_MCU_MODE_MASK_SFT                                GENMASK(31, 28)
+#define IRQ14_MCU_MODE_SFT                             24
+#define IRQ14_MCU_MODE_MASK                            0xf
+#define IRQ14_MCU_MODE_MASK_SFT                                GENMASK(27, 24)
+#define IRQ13_MCU_MODE_SFT                             20
+#define IRQ13_MCU_MODE_MASK                            0xf
+#define IRQ13_MCU_MODE_MASK_SFT                                GENMASK(23, 20)
+#define IRQ12_MCU_MODE_SFT                             16
+#define IRQ12_MCU_MODE_MASK                            0xf
+#define IRQ12_MCU_MODE_MASK_SFT                                GENMASK(19, 16)
+#define IRQ11_MCU_MODE_SFT                             12
+#define IRQ11_MCU_MODE_MASK                            0xf
+#define IRQ11_MCU_MODE_MASK_SFT                                GENMASK(15, 12)
+#define IRQ10_MCU_MODE_SFT                             8
+#define IRQ10_MCU_MODE_MASK                            0xf
+#define IRQ10_MCU_MODE_MASK_SFT                                GENMASK(11, 8)
+#define IRQ9_MCU_MODE_SFT                              4
+#define IRQ9_MCU_MODE_MASK                             0xf
+#define IRQ9_MCU_MODE_MASK_SFT                         GENMASK(7, 4)
+#define IRQ8_MCU_MODE_SFT                              0
+#define IRQ8_MCU_MODE_MASK                             0xf
+#define IRQ8_MCU_MODE_MASK_SFT                         GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CON3 */
+#define IRQ23_MCU_MODE_SFT                             28
+#define IRQ23_MCU_MODE_MASK                            0xf
+#define IRQ23_MCU_MODE_MASK_SFT                                GENMASK(31, 28)
+#define IRQ22_MCU_MODE_SFT                             24
+#define IRQ22_MCU_MODE_MASK                            0xf
+#define IRQ22_MCU_MODE_MASK_SFT                                GENMASK(27, 24)
+#define IRQ21_MCU_MODE_SFT                             20
+#define IRQ21_MCU_MODE_MASK                            0xf
+#define IRQ21_MCU_MODE_MASK_SFT                                GENMASK(23, 20)
+#define IRQ20_MCU_MODE_SFT                             16
+#define IRQ20_MCU_MODE_MASK                            0xf
+#define IRQ20_MCU_MODE_MASK_SFT                                GENMASK(19, 16)
+#define IRQ19_MCU_MODE_SFT                             12
+#define IRQ19_MCU_MODE_MASK                            0xf
+#define IRQ19_MCU_MODE_MASK_SFT                                GENMASK(15, 12)
+#define IRQ18_MCU_MODE_SFT                             8
+#define IRQ18_MCU_MODE_MASK                            0xf
+#define IRQ18_MCU_MODE_MASK_SFT                                GENMASK(11, 8)
+#define IRQ17_MCU_MODE_SFT                             4
+#define IRQ17_MCU_MODE_MASK                            0xf
+#define IRQ17_MCU_MODE_MASK_SFT                                GENMASK(7, 4)
+#define IRQ16_MCU_MODE_SFT                             0
+#define IRQ16_MCU_MODE_MASK                            0xf
+#define IRQ16_MCU_MODE_MASK_SFT                                GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CON4 */
+#define IRQ26_MCU_MODE_SFT                             8
+#define IRQ26_MCU_MODE_MASK                            0xf
+#define IRQ26_MCU_MODE_MASK_SFT                                GENMASK(11, 8)
+#define IRQ25_MCU_MODE_SFT                             4
+#define IRQ25_MCU_MODE_MASK                            0xf
+#define IRQ25_MCU_MODE_MASK_SFT                                GENMASK(7, 4)
+#define IRQ24_MCU_MODE_SFT                             0
+#define IRQ24_MCU_MODE_MASK                            0xf
+#define IRQ24_MCU_MODE_MASK_SFT                                GENMASK(3, 0)
+
+/* AFE_IRQ_MCU_CLR */
+#define IRQ31_MCU_CLR_SFT                              31
+#define IRQ31_MCU_CLR_MASK_SFT                         BIT(31)
+#define IRQ26_MCU_CLR_SFT                              26
+#define IRQ26_MCU_CLR_MASK_SFT                         BIT(26)
+#define IRQ25_MCU_CLR_SFT                              25
+#define IRQ25_MCU_CLR_MASK_SFT                         BIT(25)
+#define IRQ24_MCU_CLR_SFT                              24
+#define IRQ24_MCU_CLR_MASK_SFT                         BIT(24)
+#define IRQ23_MCU_CLR_SFT                              23
+#define IRQ23_MCU_CLR_MASK_SFT                         BIT(23)
+#define IRQ22_MCU_CLR_SFT                              22
+#define IRQ22_MCU_CLR_MASK_SFT                         BIT(22)
+#define IRQ21_MCU_CLR_SFT                              21
+#define IRQ21_MCU_CLR_MASK_SFT                         BIT(21)
+#define IRQ20_MCU_CLR_SFT                              20
+#define IRQ20_MCU_CLR_MASK_SFT                         BIT(20)
+#define IRQ19_MCU_CLR_SFT                              19
+#define IRQ19_MCU_CLR_MASK_SFT                         BIT(19)
+#define IRQ18_MCU_CLR_SFT                              18
+#define IRQ18_MCU_CLR_MASK_SFT                         BIT(18)
+#define IRQ17_MCU_CLR_SFT                              17
+#define IRQ17_MCU_CLR_MASK_SFT                         BIT(17)
+#define IRQ16_MCU_CLR_SFT                              16
+#define IRQ16_MCU_CLR_MASK_SFT                         BIT(16)
+#define IRQ15_MCU_CLR_SFT                              15
+#define IRQ15_MCU_CLR_MASK_SFT                         BIT(15)
+#define IRQ14_MCU_CLR_SFT                              14
+#define IRQ14_MCU_CLR_MASK_SFT                         BIT(14)
+#define IRQ13_MCU_CLR_SFT                              13
+#define IRQ13_MCU_CLR_MASK_SFT                         BIT(13)
+#define IRQ12_MCU_CLR_SFT                              12
+#define IRQ12_MCU_CLR_MASK_SFT                         BIT(12)
+#define IRQ11_MCU_CLR_SFT                              11
+#define IRQ11_MCU_CLR_MASK_SFT                         BIT(11)
+#define IRQ10_MCU_CLR_SFT                              10
+#define IRQ10_MCU_CLR_MASK_SFT                         BIT(10)
+#define IRQ9_MCU_CLR_SFT                               9
+#define IRQ9_MCU_CLR_MASK_SFT                          BIT(9)
+#define IRQ8_MCU_CLR_SFT                               8
+#define IRQ8_MCU_CLR_MASK_SFT                          BIT(8)
+#define IRQ7_MCU_CLR_SFT                               7
+#define IRQ7_MCU_CLR_MASK_SFT                          BIT(7)
+#define IRQ6_MCU_CLR_SFT                               6
+#define IRQ6_MCU_CLR_MASK_SFT                          BIT(6)
+#define IRQ5_MCU_CLR_SFT                               5
+#define IRQ5_MCU_CLR_MASK_SFT                          BIT(5)
+#define IRQ4_MCU_CLR_SFT                               4
+#define IRQ4_MCU_CLR_MASK_SFT                          BIT(4)
+#define IRQ3_MCU_CLR_SFT                               3
+#define IRQ3_MCU_CLR_MASK_SFT                          BIT(3)
+#define IRQ2_MCU_CLR_SFT                               2
+#define IRQ2_MCU_CLR_MASK_SFT                          BIT(2)
+#define IRQ1_MCU_CLR_SFT                               1
+#define IRQ1_MCU_CLR_MASK_SFT                          BIT(1)
+#define IRQ0_MCU_CLR_SFT                               0
+#define IRQ0_MCU_CLR_MASK_SFT                          BIT(0)
+
+/* AFE_IRQ_MCU_EN */
+#define IRQ31_MCU_EN_SFT                               31
+#define IRQ30_MCU_EN_SFT                               30
+#define IRQ29_MCU_EN_SFT                               29
+#define IRQ28_MCU_EN_SFT                               28
+#define IRQ27_MCU_EN_SFT                               27
+#define IRQ26_MCU_EN_SFT                               26
+#define IRQ25_MCU_EN_SFT                               25
+#define IRQ24_MCU_EN_SFT                               24
+#define IRQ23_MCU_EN_SFT                               23
+#define IRQ22_MCU_EN_SFT                               22
+#define IRQ21_MCU_EN_SFT                               21
+#define IRQ20_MCU_EN_SFT                               20
+#define IRQ19_MCU_EN_SFT                               19
+#define IRQ18_MCU_EN_SFT                               18
+#define IRQ17_MCU_EN_SFT                               17
+#define IRQ16_MCU_EN_SFT                               16
+#define IRQ15_MCU_EN_SFT                               15
+#define IRQ14_MCU_EN_SFT                               14
+#define IRQ13_MCU_EN_SFT                               13
+#define IRQ12_MCU_EN_SFT                               12
+#define IRQ11_MCU_EN_SFT                               11
+#define IRQ10_MCU_EN_SFT                               10
+#define IRQ9_MCU_EN_SFT                                        9
+#define IRQ8_MCU_EN_SFT                                        8
+#define IRQ7_MCU_EN_SFT                                        7
+#define IRQ6_MCU_EN_SFT                                        6
+#define IRQ5_MCU_EN_SFT                                        5
+#define IRQ4_MCU_EN_SFT                                        4
+#define IRQ3_MCU_EN_SFT                                        3
+#define IRQ2_MCU_EN_SFT                                        2
+#define IRQ1_MCU_EN_SFT                                        1
+#define IRQ0_MCU_EN_SFT                                        0
+
+/* AFE_IRQ_MCU_SCP_EN */
+#define IRQ31_MCU_SCP_EN_SFT                           31
+#define IRQ30_MCU_SCP_EN_SFT                           30
+#define IRQ29_MCU_SCP_EN_SFT                           29
+#define IRQ28_MCU_SCP_EN_SFT                           28
+#define IRQ27_MCU_SCP_EN_SFT                           27
+#define IRQ26_MCU_SCP_EN_SFT                           26
+#define IRQ25_MCU_SCP_EN_SFT                           25
+#define IRQ24_MCU_SCP_EN_SFT                           24
+#define IRQ23_MCU_SCP_EN_SFT                           23
+#define IRQ22_MCU_SCP_EN_SFT                           22
+#define IRQ21_MCU_SCP_EN_SFT                           21
+#define IRQ20_MCU_SCP_EN_SFT                           20
+#define IRQ19_MCU_SCP_EN_SFT                           19
+#define IRQ18_MCU_SCP_EN_SFT                           18
+#define IRQ17_MCU_SCP_EN_SFT                           17
+#define IRQ16_MCU_SCP_EN_SFT                           16
+#define IRQ15_MCU_SCP_EN_SFT                           15
+#define IRQ14_MCU_SCP_EN_SFT                           14
+#define IRQ13_MCU_SCP_EN_SFT                           13
+#define IRQ12_MCU_SCP_EN_SFT                           12
+#define IRQ11_MCU_SCP_EN_SFT                           11
+#define IRQ10_MCU_SCP_EN_SFT                           10
+#define IRQ9_MCU_SCP_EN_SFT                            9
+#define IRQ8_MCU_SCP_EN_SFT                            8
+#define IRQ7_MCU_SCP_EN_SFT                            7
+#define IRQ6_MCU_SCP_EN_SFT                            6
+#define IRQ5_MCU_SCP_EN_SFT                            5
+#define IRQ4_MCU_SCP_EN_SFT                            4
+#define IRQ3_MCU_SCP_EN_SFT                            3
+#define IRQ2_MCU_SCP_EN_SFT                            2
+#define IRQ1_MCU_SCP_EN_SFT                            1
+#define IRQ0_MCU_SCP_EN_SFT                            0
+
+/* AFE_IRQ_MCU_DSP_EN */
+#define IRQ31_MCU_DSP_EN_SFT                           31
+#define IRQ30_MCU_DSP_EN_SFT                           30
+#define IRQ29_MCU_DSP_EN_SFT                           29
+#define IRQ28_MCU_DSP_EN_SFT                           28
+#define IRQ27_MCU_DSP_EN_SFT                           27
+#define IRQ26_MCU_DSP_EN_SFT                           26
+#define IRQ25_MCU_DSP_EN_SFT                           25
+#define IRQ24_MCU_DSP_EN_SFT                           24
+#define IRQ23_MCU_DSP_EN_SFT                           23
+#define IRQ22_MCU_DSP_EN_SFT                           22
+#define IRQ21_MCU_DSP_EN_SFT                           21
+#define IRQ20_MCU_DSP_EN_SFT                           20
+#define IRQ19_MCU_DSP_EN_SFT                           19
+#define IRQ18_MCU_DSP_EN_SFT                           18
+#define IRQ17_MCU_DSP_EN_SFT                           17
+#define IRQ16_MCU_DSP_EN_SFT                           16
+#define IRQ15_MCU_DSP_EN_SFT                           15
+#define IRQ14_MCU_DSP_EN_SFT                           14
+#define IRQ13_MCU_DSP_EN_SFT                           13
+#define IRQ12_MCU_DSP_EN_SFT                           12
+#define IRQ11_MCU_DSP_EN_SFT                           11
+#define IRQ10_MCU_DSP_EN_SFT                           10
+#define IRQ9_MCU_DSP_EN_SFT                            9
+#define IRQ8_MCU_DSP_EN_SFT                            8
+#define IRQ7_MCU_DSP_EN_SFT                            7
+#define IRQ6_MCU_DSP_EN_SFT                            6
+#define IRQ5_MCU_DSP_EN_SFT                            5
+#define IRQ4_MCU_DSP_EN_SFT                            4
+#define IRQ3_MCU_DSP_EN_SFT                            3
+#define IRQ2_MCU_DSP_EN_SFT                            2
+#define IRQ1_MCU_DSP_EN_SFT                            1
+#define IRQ0_MCU_DSP_EN_SFT                            0
+
+/* AFE_AUD_PAD_TOP */
+#define AUD_PAD_TOP_MON_SFT                            15
+#define AUD_PAD_TOP_MON_MASK_SFT                       GENMASK(31, 15)
+#define AUD_PAD_TOP_FIFO_RSP_SFT                       4
+#define AUD_PAD_TOP_FIFO_RSP_MASK_SFT                  GENMASK(7, 4)
+#define RG_RX_PROTOCOL2_SFT                            3
+#define RG_RX_PROTOCOL2_MASK_SFT                       BIT(3)
+#define RESERVDED_01_SFT                               1
+#define RESERVDED_01_MASK_SFT                          GENMASK(2, 1)
+#define RG_RX_FIFO_ON_SFT                              0
+#define RG_RX_FIFO_ON_MASK_SFT                         BIT(0)
+
+/* AFE_ADDA_MTKAIF_SYNCWORD_CFG */
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_SFT      23
+#define RG_ADDA6_MTKAIF_RX_SYNC_WORD2_DISABLE_MASK_SFT BIT(23)
+
+/* AFE_ADDA_MTKAIF_RX_CFG0 */
+#define MTKAIF_RXIF_VOICE_MODE_SFT                     20
+#define MTKAIF_RXIF_VOICE_MODE_MASK_SFT                        GENMASK(23, 20)
+#define MTKAIF_RXIF_DETECT_ON_SFT                      16
+#define MTKAIF_RXIF_DETECT_ON_MASK_SFT                 BIT(16)
+#define MTKAIF_RXIF_DATA_BIT_SFT                       8
+#define MTKAIF_RXIF_DATA_BIT_MASK_SFT                  GENMASK(10, 8)
+#define MTKAIF_RXIF_FIFO_RSP_SFT                       4
+#define MTKAIF_RXIF_FIFO_RSP_MASK_SFT                  GENMASK(6, 4)
+#define MTKAIF_RXIF_DATA_MODE_SFT                      0
+#define MTKAIF_RXIF_DATA_MODE_MASK_SFT                 BIT(0)
+
+/* GENERAL_ASRC_MODE */
+#define GENERAL2_ASRCOUT_MODE_SFT                      12
+#define GENERAL2_ASRCOUT_MODE_MASK                     0xf
+#define GENERAL2_ASRCOUT_MODE_MASK_SFT                 GENMASK(15, 12)
+#define GENERAL2_ASRCIN_MODE_SFT                       8
+#define GENERAL2_ASRCIN_MODE_MASK                      0xf
+#define GENERAL2_ASRCIN_MODE_MASK_SFT                  GENMASK(11, 8)
+#define GENERAL1_ASRCOUT_MODE_SFT                      4
+#define GENERAL1_ASRCOUT_MODE_MASK                     0xf
+#define GENERAL1_ASRCOUT_MODE_MASK_SFT                 GENMASK(7, 4)
+#define GENERAL1_ASRCIN_MODE_SFT                       0
+#define GENERAL1_ASRCIN_MODE_MASK                      0xf
+#define GENERAL1_ASRCIN_MODE_MASK_SFT                  GENMASK(3, 0)
+
+/* GENERAL_ASRC_EN_ON */
+#define GENERAL2_ASRC_EN_ON_SFT                                1
+#define GENERAL2_ASRC_EN_ON_MASK_SFT                   BIT(1)
+#define GENERAL1_ASRC_EN_ON_SFT                                0
+#define GENERAL1_ASRC_EN_ON_MASK_SFT                   BIT(0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON0 */
+#define G_SRC_CHSET_STR_CLR_SFT                                4
+#define G_SRC_CHSET_STR_CLR_MASK_SFT                   BIT(4)
+#define G_SRC_CHSET_ON_SFT                             2
+#define G_SRC_CHSET_ON_MASK_SFT                                BIT(2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT                      1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT                 BIT(1)
+#define G_SRC_ASM_ON_SFT                               0
+#define G_SRC_ASM_ON_MASK_SFT                          BIT(0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON3 */
+#define G_SRC_ASM_FREQ_4_SFT                           0
+#define G_SRC_ASM_FREQ_4_MASK_SFT                      GENMASK(23, 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON4 */
+#define G_SRC_ASM_FREQ_5_SFT                           0
+#define G_SRC_ASM_FREQ_5_MASK_SFT                      GENMASK(23, 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON13 */
+#define G_SRC_COEFF_SRAM_ADR_SFT                       0
+#define G_SRC_COEFF_SRAM_ADR_MASK_SFT                  GENMASK(5, 0)
+
+/* AFE_GENERAL1_ASRC_2CH_CON2 */
+#define G_SRC_CHSET_O16BIT_SFT                         19
+#define G_SRC_CHSET_O16BIT_MASK_SFT                    BIT(19)
+#define G_SRC_CHSET_CLR_IIR_HISTORY_SFT                        17
+#define G_SRC_CHSET_CLR_IIR_HISTORY_MASK_SFT           BIT(17)
+#define G_SRC_CHSET_IS_MONO_SFT                                16
+#define G_SRC_CHSET_IS_MONO_MASK_SFT                   BIT(16)
+#define G_SRC_CHSET_IIR_EN_SFT                         11
+#define G_SRC_CHSET_IIR_EN_MASK_SFT                    BIT(11)
+#define G_SRC_CHSET_IIR_STAGE_SFT                      8
+#define G_SRC_CHSET_IIR_STAGE_MASK_SFT                 GENMASK(10, 8)
+#define G_SRC_CHSET_STR_CLR_RU_SFT                     5
+#define G_SRC_CHSET_STR_CLR_RU_MASK_SFT                        BIT(5)
+#define G_SRC_CHSET_ON_SFT                             2
+#define G_SRC_CHSET_ON_MASK_SFT                                BIT(2)
+#define G_SRC_COEFF_SRAM_CTRL_SFT                      1
+#define G_SRC_COEFF_SRAM_CTRL_MASK_SFT                 BIT(1)
+#define G_SRC_ASM_ON_SFT                               0
+#define G_SRC_ASM_ON_MASK_SFT                          BIT(0)
+
+/* AFE_ADDA_DL_SDM_DITHER_CON */
+#define AFE_DL_SDM_DITHER_64TAP_EN_SFT                 20
+#define AFE_DL_SDM_DITHER_64TAP_EN_MASK_SFT            BIT(20)
+#define AFE_DL_SDM_DITHER_EN_SFT                       16
+#define AFE_DL_SDM_DITHER_EN_MASK_SFT                  BIT(16)
+#define AFE_DL_SDM_DITHER_GAIN_SFT                     0
+#define AFE_DL_SDM_DITHER_GAIN_MASK_SFT                        GENMASK(7, 0)
+
+/* AFE_ADDA_DL_SDM_AUTO_RESET_CON */
+#define SDM_AUTO_RESET_TEST_ON_SFT                     31
+#define SDM_AUTO_RESET_TEST_ON_MASK_SFT                        BIT(31)
+#define AFE_DL_USE_NEW_2ND_SDM_SFT                     28
+#define AFE_DL_USE_NEW_2ND_SDM_MASK_SFT                        BIT(28)
+#define SDM_AUTO_RESET_COUNT_TH_SFT                    0
+#define SDM_AUTO_RESET_COUNT_TH_MASK_SFT               GENMASK(23, 0)
+
+/* AFE_ASRC_2CH_CON0 */
+#define CON0_CHSET_STR_CLR_SFT                         4
+#define CON0_CHSET_STR_CLR_MASK_SFT                    BIT(4)
+#define CON0_ASM_ON_SFT                                        0
+#define CON0_ASM_ON_MASK_SFT                           BIT(0)
+
+/* AFE_ASRC_2CH_CON5 */
+#define CALI_EN_SFT                                    0
+#define CALI_EN_MASK_SFT                               BIT(0)
+
+/* FPGA_CFG4 */
+#define IRQ_COUNTER_SFT                                        3
+#define IRQ_COUNTER_MASK_SFT                           GENMASK(31, 3)
+#define IRQ_CLK_COUNTER_CLEAN_SFT                      2
+#define IRQ_CLK_COUNTER_CLEAN_MASK_SFT                 BIT(2)
+#define IRQ_CLK_COUNTER_PAUSE_SFT                      1
+#define IRQ_CLK_COUNTER_PAUSE_MASK_SFT                 BIT(1)
+#define IRQ_CLK_COUNTER_ON_SFT                         0
+#define IRQ_CLK_COUNTER_ON_MASK_SFT                    BIT(0)
+
+/* FPGA_CFG5 */
+#define WR_MSTR_ON_SFT                                 16
+#define WR_MSTR_ON_MASK_SFT                            GENMASK(28, 16)
+#define WR_AG_SEL_SFT                                  0
+#define WR_AG_SEL_MASK_SFT                             GENMASK(12, 0)
+
+/* FPGA_CFG6 */
+#define WR_MSTR_REQ_REAL_SFT                           16
+#define WR_MSTR_REQ_REAL_MASK_SFT                      GENMASK(28, 16)
+#define WR_MSTR_REQ_IN_SFT                             0
+#define WR_MSTR_REQ_IN_MASK_SFT                                GENMASK(12, 0)
+
+/* FPGA_CFG7 */
+#define MEM1_WDATA_MON0_SFT                            0
+#define MEM1_WDATA_MON0_MASK_SFT                       GENMASK(31, 0)
+
+/* FPGA_CFG8 */
+#define MEM1_WDATA_MON1_SFT                            0
+#define MEM1_WDATA_MON1_MASK_SFT                       GENMASK(31, 0)
+
+/* FPGA_CFG9 */
+#define MEM_WE_SFT                                     31
+#define MEM_WE_MASK_SFT                                        BIT(31)
+#define AFE_HREADY_SFT                                 30
+#define AFE_HREADY_MASK_SFT                            BIT(30)
+#define MEM_WR_REQ_SFT                                 29
+#define MEM_WR_REQ_MASK_SFT                            BIT(29)
+#define WR_AG_REG_MON_SFT                              16
+#define WR_AG_REG_MON_MASK_SFT                         GENMASK(28, 16)
+#define HCLK_CK_SFT                                    15
+#define HCLK_CK_MASK_SFT                               BIT(15)
+#define MEM_RD_REQ_SFT                                 14
+#define MEM_RD_REQ_MASK_SFT                            BIT(14)
+#define RD_AG_REQ_MON_SFT                              0
+#define RD_AG_REQ_MON_MASK_SFT                         GENMASK(13, 0)
+
+/* FPGA_CFG10 */
+#define MEM_BYTE_0_SFT                                 0
+#define MEM_BYTE_0_MASK_SFT                            GENMASK(31, 0)
+
+/* FPGA_CFG11 */
+#define MEM_BYTE_1_SFT                                 0
+#define MEM_BYTE_1_MASK_SFT                            GENMASK(31, 0)
+
+/* FPGA_CFG12 */
+#define RDATA_CNT_SFT                                  30
+#define RDATA_CNT_MASK_SFT                             GENMASK(31, 30)
+#define MS2_HREADY_SFT                                 29
+#define MS2_HREADY_MASK_SFT                            BIT(29)
+#define MS1_HREADY_SFT                                 28
+#define MS1_HREADY_MASK_SFT                            BIT(28)
+#define AG_SEL_SFT                                     0
+#define AG_SEL_MASK_SFT                                        GENMASK(25, 0)
+
+/* FPGA_CFG13 */
+#define AFE_ST_SFT                                     27
+#define AFE_ST_MASK_SFT                                        GENMASK(31, 27)
+#define AG_IN_SERVICE_SFT                              0
+#define AG_IN_SERVICE_MASK_SFT                         GENMASK(25, 0)
+
+/* ETDM_IN1_CON0 */
+#define ETDM_IN1_CON0_REG_ETDM_IN_EN_SFT                       0
+#define ETDM_IN1_CON0_REG_ETDM_IN_EN_MASK_SFT                  BIT(0)
+#define ETDM_IN1_CON0_REG_SYNC_MODE_SFT                                1
+#define ETDM_IN1_CON0_REG_SYNC_MODE_MASK_SFT                   BIT(1)
+#define ETDM_IN1_CON0_REG_LSB_FIRST_SFT                                3
+#define ETDM_IN1_CON0_REG_LSB_FIRST_MASK_SFT                   BIT(3)
+#define ETDM_IN1_CON0_REG_SOFT_RST_SFT                         4
+#define ETDM_IN1_CON0_REG_SOFT_RST_MASK_SFT                    BIT(4)
+#define ETDM_IN1_CON0_REG_SLAVE_MODE_SFT                       5
+#define ETDM_IN1_CON0_REG_SLAVE_MODE_MASK_SFT                  BIT(5)
+#define ETDM_IN1_CON0_REG_FMT_SFT                              6
+#define ETDM_IN1_CON0_REG_FMT_MASK_SFT                         GENMASK(8, 6)
+#define ETDM_IN1_CON0_REG_LRCK_EDGE_SEL_SFT                    10
+#define ETDM_IN1_CON0_REG_LRCK_EDGE_SEL_MASK_SFT               BIT(10)
+#define ETDM_IN1_CON0_REG_BIT_LENGTH_SFT                       11
+#define ETDM_IN1_CON0_REG_BIT_LENGTH_MASK_SFT                  GENMASK(15, 11)
+#define ETDM_IN1_CON0_REG_WORD_LENGTH_SFT                      16
+#define ETDM_IN1_CON0_REG_WORD_LENGTH_MASK_SFT                 GENMASK(20, 16)
+#define ETDM_IN1_CON0_REG_CH_NUM_SFT                           23
+#define ETDM_IN1_CON0_REG_CH_NUM_MASK_SFT                      GENMASK(27, 23)
+#define ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_SFT         28
+#define ETDM_IN1_CON0_REG_RELATCH_1X_EN_SEL_DOMAIN_MASK_SFT    GENMASK(31, 28)
+#define ETDM_IN1_CON0_REG_VALID_TOGETHER_SFT                   31
+#define ETDM_IN1_CON0_REG_VALID_TOGETHER_MASK_SFT              BIT(31)
+#define ETDM_IN_CON0_CTRL_MASK                                 0x1f9ff9e2
+
+/* ETDM_IN1_CON1 */
+#define ETDM_IN1_CON1_REG_INITIAL_COUNT_SFT                    0
+#define ETDM_IN1_CON1_REG_INITIAL_COUNT_MASK_SFT               GENMASK(4, 0)
+#define ETDM_IN1_CON1_REG_INITIAL_POINT_SFT                    5
+#define ETDM_IN1_CON1_REG_INITIAL_POINT_MASK_SFT               GENMASK(9, 5)
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_OFF_SFT                    10
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_OFF_MASK_SFT               BIT(10)
+#define ETDM_IN1_CON1_REG_BCK_AUTO_OFF_SFT                     11
+#define ETDM_IN1_CON1_REG_BCK_AUTO_OFF_MASK_SFT                        BIT(11)
+#define ETDM_IN1_CON1_REG_INITIAL_LRCK_SFT                     13
+#define ETDM_IN1_CON1_REG_INITIAL_LRCK_MASK_SFT                        BIT(13)
+#define ETDM_IN1_CON1_REG_LRCK_RESET_SFT                       15
+#define ETDM_IN1_CON1_REG_LRCK_RESET_MASK_SFT                  BIT(15)
+#define ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_SFT                  16
+#define ETDM_IN1_CON1_PINMUX_MCLK_CTRL_OE_MASK_SFT             BIT(16)
+#define ETDM_IN1_CON1_REG_OUTPUT_CR_EN_SFT                     18
+#define ETDM_IN1_CON1_REG_OUTPUT_CR_EN_MASK_SFT                        BIT(18)
+#define ETDM_IN1_CON1_REG_LR_ALIGN_SFT                         19
+#define ETDM_IN1_CON1_REG_LR_ALIGN_MASK_SFT                    BIT(19)
+#define ETDM_IN1_CON1_REG_LRCK_WIDTH_SFT                       20
+#define ETDM_IN1_CON1_REG_LRCK_WIDTH_MASK_SFT                  GENMASK(29, 20)
+#define ETDM_IN1_CON1_REG_DIRECT_INPUT_MASTER_BCK_SFT          30
+#define ETDM_IN1_CON1_REG_DIRECT_INPUT_MASTER_BCK_MASK_SFT     BIT(30)
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_SFT                   31
+#define ETDM_IN1_CON1_REG_LRCK_AUTO_MODE_MASK_SFT              BIT(31)
+#define ETDM_IN_CON1_CTRL_MASK                                 0xbff10000
+
+/* ETDM_IN1_CON2 */
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_SFT                     0
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_MASK_SFT                        GENMASK(4, 0)
+#define ETDM_IN1_CON2_REG_UPDATE_GAP_SFT                       5
+#define ETDM_IN1_CON2_REG_UPDATE_GAP_MASK_SFT                  GENMASK(9, 5)
+#define ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_SFT                 10
+#define ETDM_IN1_CON2_REG_CLOCK_SOURCE_SEL_MASK_SFT            GENMASK(12, 10)
+#define ETDM_IN1_CON2_REG_AGENT_USE_ETDM_BCK_SFT               13
+#define ETDM_IN1_CON2_REG_AGENT_USE_ETDM_BCK_MASK_SFT          BIT(13)
+#define ETDM_IN1_CON2_REG_CK_EN_SEL_AUTO_SFT                   14
+#define ETDM_IN1_CON2_REG_CK_EN_SEL_AUTO_MASK_SFT              BIT(14)
+#define ETDM_IN1_CON2_REG_MULTI_IP_ONE_DATA_CH_NUM_SFT         15
+#define ETDM_IN1_CON2_REG_MULTI_IP_ONE_DATA_CH_NUM_MASK_SFT    GENMASK(19, 15)
+#define ETDM_IN1_CON2_REG_MASK_AUTO_SFT                                20
+#define ETDM_IN1_CON2_REG_MASK_AUTO_MASK_SFT                   BIT(20)
+#define ETDM_IN1_CON2_REG_MASK_NUM_SFT                         21
+#define ETDM_IN1_CON2_REG_MASK_NUM_MASK_SFT                    GENMASK(25, 21)
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_AUTO_SFT                        26
+#define ETDM_IN1_CON2_REG_UPDATE_POINT_AUTO_MASK_SFT           BIT(26)
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_0P5T_EN_SFT              27
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_0P5T_EN_MASK_SFT         BIT(27)
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_BCK_INV_SFT              28
+#define ETDM_IN1_CON2_REG_SDATA_DELAY_BCK_INV_MASK_SFT         BIT(28)
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_0P5T_EN_SFT               29
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_0P5T_EN_MASK_SFT          BIT(29)
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_BCK_INV_SFT               30
+#define ETDM_IN1_CON2_REG_LRCK_DELAY_BCK_INV_MASK_SFT          BIT(30)
+#define ETDM_IN1_CON2_REG_MULTI_IP_MODE_SFT                    31
+#define ETDM_IN1_CON2_REG_MULTI_IP_MODE_MASK_SFT               BIT(31)
+#define ETDM_IN_CON2_CTRL_MASK                                 0x800f8000
+#define ETDM_IN_CON2_MULTI_IP_CH(x)                            (((x) - 1) << 15)
+#define ETDM_IN_CON2_MULTI_IP_2CH_MODE                         BIT(31)
+
+/* ETDM_IN1_CON3 */
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_0_SFT                    0
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_0_MASK_SFT               BIT(0)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_1_SFT                    1
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_1_MASK_SFT               BIT(1)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_2_SFT                    2
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_2_MASK_SFT               BIT(2)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_3_SFT                    3
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_3_MASK_SFT               BIT(3)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_4_SFT                    4
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_4_MASK_SFT               BIT(4)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_5_SFT                    5
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_5_MASK_SFT               BIT(5)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_6_SFT                    6
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_6_MASK_SFT               BIT(6)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_7_SFT                    7
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_7_MASK_SFT               BIT(7)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_8_SFT                    8
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_8_MASK_SFT               BIT(8)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_9_SFT                    9
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_9_MASK_SFT               BIT(9)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_10_SFT                   10
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_10_MASK_SFT              BIT(10)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_11_SFT                   11
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_11_MASK_SFT              BIT(11)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_12_SFT                   12
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_12_MASK_SFT              BIT(12)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_13_SFT                   13
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_13_MASK_SFT              BIT(13)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_14_SFT                   14
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_14_MASK_SFT              BIT(14)
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_15_SFT                   15
+#define ETDM_IN1_CON3_REG_DISABLE_OUT_15_MASK_SFT              BIT(15)
+#define ETDM_IN1_CON3_REG_RJ_DATA_RIGHT_ALIGN_SFT              16
+#define ETDM_IN1_CON3_REG_RJ_DATA_RIGHT_ALIGN_MASK_SFT         BIT(16)
+#define ETDM_IN1_CON3_REG_MONITOR_SEL_SFT                      17
+#define ETDM_IN1_CON3_REG_MONITOR_SEL_MASK_SFT                 GENMASK(18, 17)
+#define ETDM_IN1_CON3_REG_CNT_UPPER_LIMIT_SFT                  19
+#define ETDM_IN1_CON3_REG_CNT_UPPER_LIMIT_MASK_SFT             GENMASK(24, 19)
+#define ETDM_IN1_CON3_REG_COMPACT_SAMPLE_END_DIS_SFT           25
+#define ETDM_IN1_CON3_REG_COMPACT_SAMPLE_END_DIS_MASK_SFT      BIT(25)
+#define ETDM_IN1_CON3_REG_FS_TIMING_SEL_SFT                    26
+#define ETDM_IN1_CON3_REG_FS_TIMING_SEL_MASK_SFT               GENMASK(30, 26)
+#define ETDM_IN1_CON3_REG_SAMPLE_END_MODE_SFT                  31
+#define ETDM_IN1_CON3_REG_SAMPLE_END_MODE_MASK_SFT             BIT(31)
+#define ETDM_IN_CON3_CTRL_MASK                                 (0x7c000000)
+#define ETDM_IN_CON3_FS(x)                                     (((x) & 0x1f) << 26)
+
+/* ETDM_IN1_CON4 */
+#define ETDM_IN1_CON4_REG_DSD_MODE_SFT                         0
+#define ETDM_IN1_CON4_REG_DSD_MODE_MASK_SFT                    GENMASK(5, 0)
+#define ETDM_IN1_CON4_REG_DSD_REPACK_AUTO_MODE_SFT             8
+#define ETDM_IN1_CON4_REG_DSD_REPACK_AUTO_MODE_MASK_SFT                BIT(8)
+#define ETDM_IN1_CON4_REG_REPACK_WORD_LENGTH_SFT               9
+#define ETDM_IN1_CON4_REG_REPACK_WORD_LENGTH_MASK_SFT          GENMASK(10, 9)
+#define ETDM_IN1_CON4_REG_ASYNC_RESET_SFT                      11
+#define ETDM_IN1_CON4_REG_ASYNC_RESET_MASK_SFT                 BIT(11)
+#define ETDM_IN1_CON4_REG_DSD_CHNUM_SFT                                12
+#define ETDM_IN1_CON4_REG_DSD_CHNUM_MASK_SFT                   GENMASK(15, 12)
+#define ETDM_IN1_CON4_REG_SLAVE_BCK_INV_SFT                    16
+#define ETDM_IN1_CON4_REG_SLAVE_BCK_INV_MASK_SFT               BIT(16)
+#define ETDM_IN1_CON4_REG_SLAVE_LRCK_INV_SFT                   17
+#define ETDM_IN1_CON4_REG_SLAVE_LRCK_INV_MASK_SFT              BIT(17)
+#define ETDM_IN1_CON4_REG_MASTER_BCK_INV_SFT                   18
+#define ETDM_IN1_CON4_REG_MASTER_BCK_INV_MASK_SFT              BIT(18)
+#define ETDM_IN1_CON4_REG_MASTER_LRCK_INV_SFT                  19
+#define ETDM_IN1_CON4_REG_MASTER_LRCK_INV_MASK_SFT             BIT(19)
+#define ETDM_IN1_CON4_REG_RELATCH_1X_EN_SEL_SFT                        20
+#define ETDM_IN1_CON4_REG_RELATCH_1X_EN_SEL_MASK_SFT           GENMASK(24, 20)
+#define ETDM_IN1_CON4_REG_SAMPLE_END_POINT_SFT                 25
+#define ETDM_IN1_CON4_REG_SAMPLE_END_POINT_MASK_SFT            GENMASK(29, 25)
+#define ETDM_IN1_CON4_REG_WAIT_LAST_SAMPLE_SFT                 30
+#define ETDM_IN1_CON4_REG_WAIT_LAST_SAMPLE_MASK_SFT            BIT(30)
+#define ETDM_IN1_CON4_REG_MASTER_BCK_FORCE_ON_SFT              31
+#define ETDM_IN1_CON4_REG_MASTER_BCK_FORCE_ON_MASK_SFT         BIT(31)
+#define ETDM_IN_CON4_CTRL_MASK                                 0x1ff0000
+#define ETDM_IN_CON4_FS(x)                                     (((x) & 0x1f) << 20)
+#define ETDM_IN_CON4_CON0_MASTER_LRCK_INV                      BIT(19)
+#define ETDM_IN_CON4_CON0_MASTER_BCK_INV                       BIT(18)
+#define ETDM_IN_CON4_CON0_SLAVE_LRCK_INV                       BIT(17)
+#define ETDM_IN_CON4_CON0_SLAVE_BCK_INV                                BIT(16)
+
+/* ETDM_IN1_CON5 */
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_0_SFT                    0
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_0_MASK_SFT               BIT(0)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_1_SFT                    1
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_1_MASK_SFT               BIT(1)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_2_SFT                    2
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_2_MASK_SFT               BIT(2)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_3_SFT                    3
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_3_MASK_SFT               BIT(3)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_4_SFT                    4
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_4_MASK_SFT               BIT(4)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_5_SFT                    5
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_5_MASK_SFT               BIT(5)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_6_SFT                    6
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_6_MASK_SFT               BIT(6)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_7_SFT                    7
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_7_MASK_SFT               BIT(7)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_8_SFT                    8
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_8_MASK_SFT               BIT(8)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_9_SFT                    9
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_9_MASK_SFT               BIT(9)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_10_SFT                   10
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_10_MASK_SFT              BIT(10)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_11_SFT                   11
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_11_MASK_SFT              BIT(11)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_12_SFT                   12
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_12_MASK_SFT              BIT(12)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_13_SFT                   13
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_13_MASK_SFT              BIT(13)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_14_SFT                   14
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_14_MASK_SFT              BIT(14)
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_15_SFT                   15
+#define ETDM_IN1_CON5_REG_ODD_FLAG_EN_15_MASK_SFT              BIT(15)
+#define ETDM_IN1_CON5_REG_LR_SWAP_0_SFT                                16
+#define ETDM_IN1_CON5_REG_LR_SWAP_0_MASK_SFT                   BIT(16)
+#define ETDM_IN1_CON5_REG_LR_SWAP_1_SFT                                17
+#define ETDM_IN1_CON5_REG_LR_SWAP_1_MASK_SFT                   BIT(17)
+#define ETDM_IN1_CON5_REG_LR_SWAP_2_SFT                                18
+#define ETDM_IN1_CON5_REG_LR_SWAP_2_MASK_SFT                   BIT(18)
+#define ETDM_IN1_CON5_REG_LR_SWAP_3_SFT                                19
+#define ETDM_IN1_CON5_REG_LR_SWAP_3_MASK_SFT                   BIT(19)
+#define ETDM_IN1_CON5_REG_LR_SWAP_4_SFT                                20
+#define ETDM_IN1_CON5_REG_LR_SWAP_4_MASK_SFT                   BIT(20)
+#define ETDM_IN1_CON5_REG_LR_SWAP_5_SFT                                21
+#define ETDM_IN1_CON5_REG_LR_SWAP_5_MASK_SFT                   BIT(21)
+#define ETDM_IN1_CON5_REG_LR_SWAP_6_SFT                                22
+#define ETDM_IN1_CON5_REG_LR_SWAP_6_MASK_SFT                   BIT(22)
+#define ETDM_IN1_CON5_REG_LR_SWAP_7_SFT                                23
+#define ETDM_IN1_CON5_REG_LR_SWAP_7_MASK_SFT                   BIT(23)
+#define ETDM_IN1_CON5_REG_LR_SWAP_8_SFT                                24
+#define ETDM_IN1_CON5_REG_LR_SWAP_8_MASK_SFT                   BIT(24)
+#define ETDM_IN1_CON5_REG_LR_SWAP_9_SFT                                25
+#define ETDM_IN1_CON5_REG_LR_SWAP_9_MASK_SFT                   BIT(25)
+#define ETDM_IN1_CON5_REG_LR_SWAP_10_SFT                       26
+#define ETDM_IN1_CON5_REG_LR_SWAP_10_MASK_SFT                  BIT(26)
+#define ETDM_IN1_CON5_REG_LR_SWAP_11_SFT                       27
+#define ETDM_IN1_CON5_REG_LR_SWAP_11_MASK_SFT                  BIT(27)
+#define ETDM_IN1_CON5_REG_LR_SWAP_12_SFT                       28
+#define ETDM_IN1_CON5_REG_LR_SWAP_12_MASK_SFT                  BIT(28)
+#define ETDM_IN1_CON5_REG_LR_SWAP_13_SFT                       29
+#define ETDM_IN1_CON5_REG_LR_SWAP_13_MASK_SFT                  BIT(29)
+#define ETDM_IN1_CON5_REG_LR_SWAP_14_SFT                       30
+#define ETDM_IN1_CON5_REG_LR_SWAP_14_MASK_SFT                  BIT(30)
+#define ETDM_IN1_CON5_REG_LR_SWAP_15_SFT                       31
+#define ETDM_IN1_CON5_REG_LR_SWAP_15_MASK_SFT                  BIT(31)
+
+/* ETDM_IN1_CON6 */
+#define ETDM_IN1_CON6_LCH_DATA_REG_SFT                         0
+#define ETDM_IN1_CON6_LCH_DATA_REG_MASK_SFT                    GENMASK(31, 0)
+
+/* ETDM_IN1_CON7 */
+#define ETDM_IN1_CON7_RCH_DATA_REG_SFT                         0
+#define ETDM_IN1_CON7_RCH_DATA_REG_MASK_SFT                    GENMASK(31, 0)
+
+/* ETDM_IN1_CON8 */
+#define ETDM_IN1_CON8_REG_AFIFO_THRESHOLD_SFT                  29
+#define ETDM_IN1_CON8_REG_AFIFO_THRESHOLD_MASK_SFT             GENMASK(30, 29)
+#define ETDM_IN1_CON8_REG_CK_EN_SEL_MANUAL_SFT                 16
+#define ETDM_IN1_CON8_REG_CK_EN_SEL_MANUAL_MASK_SFT            GENMASK(25, 16)
+#define ETDM_IN1_CON8_REG_AFIFO_SW_RESET_SFT                   15
+#define ETDM_IN1_CON8_REG_AFIFO_SW_RESET_MASK_SFT              BIT(15)
+#define ETDM_IN1_CON8_REG_AFIFO_RESET_SEL_SFT                  14
+#define ETDM_IN1_CON8_REG_AFIFO_RESET_SEL_MASK_SFT             BIT(14)
+#define ETDM_IN1_CON8_REG_AFIFO_AUTO_RESET_DIS_SFT             9
+#define ETDM_IN1_CON8_REG_AFIFO_AUTO_RESET_DIS_MASK_SFT                BIT(9)
+#define ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_SFT                   8
+#define ETDM_IN1_CON8_REG_ETDM_USE_AFIFO_MASK_SFT              BIT(8)
+#define ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_SFT           5
+#define ETDM_IN1_CON8_REG_AFIFO_CLOCK_DOMAIN_SEL_MASK_SFT      GENMASK(7, 5)
+#define ETDM_IN1_CON8_REG_AFIFO_MODE_SFT                       0
+#define ETDM_IN1_CON8_REG_AFIFO_MODE_MASK_SFT                  GENMASK(4, 0)
+#define ETDM_IN_CON8_FS(x)                                     (((x) & 0x1f) << 0)
+#define ETDM_IN_CON8_CTRL_MASK                                 0x13f
+
+#define AUDIO_TOP_CON0                                 0x0000
+#define AUDIO_TOP_CON1                                 0x0004
+#define AUDIO_TOP_CON2                                 0x0008
+#define AUDIO_TOP_CON3                                 0x000c
+#define AFE_DAC_CON0                                   0x0010
+#define AFE_I2S_CON                                    0x0018
+#define AFE_CONN0                                      0x0020
+#define AFE_CONN1                                      0x0024
+#define AFE_CONN2                                      0x0028
+#define AFE_CONN3                                      0x002c
+#define AFE_CONN4                                      0x0030
+#define AFE_I2S_CON1                                   0x0034
+#define AFE_I2S_CON2                                   0x0038
+#define AFE_I2S_CON3                                   0x0040
+#define AFE_CONN5                                      0x0044
+#define AFE_CONN_24BIT                                 0x0048
+#define AFE_DL1_CON0                                   0x004c
+#define AFE_DL1_BASE_MSB                               0x0050
+#define AFE_DL1_BASE                                   0x0054
+#define AFE_DL1_CUR_MSB                                        0x0058
+#define AFE_DL1_CUR                                    0x005c
+#define AFE_DL1_END_MSB                                        0x0060
+#define AFE_DL1_END                                    0x0064
+#define AFE_DL2_CON0                                   0x0068
+#define AFE_DL2_BASE_MSB                               0x006c
+#define AFE_DL2_BASE                                   0x0070
+#define AFE_DL2_CUR_MSB                                        0x0074
+#define AFE_DL2_CUR                                    0x0078
+#define AFE_DL2_END_MSB                                        0x007c
+#define AFE_DL2_END                                    0x0080
+#define AFE_DL3_CON0                                   0x0084
+#define AFE_DL3_BASE_MSB                               0x0088
+#define AFE_DL3_BASE                                   0x008c
+#define AFE_DL3_CUR_MSB                                        0x0090
+#define AFE_DL3_CUR                                    0x0094
+#define AFE_DL3_END_MSB                                        0x0098
+#define AFE_DL3_END                                    0x009c
+#define AFE_CONN6                                      0x00bc
+#define AFE_DL4_CON0                                   0x00cc
+#define AFE_DL4_BASE_MSB                               0x00d0
+#define AFE_DL4_BASE                                   0x00d4
+#define AFE_DL4_CUR_MSB                                        0x00d8
+#define AFE_DL4_CUR                                    0x00dc
+#define AFE_DL4_END_MSB                                        0x00e0
+#define AFE_DL4_END                                    0x00e4
+#define AFE_DL12_CON0                                  0x00e8
+#define AFE_DL12_BASE_MSB                              0x00ec
+#define AFE_DL12_BASE                                  0x00f0
+#define AFE_DL12_CUR_MSB                               0x00f4
+#define AFE_DL12_CUR                                   0x00f8
+#define AFE_DL12_END_MSB                               0x00fc
+#define AFE_DL12_END                                   0x0100
+#define AFE_ADDA_DL_SRC2_CON0                          0x0108
+#define AFE_ADDA_DL_SRC2_CON1                          0x010c
+#define AFE_ADDA_UL_SRC_CON0                           0x0114
+#define AFE_ADDA_UL_SRC_CON1                           0x0118
+#define AFE_ADDA_TOP_CON0                              0x0120
+#define AFE_ADDA_UL_DL_CON0                            0x0124
+#define AFE_ADDA_SRC_DEBUG                             0x012c
+#define AFE_ADDA_SRC_DEBUG_MON0                                0x0130
+#define AFE_ADDA_SRC_DEBUG_MON1                                0x0134
+#define AFE_ADDA_UL_SRC_MON0                           0x0148
+#define AFE_ADDA_UL_SRC_MON1                           0x014c
+#define AFE_SECURE_CON0                                        0x0150
+#define AFE_SRAM_BOUND                                 0x0154
+#define AFE_SECURE_CON1                                        0x0158
+#define AFE_SECURE_CONN0                               0x015c
+#define AFE_VUL_CON0                                   0x0170
+#define AFE_VUL_BASE_MSB                               0x0174
+#define AFE_VUL_BASE                                   0x0178
+#define AFE_VUL_CUR_MSB                                        0x017c
+#define AFE_VUL_CUR                                    0x0180
+#define AFE_VUL_END_MSB                                        0x0184
+#define AFE_VUL_END                                    0x0188
+#define AFE_SIDETONE_DEBUG                             0x01d0
+#define AFE_SIDETONE_MON                               0x01d4
+#define AFE_SINEGEN_CON2                               0x01dc
+#define AFE_SIDETONE_CON0                              0x01e0
+#define AFE_SIDETONE_COEFF                             0x01e4
+#define AFE_SIDETONE_CON1                              0x01e8
+#define AFE_SIDETONE_GAIN                              0x01ec
+#define AFE_SINEGEN_CON0                               0x01f0
+#define AFE_TOP_CON0                                   0x0200
+#define AFE_VUL2_CON0                                  0x020c
+#define AFE_VUL2_BASE_MSB                              0x0210
+#define AFE_VUL2_BASE                                  0x0214
+#define AFE_VUL2_CUR_MSB                               0x0218
+#define AFE_VUL2_CUR                                   0x021c
+#define AFE_VUL2_END_MSB                               0x0220
+#define AFE_VUL2_END                                   0x0224
+#define AFE_VUL3_CON0                                  0x0228
+#define AFE_VUL3_BASE_MSB                              0x022c
+#define AFE_VUL3_BASE                                  0x0230
+#define AFE_VUL3_CUR_MSB                               0x0234
+#define AFE_VUL3_CUR                                   0x0238
+#define AFE_VUL3_END_MSB                               0x023c
+#define AFE_VUL3_END                                   0x0240
+#define AFE_BUSY                                       0x0244
+#define AFE_BUS_CFG                                    0x0250
+#define AFE_ADDA_PREDIS_CON0                           0x0260
+#define AFE_ADDA_PREDIS_CON1                           0x0264
+#define AFE_I2S_MON                                    0x027c
+#define AFE_ADDA_IIR_COEF_02_01                                0x0290
+#define AFE_ADDA_IIR_COEF_04_03                                0x0294
+#define AFE_ADDA_IIR_COEF_06_05                                0x0298
+#define AFE_ADDA_IIR_COEF_08_07                                0x029c
+#define AFE_ADDA_IIR_COEF_10_09                                0x02a0
+#define AFE_IRQ_MCU_CON1                               0x02e4
+#define AFE_IRQ_MCU_CON2                               0x02e8
+#define AFE_DAC_MON                                    0x02ec
+#define AFE_IRQ_MCU_CON3                               0x02f0
+#define AFE_IRQ_MCU_CON4                               0x02f4
+#define AFE_IRQ_MCU_CNT0                               0x0300
+#define AFE_IRQ_MCU_CNT6                               0x0304
+#define AFE_IRQ_MCU_CNT8                               0x0308
+#define AFE_IRQ_MCU_DSP2_EN                            0x030c
+#define AFE_IRQ0_MCU_CNT_MON                           0x0310
+#define AFE_IRQ6_MCU_CNT_MON                           0x0314
+#define AFE_VUL4_CON0                                  0x0358
+#define AFE_VUL4_BASE_MSB                              0x035c
+#define AFE_VUL4_BASE                                  0x0360
+#define AFE_VUL4_CUR_MSB                               0x0364
+#define AFE_VUL4_CUR                                   0x0368
+#define AFE_VUL4_END_MSB                               0x036c
+#define AFE_VUL4_END                                   0x0370
+#define AFE_VUL12_CON0                                 0x0374
+#define AFE_VUL12_BASE_MSB                             0x0378
+#define AFE_VUL12_BASE                                 0x037c
+#define AFE_VUL12_CUR_MSB                              0x0380
+#define AFE_VUL12_CUR                                  0x0384
+#define AFE_VUL12_END_MSB                              0x0388
+#define AFE_VUL12_END                                  0x038c
+#define AFE_IRQ3_MCU_CNT_MON                           0x0398
+#define AFE_IRQ4_MCU_CNT_MON                           0x039c
+#define AFE_IRQ_MCU_CON0                               0x03a0
+#define AFE_IRQ_MCU_STATUS                             0x03a4
+#define AFE_IRQ_MCU_CLR                                        0x03a8
+#define AFE_IRQ_MCU_CNT1                               0x03ac
+#define AFE_IRQ_MCU_CNT2                               0x03b0
+#define AFE_IRQ_MCU_EN                                 0x03b4
+#define AFE_IRQ_MCU_MON2                               0x03b8
+#define AFE_IRQ_MCU_CNT5                               0x03bc
+#define AFE_IRQ1_MCU_CNT_MON                           0x03c0
+#define AFE_IRQ2_MCU_CNT_MON                           0x03c4
+#define AFE_IRQ5_MCU_CNT_MON                           0x03cc
+#define AFE_IRQ_MCU_DSP_EN                             0x03d0
+#define AFE_IRQ_MCU_SCP_EN                             0x03d4
+#define AFE_IRQ_MCU_CNT7                               0x03dc
+#define AFE_IRQ7_MCU_CNT_MON                           0x03e0
+#define AFE_IRQ_MCU_CNT3                               0x03e4
+#define AFE_IRQ_MCU_CNT4                               0x03e8
+#define AFE_IRQ_MCU_CNT11                              0x03ec
+#define AFE_APLL1_TUNER_CFG                            0x03f0
+#define AFE_APLL2_TUNER_CFG                            0x03f4
+#define AFE_IRQ_MCU_MISS_CLR                           0x03f8
+#define AFE_CONN33                                     0x0408
+#define AFE_IRQ_MCU_CNT12                              0x040c
+#define AFE_GAIN1_CON0                                 0x0410
+#define AFE_GAIN1_CON1                                 0x0414
+#define AFE_GAIN1_CON2                                 0x0418
+#define AFE_GAIN1_CON3                                 0x041c
+#define AFE_CONN7                                      0x0420
+#define AFE_GAIN1_CUR                                  0x0424
+#define AFE_GAIN2_CON0                                 0x0428
+#define AFE_GAIN2_CON1                                 0x042c
+#define AFE_GAIN2_CON2                                 0x0430
+#define AFE_GAIN2_CON3                                 0x0434
+#define AFE_CONN8                                      0x0438
+#define AFE_GAIN2_CUR                                  0x043c
+#define AFE_CONN9                                      0x0440
+#define AFE_CONN10                                     0x0444
+#define AFE_CONN11                                     0x0448
+#define AFE_CONN12                                     0x044c
+#define AFE_CONN13                                     0x0450
+#define AFE_CONN14                                     0x0454
+#define AFE_CONN15                                     0x0458
+#define AFE_CONN16                                     0x045c
+#define AFE_CONN17                                     0x0460
+#define AFE_CONN18                                     0x0464
+#define AFE_CONN19                                     0x0468
+#define AFE_CONN20                                     0x046c
+#define AFE_CONN21                                     0x0470
+#define AFE_CONN22                                     0x0474
+#define AFE_CONN23                                     0x0478
+#define AFE_CONN24                                     0x047c
+#define AFE_CONN_RS                                    0x0494
+#define AFE_CONN_DI                                    0x0498
+#define AFE_CONN25                                     0x04b0
+#define AFE_CONN26                                     0x04b4
+#define AFE_CONN27                                     0x04b8
+#define AFE_CONN28                                     0x04bc
+#define AFE_CONN29                                     0x04c0
+#define AFE_CONN30                                     0x04c4
+#define AFE_CONN31                                     0x04c8
+#define AFE_CONN32                                     0x04cc
+#define AFE_SRAM_DELSEL_CON1                           0x04f4
+#define AFE_CONN56                                     0x0500
+#define AFE_CONN57                                     0x0504
+#define AFE_CONN58                                     0x0508
+#define AFE_CONN59                                     0x050c
+#define AFE_CONN56_1                                   0x0510
+#define AFE_CONN57_1                                   0x0514
+#define AFE_CONN58_1                                   0x0518
+#define AFE_CONN59_1                                   0x051c
+#define PCM_INTF_CON1                                  0x0530
+#define PCM_INTF_CON2                                  0x0538
+#define PCM2_INTF_CON                                  0x053c
+#define AFE_CM1_CON                                    0x0550
+#define AFE_CONN34                                     0x0580
+#define FPGA_CFG0                                      0x05b0
+#define FPGA_CFG1                                      0x05b4
+#define FPGA_CFG2                                      0x05c0
+#define FPGA_CFG3                                      0x05c4
+#define AUDIO_TOP_DBG_CON                              0x05c8
+#define AUDIO_TOP_DBG_MON0                             0x05cc
+#define AUDIO_TOP_DBG_MON1                             0x05d0
+#define AFE_IRQ8_MCU_CNT_MON                           0x05e4
+#define AFE_IRQ11_MCU_CNT_MON                          0x05e8
+#define AFE_IRQ12_MCU_CNT_MON                          0x05ec
+#define AFE_IRQ_MCU_CNT9                               0x0600
+#define AFE_IRQ_MCU_CNT10                              0x0604
+#define AFE_IRQ_MCU_CNT13                              0x0608
+#define AFE_IRQ_MCU_CNT14                              0x060c
+#define AFE_IRQ_MCU_CNT15                              0x0610
+#define AFE_IRQ_MCU_CNT16                              0x0614
+#define AFE_IRQ_MCU_CNT17                              0x0618
+#define AFE_IRQ_MCU_CNT18                              0x061c
+#define AFE_IRQ_MCU_CNT19                              0x0620
+#define AFE_IRQ_MCU_CNT20                              0x0624
+#define AFE_IRQ_MCU_CNT21                              0x0628
+#define AFE_IRQ_MCU_CNT22                              0x062c
+#define AFE_IRQ_MCU_CNT23                              0x0630
+#define AFE_IRQ_MCU_CNT24                              0x0634
+#define AFE_IRQ_MCU_CNT25                              0x0638
+#define AFE_IRQ_MCU_CNT26                              0x063c
+#define AFE_IRQ9_MCU_CNT_MON                           0x0660
+#define AFE_IRQ10_MCU_CNT_MON                          0x0664
+#define AFE_IRQ13_MCU_CNT_MON                          0x0668
+#define AFE_IRQ14_MCU_CNT_MON                          0x066c
+#define AFE_IRQ15_MCU_CNT_MON                          0x0670
+#define AFE_IRQ16_MCU_CNT_MON                          0x0674
+#define AFE_IRQ17_MCU_CNT_MON                          0x0678
+#define AFE_IRQ18_MCU_CNT_MON                          0x067c
+#define AFE_IRQ19_MCU_CNT_MON                          0x0680
+#define AFE_IRQ20_MCU_CNT_MON                          0x0684
+#define AFE_IRQ21_MCU_CNT_MON                          0x0688
+#define AFE_IRQ22_MCU_CNT_MON                          0x068c
+#define AFE_IRQ23_MCU_CNT_MON                          0x0690
+#define AFE_IRQ24_MCU_CNT_MON                          0x0694
+#define AFE_IRQ25_MCU_CNT_MON                          0x0698
+#define AFE_IRQ26_MCU_CNT_MON                          0x069c
+#define AFE_IRQ31_MCU_CNT_MON                          0x06a0
+#define AFE_GENERAL_REG0                               0x0800
+#define AFE_GENERAL_REG1                               0x0804
+#define AFE_GENERAL_REG2                               0x0808
+#define AFE_GENERAL_REG3                               0x080c
+#define AFE_GENERAL_REG4                               0x0810
+#define AFE_GENERAL_REG5                               0x0814
+#define AFE_GENERAL_REG6                               0x0818
+#define AFE_GENERAL_REG7                               0x081c
+#define AFE_GENERAL_REG8                               0x0820
+#define AFE_GENERAL_REG9                               0x0824
+#define AFE_GENERAL_REG10                              0x0828
+#define AFE_GENERAL_REG11                              0x082c
+#define AFE_GENERAL_REG12                              0x0830
+#define AFE_GENERAL_REG13                              0x0834
+#define AFE_GENERAL_REG14                              0x0838
+#define AFE_GENERAL_REG15                              0x083c
+#define AFE_CBIP_CFG0                                  0x0840
+#define AFE_CBIP_MON0                                  0x0844
+#define AFE_CBIP_SLV_MUX_MON0                          0x0848
+#define AFE_CBIP_SLV_DECODER_MON0                      0x084c
+#define AFE_ADDA6_MTKAIF_MON0                          0x0854
+#define AFE_ADDA6_MTKAIF_MON1                          0x0858
+#define AFE_AWB_CON0                                   0x085c
+#define AFE_AWB_BASE_MSB                               0x0860
+#define AFE_AWB_BASE                                   0x0864
+#define AFE_AWB_CUR_MSB                                        0x0868
+#define AFE_AWB_CUR                                    0x086c
+#define AFE_AWB_END_MSB                                        0x0870
+#define AFE_AWB_END                                    0x0874
+#define AFE_AWB2_CON0                                  0x0878
+#define AFE_AWB2_BASE_MSB                              0x087c
+#define AFE_AWB2_BASE                                  0x0880
+#define AFE_AWB2_CUR_MSB                               0x0884
+#define AFE_AWB2_CUR                                   0x0888
+#define AFE_AWB2_END_MSB                               0x088c
+#define AFE_AWB2_END                                   0x0890
+#define AFE_DAI_CON0                                   0x0894
+#define AFE_DAI_BASE_MSB                               0x0898
+#define AFE_DAI_BASE                                   0x089c
+#define AFE_DAI_CUR_MSB                                        0x08a0
+#define AFE_DAI_CUR                                    0x08a4
+#define AFE_DAI_END_MSB                                        0x08a8
+#define AFE_DAI_END                                    0x08ac
+#define AFE_DAI2_CON0                                  0x08b0
+#define AFE_DAI2_BASE_MSB                              0x08b4
+#define AFE_DAI2_BASE                                  0x08b8
+#define AFE_DAI2_CUR_MSB                               0x08bc
+#define AFE_DAI2_CUR                                   0x08c0
+#define AFE_DAI2_END_MSB                               0x08c4
+#define AFE_DAI2_END                                   0x08c8
+#define AFE_MEMIF_CON0                                 0x08cc
+#define AFE_CONN0_1                                    0x0900
+#define AFE_CONN1_1                                    0x0904
+#define AFE_CONN2_1                                    0x0908
+#define AFE_CONN3_1                                    0x090c
+#define AFE_CONN4_1                                    0x0910
+#define AFE_CONN5_1                                    0x0914
+#define AFE_CONN6_1                                    0x0918
+#define AFE_CONN7_1                                    0x091c
+#define AFE_CONN8_1                                    0x0920
+#define AFE_CONN9_1                                    0x0924
+#define AFE_CONN10_1                                   0x0928
+#define AFE_CONN11_1                                   0x092c
+#define AFE_CONN12_1                                   0x0930
+#define AFE_CONN13_1                                   0x0934
+#define AFE_CONN14_1                                   0x0938
+#define AFE_CONN15_1                                   0x093c
+#define AFE_CONN16_1                                   0x0940
+#define AFE_CONN17_1                                   0x0944
+#define AFE_CONN18_1                                   0x0948
+#define AFE_CONN19_1                                   0x094c
+#define AFE_CONN20_1                                   0x0950
+#define AFE_CONN21_1                                   0x0954
+#define AFE_CONN22_1                                   0x0958
+#define AFE_CONN23_1                                   0x095c
+#define AFE_CONN24_1                                   0x0960
+#define AFE_CONN25_1                                   0x0964
+#define AFE_CONN26_1                                   0x0968
+#define AFE_CONN27_1                                   0x096c
+#define AFE_CONN28_1                                   0x0970
+#define AFE_CONN29_1                                   0x0974
+#define AFE_CONN30_1                                   0x0978
+#define AFE_CONN31_1                                   0x097c
+#define AFE_CONN32_1                                   0x0980
+#define AFE_CONN33_1                                   0x0984
+#define AFE_CONN34_1                                   0x0988
+#define AFE_CONN_RS_1                                  0x098c
+#define AFE_CONN_DI_1                                  0x0990
+#define AFE_CONN_24BIT_1                               0x0994
+#define AFE_CONN_REG                                   0x0998
+#define AFE_CONN35                                     0x09a0
+#define AFE_CONN36                                     0x09a4
+#define AFE_CONN37                                     0x09a8
+#define AFE_CONN38                                     0x09ac
+#define AFE_CONN35_1                                   0x09b0
+#define AFE_CONN36_1                                   0x09b4
+#define AFE_CONN37_1                                   0x09b8
+#define AFE_CONN38_1                                   0x09bc
+#define AFE_CONN39                                     0x09c0
+#define AFE_CONN40                                     0x09c4
+#define AFE_CONN41                                     0x09c8
+#define AFE_CONN42                                     0x09cc
+#define AFE_CONN39_1                                   0x09e0
+#define AFE_CONN40_1                                   0x09e4
+#define AFE_CONN41_1                                   0x09e8
+#define AFE_CONN42_1                                   0x09ec
+#define AFE_I2S_CON4                                   0x09f8
+#define AFE_CONN60                                     0x0a64
+#define AFE_CONN61                                     0x0a68
+#define AFE_CONN62                                     0x0a6c
+#define AFE_CONN63                                     0x0a70
+#define AFE_CONN64                                     0x0a74
+#define AFE_CONN65                                     0x0a78
+#define AFE_CONN66                                     0x0a7c
+#define AFE_ADDA6_TOP_CON0                             0x0a80
+#define AFE_ADDA6_UL_SRC_CON0                          0x0a84
+#define AFE_ADDA6_UL_SRC_CON1                          0x0a88
+#define AFE_ADDA6_SRC_DEBUG                            0x0a8c
+#define AFE_ADDA6_SRC_DEBUG_MON0                       0x0a90
+#define AFE_ADDA6_ULCF_CFG_02_01                       0x0aa0
+#define AFE_ADDA6_ULCF_CFG_04_03                       0x0aa4
+#define AFE_ADDA6_ULCF_CFG_06_05                       0x0aa8
+#define AFE_ADDA6_ULCF_CFG_08_07                       0x0aac
+#define AFE_ADDA6_ULCF_CFG_10_09                       0x0ab0
+#define AFE_ADDA6_ULCF_CFG_12_11                       0x0ab4
+#define AFE_ADDA6_ULCF_CFG_14_13                       0x0ab8
+#define AFE_ADDA6_ULCF_CFG_16_15                       0x0abc
+#define AFE_ADDA6_ULCF_CFG_18_17                       0x0ac0
+#define AFE_ADDA6_ULCF_CFG_20_19                       0x0ac4
+#define AFE_ADDA6_ULCF_CFG_22_21                       0x0ac8
+#define AFE_ADDA6_ULCF_CFG_24_23                       0x0acc
+#define AFE_ADDA6_ULCF_CFG_26_25                       0x0ad0
+#define AFE_ADDA6_ULCF_CFG_28_27                       0x0ad4
+#define AFE_ADDA6_ULCF_CFG_30_29                       0x0ad8
+#define AFE_ADD6A_UL_SRC_MON0                          0x0ae4
+#define AFE_ADDA6_UL_SRC_MON1                          0x0ae8
+#define AFE_CONN43                                     0x0af8
+#define AFE_CONN43_1                                   0x0afc
+#define AFE_MOD_DAI_CON0                               0x0b00
+#define AFE_MOD_DAI_BASE_MSB                           0x0b04
+#define AFE_MOD_DAI_BASE                               0x0b08
+#define AFE_MOD_DAI_CUR_MSB                            0x0b0c
+#define AFE_MOD_DAI_CUR                                        0x0b10
+#define AFE_MOD_DAI_END_MSB                            0x0b14
+#define AFE_MOD_DAI_END                                        0x0b18
+#define AFE_AWB_RCH_MON                                        0x0b70
+#define AFE_AWB_LCH_MON                                        0x0b74
+#define AFE_VUL_RCH_MON                                        0x0b78
+#define AFE_VUL_LCH_MON                                        0x0b7c
+#define AFE_VUL12_RCH_MON                              0x0b80
+#define AFE_VUL12_LCH_MON                              0x0b84
+#define AFE_VUL2_RCH_MON                               0x0b88
+#define AFE_VUL2_LCH_MON                               0x0b8c
+#define AFE_DAI_DATA_MON                               0x0b90
+#define AFE_MOD_DAI_DATA_MON                           0x0b94
+#define AFE_DAI2_DATA_MON                              0x0b98
+#define AFE_AWB2_RCH_MON                               0x0b9c
+#define AFE_AWB2_LCH_MON                               0x0ba0
+#define AFE_VUL3_RCH_MON                               0x0ba4
+#define AFE_VUL3_LCH_MON                               0x0ba8
+#define AFE_VUL4_RCH_MON                               0x0bac
+#define AFE_VUL4_LCH_MON                               0x0bb0
+#define AFE_VUL5_RCH_MON                               0x0bb4
+#define AFE_VUL5_LCH_MON                               0x0bb8
+#define AFE_VUL6_RCH_MON                               0x0bbc
+#define AFE_VUL6_LCH_MON                               0x0bc0
+#define AFE_DL1_RCH_MON                                        0x0bc4
+#define AFE_DL1_LCH_MON                                        0x0bc8
+#define AFE_DL2_RCH_MON                                        0x0bcc
+#define AFE_DL2_LCH_MON                                        0x0bd0
+#define AFE_DL12_RCH1_MON                              0x0bd4
+#define AFE_DL12_LCH1_MON                              0x0bd8
+#define AFE_DL12_RCH2_MON                              0x0bdc
+#define AFE_DL12_LCH2_MON                              0x0be0
+#define AFE_DL3_RCH_MON                                        0x0be4
+#define AFE_DL3_LCH_MON                                        0x0be8
+#define AFE_DL4_RCH_MON                                        0x0bec
+#define AFE_DL4_LCH_MON                                        0x0bf0
+#define AFE_DL5_RCH_MON                                        0x0bf4
+#define AFE_DL5_LCH_MON                                        0x0bf8
+#define AFE_DL6_RCH_MON                                        0x0bfc
+#define AFE_DL6_LCH_MON                                        0x0c00
+#define AFE_DL7_RCH_MON                                        0x0c04
+#define AFE_DL7_LCH_MON                                        0x0c08
+#define AFE_DL8_RCH_MON                                        0x0c0c
+#define AFE_DL8_LCH_MON                                        0x0c10
+#define AFE_VUL5_CON0                                  0x0c14
+#define AFE_VUL5_BASE_MSB                              0x0c18
+#define AFE_VUL5_BASE                                  0x0c1c
+#define AFE_VUL5_CUR_MSB                               0x0c20
+#define AFE_VUL5_CUR                                   0x0c24
+#define AFE_VUL5_END_MSB                               0x0c28
+#define AFE_VUL5_END                                   0x0c2c
+#define AFE_VUL6_CON0                                  0x0c30
+#define AFE_VUL6_BASE_MSB                              0x0c34
+#define AFE_VUL6_BASE                                  0x0c38
+#define AFE_VUL6_CUR_MSB                               0x0c3c
+#define AFE_VUL6_CUR                                   0x0c40
+#define AFE_VUL6_END_MSB                               0x0c44
+#define AFE_VUL6_END                                   0x0c48
+#define AFE_ADDA_DL_SDM_DCCOMP_CON                     0x0c50
+#define AFE_ADDA_DL_SDM_TEST                           0x0c54
+#define AFE_ADDA_DL_DC_COMP_CFG0                       0x0c58
+#define AFE_ADDA_DL_DC_COMP_CFG1                       0x0c5c
+#define AFE_ADDA_DL_SDM_FIFO_MON                       0x0c60
+#define AFE_ADDA_DL_SRC_LCH_MON                                0x0c64
+#define AFE_ADDA_DL_SRC_RCH_MON                                0x0c68
+#define AFE_ADDA_DL_SDM_OUT_MON                                0x0c6c
+#define AFE_ADDA_DL_SDM_DITHER_CON                     0x0c70
+#define AFE_ADDA_DL_SDM_AUTO_RESET_CON                 0x0c74
+#define AFE_CONNSYS_I2S_CON                            0x0c78
+#define AFE_CONNSYS_I2S_MON                            0x0c7c
+#define AFE_ASRC_2CH_CON0                              0x0c80
+#define AFE_ASRC_2CH_CON1                              0x0c84
+#define AFE_ASRC_2CH_CON2                              0x0c88
+#define AFE_ASRC_2CH_CON3                              0x0c8c
+#define AFE_ASRC_2CH_CON4                              0x0c90
+#define AFE_ASRC_2CH_CON5                              0x0c94
+#define AFE_ASRC_2CH_CON6                              0x0c98
+#define AFE_ASRC_2CH_CON7                              0x0c9c
+#define AFE_ASRC_2CH_CON8                              0x0ca0
+#define AFE_ASRC_2CH_CON9                              0x0ca4
+#define AFE_ASRC_2CH_CON10                             0x0ca8
+#define AFE_ASRC_2CH_CON12                             0x0cb0
+#define AFE_ASRC_2CH_CON13                             0x0cb4
+#define AFE_ADDA6_IIR_COEF_02_01                       0x0ce0
+#define AFE_ADDA6_IIR_COEF_04_03                       0x0ce4
+#define AFE_ADDA6_IIR_COEF_06_05                       0x0ce8
+#define AFE_ADDA6_IIR_COEF_08_07                       0x0cec
+#define AFE_ADDA6_IIR_COEF_10_09                       0x0cf0
+#define AFE_CONN67                                     0x0cf4
+#define AFE_CONN68                                     0x0cf8
+#define AFE_CONN69                                     0x0cfc
+#define AFE_SE_PROT_SIDEBAND                           0x0d38
+#define AFE_SE_DOMAIN_SIDEBAND0                                0x0d3c
+#define AFE_ADDA_PREDIS_CON2                           0x0d40
+#define AFE_ADDA_PREDIS_CON3                           0x0d44
+#define AFE_SE_DOMAIN_SIDEBAND1                                0x0d54
+#define AFE_SE_DOMAIN_SIDEBAND2                                0x0d58
+#define AFE_SE_DOMAIN_SIDEBAND3                                0x0d5c
+#define AFE_CONN44                                     0x0d70
+#define AFE_CONN45                                     0x0d74
+#define AFE_CONN46                                     0x0d78
+#define AFE_CONN47                                     0x0d7c
+#define AFE_CONN44_1                                   0x0d80
+#define AFE_CONN45_1                                   0x0d84
+#define AFE_CONN46_1                                   0x0d88
+#define AFE_CONN47_1                                   0x0d8c
+#define AFE_HD_ENGEN_ENABLE                            0x0dd0
+#define AFE_ADDA_DL_NLE_FIFO_MON                       0x0dfc
+#define AFE_ADDA_MTKAIF_CFG0                           0x0e00
+#define AFE_CONN67_1                                   0x0e04
+#define AFE_CONN68_1                                   0x0e08
+#define AFE_CONN69_1                                   0x0e0c
+#define AFE_ADDA_MTKAIF_SYNCWORD_CFG                   0x0e14
+#define AFE_ADDA_MTKAIF_RX_CFG0                                0x0e20
+#define AFE_ADDA_MTKAIF_RX_CFG1                                0x0e24
+#define AFE_ADDA_MTKAIF_RX_CFG2                                0x0e28
+#define AFE_ADDA_MTKAIF_MON0                           0x0e34
+#define AFE_ADDA_MTKAIF_MON1                           0x0e38
+#define AFE_AUD_PAD_TOP                                        0x0e40
+#define AFE_DL_NLE_R_CFG0                              0x0e44
+#define AFE_DL_NLE_R_CFG1                              0x0e48
+#define AFE_DL_NLE_L_CFG0                              0x0e4c
+#define AFE_DL_NLE_L_CFG1                              0x0e50
+#define AFE_DL_NLE_R_MON0                              0x0e54
+#define AFE_DL_NLE_R_MON1                              0x0e58
+#define AFE_DL_NLE_R_MON2                              0x0e5c
+#define AFE_DL_NLE_L_MON0                              0x0e60
+#define AFE_DL_NLE_L_MON1                              0x0e64
+#define AFE_DL_NLE_L_MON2                              0x0e68
+#define AFE_DL_NLE_GAIN_CFG0                           0x0e6c
+#define AFE_ADDA6_MTKAIF_CFG0                          0x0e70
+#define AFE_ADDA6_MTKAIF_RX_CFG0                       0x0e74
+#define AFE_ADDA6_MTKAIF_RX_CFG1                       0x0e78
+#define AFE_ADDA6_MTKAIF_RX_CFG2                       0x0e7c
+#define AFE_GENERAL1_ASRC_2CH_CON0                     0x0e80
+#define AFE_GENERAL1_ASRC_2CH_CON1                     0x0e84
+#define AFE_GENERAL1_ASRC_2CH_CON2                     0x0e88
+#define AFE_GENERAL1_ASRC_2CH_CON3                     0x0e8c
+#define AFE_GENERAL1_ASRC_2CH_CON4                     0x0e90
+#define AFE_GENERAL1_ASRC_2CH_CON5                     0x0e94
+#define AFE_GENERAL1_ASRC_2CH_CON6                     0x0e98
+#define AFE_GENERAL1_ASRC_2CH_CON7                     0x0e9c
+#define AFE_GENERAL1_ASRC_2CH_CON8                     0x0ea0
+#define AFE_GENERAL1_ASRC_2CH_CON9                     0x0ea4
+#define AFE_GENERAL1_ASRC_2CH_CON10                    0x0ea8
+#define AFE_GENERAL1_ASRC_2CH_CON12                    0x0eb0
+#define AFE_GENERAL1_ASRC_2CH_CON13                    0x0eb4
+#define GENERAL_ASRC_MODE                              0x0eb8
+#define GENERAL_ASRC_EN_ON                             0x0ebc
+#define AFE_CONN48                                     0x0ec0
+#define AFE_CONN49                                     0x0ec4
+#define AFE_CONN50                                     0x0ec8
+#define AFE_CONN51                                     0x0ecc
+#define AFE_CONN52                                     0x0ed0
+#define AFE_CONN53                                     0x0ed4
+#define AFE_CONN54                                     0x0ed8
+#define AFE_CONN55                                     0x0edc
+#define AFE_CONN48_1                                   0x0ee0
+#define AFE_CONN49_1                                   0x0ee4
+#define AFE_CONN50_1                                   0x0ee8
+#define AFE_CONN51_1                                   0x0eec
+#define AFE_CONN52_1                                   0x0ef0
+#define AFE_CONN53_1                                   0x0ef4
+#define AFE_CONN54_1                                   0x0ef8
+#define AFE_CONN55_1                                   0x0efc
+#define AFE_GENERAL2_ASRC_2CH_CON0                     0x0f00
+#define AFE_GENERAL2_ASRC_2CH_CON1                     0x0f04
+#define AFE_GENERAL2_ASRC_2CH_CON2                     0x0f08
+#define AFE_GENERAL2_ASRC_2CH_CON3                     0x0f0c
+#define AFE_GENERAL2_ASRC_2CH_CON4                     0x0f10
+#define AFE_GENERAL2_ASRC_2CH_CON5                     0x0f14
+#define AFE_GENERAL2_ASRC_2CH_CON6                     0x0f18
+#define AFE_GENERAL2_ASRC_2CH_CON7                     0x0f1c
+#define AFE_GENERAL2_ASRC_2CH_CON8                     0x0f20
+#define AFE_GENERAL2_ASRC_2CH_CON9                     0x0f24
+#define AFE_GENERAL2_ASRC_2CH_CON10                    0x0f28
+#define AFE_GENERAL2_ASRC_2CH_CON12                    0x0f30
+#define AFE_GENERAL2_ASRC_2CH_CON13                    0x0f34
+#define AFE_DL5_CON0                                   0x0f4c
+#define AFE_DL5_BASE_MSB                               0x0f50
+#define AFE_DL5_BASE                                   0x0f54
+#define AFE_DL5_CUR_MSB                                        0x0f58
+#define AFE_DL5_CUR                                    0x0f5c
+#define AFE_DL5_END_MSB                                        0x0f60
+#define AFE_DL5_END                                    0x0f64
+#define AFE_DL6_CON0                                   0x0f68
+#define AFE_DL6_BASE_MSB                               0x0f6c
+#define AFE_DL6_BASE                                   0x0f70
+#define AFE_DL6_CUR_MSB                                        0x0f74
+#define AFE_DL6_CUR                                    0x0f78
+#define AFE_DL6_END_MSB                                        0x0f7c
+#define AFE_DL6_END                                    0x0f80
+#define AFE_DL7_CON0                                   0x0f84
+#define AFE_DL7_BASE_MSB                               0x0f88
+#define AFE_DL7_BASE                                   0x0f8c
+#define AFE_DL7_CUR_MSB                                        0x0f90
+#define AFE_DL7_CUR                                    0x0f94
+#define AFE_DL7_END_MSB                                        0x0f98
+#define AFE_DL7_END                                    0x0f9c
+#define AFE_DL8_CON0                                   0x0fa0
+#define AFE_DL8_BASE_MSB                               0x0fa4
+#define AFE_DL8_BASE                                   0x0fa8
+#define AFE_DL8_CUR_MSB                                        0x0fac
+#define AFE_DL8_CUR                                    0x0fb0
+#define AFE_DL8_END_MSB                                        0x0fb4
+#define AFE_DL8_END                                    0x0fb8
+#define AFE_SE_SECURE_CON                              0x1004
+#define AFE_PROT_SIDEBAND_MON                          0x1008
+#define AFE_DOMAIN_SIDEBAND0_MON                       0x100c
+#define AFE_DOMAIN_SIDEBAND1_MON                       0x1010
+#define AFE_DOMAIN_SIDEBAND2_MON                       0x1014
+#define AFE_DOMAIN_SIDEBAND3_MON                       0x1018
+#define AFE_SECURE_MASK_CONN0                          0x1020
+#define AFE_SECURE_MASK_CONN1                          0x1024
+#define AFE_SECURE_MASK_CONN2                          0x1028
+#define AFE_SECURE_MASK_CONN3                          0x102c
+#define AFE_SECURE_MASK_CONN4                          0x1030
+#define AFE_SECURE_MASK_CONN5                          0x1034
+#define AFE_SECURE_MASK_CONN6                          0x1038
+#define AFE_SECURE_MASK_CONN7                          0x103c
+#define AFE_SECURE_MASK_CONN8                          0x1040
+#define AFE_SECURE_MASK_CONN9                          0x1044
+#define AFE_SECURE_MASK_CONN10                         0x1048
+#define AFE_SECURE_MASK_CONN11                         0x104c
+#define AFE_SECURE_MASK_CONN12                         0x1050
+#define AFE_SECURE_MASK_CONN13                         0x1054
+#define AFE_SECURE_MASK_CONN14                         0x1058
+#define AFE_SECURE_MASK_CONN15                         0x105c
+#define AFE_SECURE_MASK_CONN16                         0x1060
+#define AFE_SECURE_MASK_CONN17                         0x1064
+#define AFE_SECURE_MASK_CONN18                         0x1068
+#define AFE_SECURE_MASK_CONN19                         0x106c
+#define AFE_SECURE_MASK_CONN20                         0x1070
+#define AFE_SECURE_MASK_CONN21                         0x1074
+#define AFE_SECURE_MASK_CONN22                         0x1078
+#define AFE_SECURE_MASK_CONN23                         0x107c
+#define AFE_SECURE_MASK_CONN24                         0x1080
+#define AFE_SECURE_MASK_CONN25                         0x1084
+#define AFE_SECURE_MASK_CONN26                         0x1088
+#define AFE_SECURE_MASK_CONN27                         0x108c
+#define AFE_SECURE_MASK_CONN28                         0x1090
+#define AFE_SECURE_MASK_CONN29                         0x1094
+#define AFE_SECURE_MASK_CONN30                         0x1098
+#define AFE_SECURE_MASK_CONN31                         0x109c
+#define AFE_SECURE_MASK_CONN32                         0x10a0
+#define AFE_SECURE_MASK_CONN33                         0x10a4
+#define AFE_SECURE_MASK_CONN34                         0x10a8
+#define AFE_SECURE_MASK_CONN35                         0x10ac
+#define AFE_SECURE_MASK_CONN36                         0x10b0
+#define AFE_SECURE_MASK_CONN37                         0x10b4
+#define AFE_SECURE_MASK_CONN38                         0x10b8
+#define AFE_SECURE_MASK_CONN39                         0x10bc
+#define AFE_SECURE_MASK_CONN40                         0x10c0
+#define AFE_SECURE_MASK_CONN41                         0x10c4
+#define AFE_SECURE_MASK_CONN42                         0x10c8
+#define AFE_SECURE_MASK_CONN43                         0x10cc
+#define AFE_SECURE_MASK_CONN44                         0x10d0
+#define AFE_SECURE_MASK_CONN45                         0x10d4
+#define AFE_SECURE_MASK_CONN46                         0x10d8
+#define AFE_SECURE_MASK_CONN47                         0x10dc
+#define AFE_SECURE_MASK_CONN48                         0x10e0
+#define AFE_SECURE_MASK_CONN49                         0x10e4
+#define AFE_SECURE_MASK_CONN50                         0x10e8
+#define AFE_SECURE_MASK_CONN51                         0x10ec
+#define AFE_SECURE_MASK_CONN52                         0x10f0
+#define AFE_SECURE_MASK_CONN53                         0x10f4
+#define AFE_SECURE_MASK_CONN54                         0x10f8
+#define AFE_SECURE_MASK_CONN55                         0x10fc
+#define AFE_SECURE_MASK_CONN56                         0x1100
+#define AFE_SECURE_MASK_CONN57                         0x1104
+#define AFE_SECURE_MASK_CONN0_1                                0x1108
+#define AFE_SECURE_MASK_CONN1_1                                0x110c
+#define AFE_SECURE_MASK_CONN2_1                                0x1110
+#define AFE_SECURE_MASK_CONN3_1                                0x1114
+#define AFE_SECURE_MASK_CONN4_1                                0x1118
+#define AFE_SECURE_MASK_CONN5_1                                0x111c
+#define AFE_SECURE_MASK_CONN6_1                                0x1120
+#define AFE_SECURE_MASK_CONN7_1                                0x1124
+#define AFE_SECURE_MASK_CONN8_1                                0x1128
+#define AFE_SECURE_MASK_CONN9_1                                0x112c
+#define AFE_SECURE_MASK_CONN10_1                       0x1130
+#define AFE_SECURE_MASK_CONN11_1                       0x1134
+#define AFE_SECURE_MASK_CONN12_1                       0x1138
+#define AFE_SECURE_MASK_CONN13_1                       0x113c
+#define AFE_SECURE_MASK_CONN14_1                       0x1140
+#define AFE_SECURE_MASK_CONN15_1                       0x1144
+#define AFE_SECURE_MASK_CONN16_1                       0x1148
+#define AFE_SECURE_MASK_CONN17_1                       0x114c
+#define AFE_SECURE_MASK_CONN18_1                       0x1150
+#define AFE_SECURE_MASK_CONN19_1                       0x1154
+#define AFE_SECURE_MASK_CONN20_1                       0x1158
+#define AFE_SECURE_MASK_CONN21_1                       0x115c
+#define AFE_SECURE_MASK_CONN22_1                       0x1160
+#define AFE_SECURE_MASK_CONN23_1                       0x1164
+#define AFE_SECURE_MASK_CONN24_1                       0x1168
+#define AFE_SECURE_MASK_CONN25_1                       0x116c
+#define AFE_SECURE_MASK_CONN26_1                       0x1170
+#define AFE_SECURE_MASK_CONN27_1                       0x1174
+#define AFE_SECURE_MASK_CONN28_1                       0x1178
+#define AFE_SECURE_MASK_CONN29_1                       0x117c
+#define AFE_SECURE_MASK_CONN30_1                       0x1180
+#define AFE_SECURE_MASK_CONN31_1                       0x1184
+#define AFE_SECURE_MASK_CONN32_1                       0x1188
+#define AFE_SECURE_MASK_CONN33_1                       0x118c
+#define AFE_SECURE_MASK_CONN34_1                       0x1190
+#define AFE_SECURE_MASK_CONN35_1                       0x1194
+#define AFE_SECURE_MASK_CONN36_1                       0x1198
+#define AFE_SECURE_MASK_CONN37_1                       0x119c
+#define AFE_SECURE_MASK_CONN38_1                       0x11a0
+#define AFE_SECURE_MASK_CONN39_1                       0x11a4
+#define AFE_SECURE_MASK_CONN40_1                       0x11a8
+#define AFE_SECURE_MASK_CONN41_1                       0x11ac
+#define AFE_SECURE_MASK_CONN42_1                       0x11b0
+#define AFE_SECURE_MASK_CONN43_1                       0x11b4
+#define AFE_SECURE_MASK_CONN44_1                       0x11b8
+#define AFE_SECURE_MASK_CONN45_1                       0x11bc
+#define AFE_SECURE_MASK_CONN46_1                       0x11c0
+#define AFE_SECURE_MASK_CONN47_1                       0x11c4
+#define AFE_SECURE_MASK_CONN48_1                       0x11c8
+#define AFE_SECURE_MASK_CONN49_1                       0x11cc
+#define AFE_SECURE_MASK_CONN50_1                       0x11d0
+#define AFE_SECURE_MASK_CONN51_1                       0x11d4
+#define AFE_SECURE_MASK_CONN52_1                       0x11d8
+#define AFE_SECURE_MASK_CONN53_1                       0x11dc
+#define AFE_SECURE_MASK_CONN54_1                       0x11e0
+#define AFE_SECURE_MASK_CONN55_1                       0x11e4
+#define AFE_SECURE_MASK_CONN56_1                       0x11e8
+#define AFE_CONN60_1                                   0x11f0
+#define AFE_CONN61_1                                   0x11f4
+#define AFE_CONN62_1                                   0x11f8
+#define AFE_CONN63_1                                   0x11fc
+#define AFE_CONN64_1                                   0x1220
+#define AFE_CONN65_1                                   0x1224
+#define AFE_CONN66_1                                   0x1228
+#define FPGA_CFG4                                      0x1230
+#define FPGA_CFG5                                      0x1234
+#define FPGA_CFG6                                      0x1238
+#define FPGA_CFG7                                      0x123c
+#define FPGA_CFG8                                      0x1240
+#define FPGA_CFG9                                      0x1244
+#define FPGA_CFG10                                     0x1248
+#define FPGA_CFG11                                     0x124c
+#define FPGA_CFG12                                     0x1250
+#define FPGA_CFG13                                     0x1254
+#define ETDM_IN1_CON0                                  0x1430
+#define ETDM_IN1_CON1                                  0x1434
+#define ETDM_IN1_CON2                                  0x1438
+#define ETDM_IN1_CON3                                  0x143c
+#define ETDM_IN1_CON4                                  0x1440
+#define ETDM_IN1_CON5                                  0x1444
+#define ETDM_IN1_CON6                                  0x1448
+#define ETDM_IN1_CON7                                  0x144c
+#define ETDM_IN1_CON8                                  0x1450
+#define ETDM_OUT1_CON0                                 0x1454
+#define ETDM_OUT1_CON1                                 0x1458
+#define ETDM_OUT1_CON2                                 0x145c
+#define ETDM_OUT1_CON3                                 0x1460
+#define ETDM_OUT1_CON4                                 0x1464
+#define ETDM_OUT1_CON5                                 0x1468
+#define ETDM_OUT1_CON6                                 0x146c
+#define ETDM_OUT1_CON7                                 0x1470
+#define ETDM_OUT1_CON8                                 0x1474
+#define ETDM_IN1_MON                                   0x1478
+#define ETDM_OUT1_MON                                  0x147c
+#define ETDM_0_3_COWORK_CON0                           0x18b0
+#define ETDM_0_3_COWORK_CON1                           0x18b4
+#define ETDM_0_3_COWORK_CON3                           0x18bc
+
+#define AFE_MAX_REGISTER                               ETDM_0_3_COWORK_CON3
+
+#define AFE_IRQ_STATUS_BITS                            0x87FFFFFF
+#define AFE_IRQ_CNT_SHIFT                              0
+#define AFE_IRQ_CNT_MASK                               0x3ffff
+#endif
index efd5cc364a3515b445c89b2c14086477e7931493..2ee3872c83c36f58063385e599ed44d33f76c6ca 100644 (file)
@@ -284,7 +284,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe,
 {
        struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id);
        unsigned long flags;
-       int ret = 0;
+       int ret;
 
        if (!cfg)
                return -EINVAL;
@@ -308,7 +308,7 @@ static int mt8195_afe_enable_apll_tuner(struct mtk_base_afe *afe,
 
        spin_unlock_irqrestore(&cfg->ctrl_lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe,
@@ -316,7 +316,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe,
 {
        struct mt8195_afe_tuner_cfg *cfg = mt8195_afe_found_apll_tuner(id);
        unsigned long flags;
-       int ret = 0;
+       int ret;
 
        if (!cfg)
                return -EINVAL;
@@ -338,7 +338,7 @@ static int mt8195_afe_disable_apll_tuner(struct mtk_base_afe *afe,
        if (ret)
                return ret;
 
-       return ret;
+       return 0;
 }
 
 int mt8195_afe_get_mclk_source_clk_id(int sel)
index c02c10da360049a6b31a29203357147900075cb0..c2e268054773df30f5a78e29a93d5a7c186579c9 100644 (file)
@@ -2172,11 +2172,11 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                etdm_data->slave_mode = true;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                etdm_data->slave_mode = false;
                break;
        default:
index 12644ded83d593363d2a4720527afd3f9c4bb6c7..caceb0deb467f90039a04917ee4215279bfc9d6d 100644 (file)
@@ -266,11 +266,11 @@ static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                pcmif_priv->slave_mode = 1;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                pcmif_priv->slave_mode = 0;
                break;
        default:
index 54a00b0699b1fd12989797111baed1a07bed76c2..c530e3fc27e43b7b2cec24a48b5803f4c3e8940d 100644 (file)
@@ -20,6 +20,8 @@
 #include "../../codecs/rt1011.h"
 #include "../../codecs/rt5682.h"
 #include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-dsp-sof-common.h"
+#include "../common/mtk-soc-card.h"
 #include "mt8195-afe-clk.h"
 #include "mt8195-afe-common.h"
 
@@ -54,13 +56,6 @@ struct mt8195_card_data {
        unsigned long quirk;
 };
 
-struct sof_conn_stream {
-       const char *normal_link;
-       const char *sof_link;
-       const char *sof_dma;
-       int stream_dir;
-};
-
 struct mt8195_mt6359_priv {
        struct snd_soc_jack headset_jack;
        struct snd_soc_jack dp_jack;
@@ -374,7 +369,8 @@ static const struct snd_soc_ops mt8195_dptx_ops = {
 
 static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+       struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
        struct snd_soc_component *cmpnt_codec =
                asoc_rtd_to_codec(rtd, 0)->component;
        int ret;
@@ -389,7 +385,8 @@ static int mt8195_dptx_codec_init(struct snd_soc_pcm_runtime *rtd)
 
 static int mt8195_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+       struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
        struct snd_soc_component *cmpnt_codec =
                asoc_rtd_to_codec(rtd, 0)->component;
        int ret;
@@ -555,7 +552,8 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_component *cmpnt_codec =
                asoc_rtd_to_codec(rtd, 0)->component;
-       struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+       struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
        struct snd_soc_jack *jack = &priv->headset_jack;
        struct snd_soc_component *cmpnt_afe =
                snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
@@ -722,7 +720,8 @@ static int mt8195_set_bias_level_post(struct snd_soc_card *card,
        struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
 {
        struct snd_soc_component *component = dapm->component;
-       struct mt8195_mt6359_priv *priv = snd_soc_card_get_drvdata(card);
+       struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+       struct mt8195_mt6359_priv *priv = soc_card_data->mach_priv;
        int ret;
 
        /*
@@ -1321,175 +1320,24 @@ static struct snd_soc_card mt8195_mt6359_soc_card = {
 static int mt8195_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
                                 struct snd_pcm_hw_params *params)
 {
-       struct snd_soc_card *card = rtd->card;
-       struct snd_soc_dai_link *sof_dai_link = NULL;
-       struct snd_soc_pcm_runtime *runtime;
-       struct snd_soc_dai *cpu_dai;
-       int i, j, ret = 0;
-
-       for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) {
-               const struct sof_conn_stream *conn = &g_sof_conn_streams[i];
-
-               if (strcmp(rtd->dai_link->name, conn->normal_link))
-                       continue;
-
-               for_each_card_rtds(card, runtime) {
-                       if (strcmp(runtime->dai_link->name, conn->sof_link))
-                               continue;
-
-                       for_each_rtd_cpu_dais(runtime, j, cpu_dai) {
-                               if (cpu_dai->stream_active[conn->stream_dir] > 0) {
-                                       sof_dai_link = runtime->dai_link;
-                                       break;
-                               }
-                       }
-                       break;
-               }
+       int ret;
 
-               if (sof_dai_link && sof_dai_link->be_hw_params_fixup)
-                       ret = sof_dai_link->be_hw_params_fixup(runtime, params);
-
-               break;
-       }
+       ret = mtk_sof_dai_link_fixup(rtd, params);
 
        if (!strcmp(rtd->dai_link->name, "ETDM2_IN_BE") ||
            !strcmp(rtd->dai_link->name, "ETDM1_OUT_BE")) {
-               mt8195_etdm_hw_params_fixup(runtime, params);
+               mt8195_etdm_hw_params_fixup(rtd, params);
        }
 
        return ret;
 }
 
-static int mt8195_mt6359_card_late_probe(struct snd_soc_card *card)
-{
-       struct snd_soc_pcm_runtime *runtime;
-       struct snd_soc_component *sof_comp = NULL;
-       int i;
-
-       /* 1. find sof component */
-       for_each_card_rtds(card, runtime) {
-               for (i = 0; i < runtime->num_components; i++) {
-                       if (!runtime->components[i]->driver->name)
-                               continue;
-                       if (!strcmp(runtime->components[i]->driver->name, "sof-audio-component")) {
-                               sof_comp = runtime->components[i];
-                               break;
-                       }
-               }
-       }
-
-       if (!sof_comp) {
-               dev_info(card->dev, " probe without component\n");
-               return 0;
-       }
-       /* 2. add route path and fixup callback */
-       for (i = 0; i < ARRAY_SIZE(g_sof_conn_streams); i++) {
-               const struct sof_conn_stream *conn = &g_sof_conn_streams[i];
-               struct snd_soc_pcm_runtime *sof_rtd = NULL;
-               struct snd_soc_pcm_runtime *normal_rtd = NULL;
-               struct snd_soc_pcm_runtime *rtd = NULL;
-
-               for_each_card_rtds(card, rtd) {
-                       if (!strcmp(rtd->dai_link->name, conn->sof_link)) {
-                               sof_rtd = rtd;
-                               continue;
-                       }
-                       if (!strcmp(rtd->dai_link->name, conn->normal_link)) {
-                               normal_rtd = rtd;
-                               continue;
-                       }
-                       if (normal_rtd && sof_rtd)
-                               break;
-               }
-               if (normal_rtd && sof_rtd) {
-                       int j;
-                       struct snd_soc_dai *cpu_dai;
-
-                       for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) {
-                               struct snd_soc_dapm_route route;
-                               struct snd_soc_dapm_path *p = NULL;
-                               struct snd_soc_dapm_widget *play_widget =
-                                       cpu_dai->playback_widget;
-                               struct snd_soc_dapm_widget *cap_widget =
-                                       cpu_dai->capture_widget;
-                               memset(&route, 0, sizeof(route));
-                               if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE &&
-                                   cap_widget) {
-                                       snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) {
-                                               route.source = conn->sof_dma;
-                                               route.sink = p->sink->name;
-                                               snd_soc_dapm_add_routes(&card->dapm, &route, 1);
-                                       }
-                               } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK &&
-                                               play_widget){
-                                       snd_soc_dapm_widget_for_each_source_path(play_widget, p) {
-                                               route.source = p->source->name;
-                                               route.sink = conn->sof_dma;
-                                               snd_soc_dapm_add_routes(&card->dapm, &route, 1);
-                                       }
-                               } else {
-                                       dev_err(cpu_dai->dev, "stream dir and widget not pair\n");
-                               }
-                       }
-                       normal_rtd->dai_link->be_hw_params_fixup = mt8195_dai_link_fixup;
-               }
-       }
-
-       return 0;
-}
-
-static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
-                                  const char *propname)
-{
-       struct device *dev = card->dev;
-       struct snd_soc_dai_link *link;
-       const char *dai_name = NULL;
-       int i, j, ret, num_links;
-
-       num_links = of_property_count_strings(np, "mediatek,dai-link");
-
-       if (num_links < 0 || num_links > ARRAY_SIZE(mt8195_mt6359_dai_links)) {
-               dev_dbg(dev, "number of dai-link is invalid\n");
-               return -EINVAL;
-       }
-
-       card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
-       if (!card->dai_link)
-               return -ENOMEM;
-
-       card->num_links = 0;
-       link = card->dai_link;
-
-       for (i = 0; i < num_links; i++) {
-               ret = of_property_read_string_index(np, propname, i, &dai_name);
-               if (ret) {
-                       dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n",
-                               propname, i, ret);
-                       return -EINVAL;
-               }
-
-               for (j = 0; j < ARRAY_SIZE(mt8195_mt6359_dai_links); j++) {
-                       if (!strcmp(dai_name, mt8195_mt6359_dai_links[j].name)) {
-                               memcpy(link, &mt8195_mt6359_dai_links[j],
-                                      sizeof(struct snd_soc_dai_link));
-                               link++;
-                               card->num_links++;
-                               break;
-                       }
-               }
-       }
-
-       if (card->num_links != num_links)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &mt8195_mt6359_soc_card;
        struct snd_soc_dai_link *dai_link;
-       struct mt8195_mt6359_priv *priv;
+       struct mtk_soc_card_data *soc_card_data;
+       struct mt8195_mt6359_priv *mach_priv;
        struct device_node *platform_node, *adsp_node, *dp_node, *hdmi_node;
        struct mt8195_card_data *card_data;
        int is5682s = 0;
@@ -1512,17 +1360,41 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
 
        if (strstr(card->name, "_5682s"))
                is5682s = 1;
+       soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL);
+       if (!soc_card_data)
+               return -ENOMEM;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
+       mach_priv = devm_kzalloc(&pdev->dev, sizeof(*mach_priv), GFP_KERNEL);
+       if (!mach_priv)
                return -ENOMEM;
 
+       soc_card_data->mach_priv = mach_priv;
+
+       adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
+       if (adsp_node) {
+               struct mtk_sof_priv *sof_priv;
+
+               sof_priv = devm_kzalloc(&pdev->dev, sizeof(*sof_priv), GFP_KERNEL);
+               if (!sof_priv) {
+                       ret = -ENOMEM;
+                       goto err_kzalloc;
+               }
+               sof_priv->conn_streams = g_sof_conn_streams;
+               sof_priv->num_streams = ARRAY_SIZE(g_sof_conn_streams);
+               sof_priv->sof_dai_link_fixup = mt8195_dai_link_fixup;
+               soc_card_data->sof_priv = sof_priv;
+               card->late_probe = mtk_sof_card_late_probe;
+               sof_on = 1;
+       }
+
        if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) {
-               ret = mt8195_dailink_parse_of(card, pdev->dev.of_node,
-                                             "mediatek,dai-link");
+               ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node,
+                                              "mediatek,dai-link",
+                                              mt8195_mt6359_dai_links,
+                                              ARRAY_SIZE(mt8195_mt6359_dai_links));
                if (ret) {
                        dev_dbg(&pdev->dev, "Parse dai-link fail\n");
-                       return -EINVAL;
+                       goto err_parse_of;
                }
        } else {
                if (!sof_on)
@@ -1533,13 +1405,10 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
                                         "mediatek,platform", 0);
        if (!platform_node) {
                dev_dbg(&pdev->dev, "Property 'platform' missing or invalid\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_platform_node;
        }
 
-       adsp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,adsp", 0);
-       if (adsp_node)
-               sof_on = 1;
-
        dp_node = of_parse_phandle(pdev->dev.of_node, "mediatek,dptx-codec", 0);
        hdmi_node = of_parse_phandle(pdev->dev.of_node,
                                     "mediatek,hdmi-codec", 0);
@@ -1612,17 +1481,17 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
                }
        }
 
-       if (sof_on)
-               card->late_probe = mt8195_mt6359_card_late_probe;
-
-       snd_soc_card_set_drvdata(card, priv);
+       snd_soc_card_set_drvdata(card, soc_card_data);
 
        ret = devm_snd_soc_register_card(&pdev->dev, card);
 
        of_node_put(platform_node);
-       of_node_put(adsp_node);
        of_node_put(dp_node);
        of_node_put(hdmi_node);
+err_kzalloc:
+err_parse_of:
+err_platform_node:
+       of_node_put(adsp_node);
        return ret;
 }
 
index 3776b073a3dbb090333bdb495ca128ec265f17c9..d0f0ada5f4bceaed57fc2c3ea86751ec3a039470 100644 (file)
@@ -192,7 +192,6 @@ static const struct snd_soc_component_driver aiu_acodec_ctrl_component = {
        .num_dapm_routes        = ARRAY_SIZE(aiu_acodec_ctrl_routes),
        .of_xlate_dai_name      = aiu_acodec_of_xlate_dai_name,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 #ifdef CONFIG_DEBUG_FS
        .debugfs_prefix         = "acodec",
 #endif
index 286ac4983d40c22589fdd713689a4ed6700bd34b..84c10956c24143c172469b25f8c5ae10dc452fe6 100644 (file)
@@ -139,7 +139,6 @@ static const struct snd_soc_component_driver aiu_hdmi_ctrl_component = {
        .num_dapm_routes        = ARRAY_SIZE(aiu_hdmi_ctrl_routes),
        .of_xlate_dai_name      = aiu_hdmi_of_xlate_dai_name,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 #ifdef CONFIG_DEBUG_FS
        .debugfs_prefix         = "hdmi",
 #endif
index 67729de41a73ef5981a0bb757a71817cfd41fd17..a0dd914c8ed13616fbcbc0828e36418cfd255391 100644 (file)
@@ -229,7 +229,7 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        unsigned int skew;
 
        /* Only CPU Master / Codec Slave supported ATM */
-       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP)
                return -EINVAL;
 
        if (inv == SND_SOC_DAIFMT_NB_IF ||
index 37f4bb3469b5c922399cf5abf27639cbd046886f..61f9d417fd608a5a93b25e6b6879aab8a70bc446 100644 (file)
@@ -161,6 +161,7 @@ static const struct snd_soc_component_driver axg_frddr_component_drv = {
        .hw_free                = axg_fifo_pcm_hw_free,
        .pointer                = axg_fifo_pcm_pointer,
        .trigger                = axg_fifo_pcm_trigger,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct axg_fifo_match_data axg_frddr_match_data = {
@@ -286,6 +287,7 @@ static const struct snd_soc_component_driver g12a_frddr_component_drv = {
        .hw_free                = axg_fifo_pcm_hw_free,
        .pointer                = axg_fifo_pcm_pointer,
        .trigger                = axg_fifo_pcm_trigger,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct axg_fifo_match_data g12a_frddr_match_data = {
@@ -356,6 +358,7 @@ static const struct snd_soc_component_driver sm1_frddr_component_drv = {
        .hw_free                = axg_fifo_pcm_hw_free,
        .pointer                = axg_fifo_pcm_pointer,
        .trigger                = axg_fifo_pcm_trigger,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct axg_fifo_match_data sm1_frddr_match_data = {
index 672e43a9729dcc8e82fc5eedcb5e5d4e9eddd7ea..88ac58272f95b2f953b23f483279b4f04841d7cd 100644 (file)
@@ -457,7 +457,9 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = {
        .remove         = axg_pdm_dai_remove,
 };
 
-static const struct snd_soc_component_driver axg_pdm_component_drv = {};
+static const struct snd_soc_component_driver axg_pdm_component_drv = {
+       .legacy_dai_naming = 1,
+};
 
 static const struct regmap_config axg_pdm_regmap_cfg = {
        .reg_bits       = 32,
index 4ba44e0d65d9f32c7fdf0936b7a90dcac40e8bfc..e2cc4c4be758612be58f9fd1f64f0d2fb5c01d4e 100644 (file)
@@ -390,6 +390,7 @@ static const struct snd_kcontrol_new axg_spdifin_controls[] = {
 static const struct snd_soc_component_driver axg_spdifin_component_drv = {
        .controls               = axg_spdifin_controls,
        .num_controls           = ARRAY_SIZE(axg_spdifin_controls),
+       .legacy_dai_naming      = 1,
 };
 
 static const struct regmap_config axg_spdifin_regmap_cfg = {
index 3960d082e14363917ec47c6a78e4dc3cb5522071..e8a12f15f3b4a89b6a00a747c675f01a2b105c32 100644 (file)
@@ -383,6 +383,7 @@ static const struct snd_soc_component_driver axg_spdifout_component_drv = {
        .dapm_routes            = axg_spdifout_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(axg_spdifout_dapm_routes),
        .set_bias_level         = axg_spdifout_set_bias_level,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct regmap_config axg_spdifout_regmap_cfg = {
index e076ced30025741af2ad13d0574ba1ab15ff6777..c040c83637e02adae6fce5cb673f09610a5a1bc3 100644 (file)
@@ -119,19 +119,19 @@ static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                if (!iface->mclk) {
                        dev_err(dai->dev, "cpu clock master: mclk missing\n");
                        return -ENODEV;
                }
                break;
 
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                break;
 
-       case SND_SOC_DAIFMT_CBS_CFM:
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BP_FC:
+       case SND_SOC_DAIFMT_BC_FP:
                dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
                fallthrough;
        default:
@@ -326,8 +326,8 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return ret;
 
-       if ((iface->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
-           SND_SOC_DAIFMT_CBS_CFS) {
+       if ((iface->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
+           SND_SOC_DAIFMT_BP_FP) {
                ret = axg_tdm_iface_set_sclk(dai, params);
                if (ret)
                        return ret;
index d6adf7edea41fbfe378f26faa92b83a76c7a3e24..e9208e74e9659a4ae9b90e9a8e897d9e000d8704 100644 (file)
@@ -182,6 +182,7 @@ static const struct snd_soc_component_driver axg_toddr_component_drv = {
        .hw_free                = axg_fifo_pcm_hw_free,
        .pointer                = axg_fifo_pcm_pointer,
        .trigger                = axg_fifo_pcm_trigger,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct axg_fifo_match_data axg_toddr_match_data = {
@@ -242,6 +243,7 @@ static const struct snd_soc_component_driver g12a_toddr_component_drv = {
        .hw_free                = axg_fifo_pcm_hw_free,
        .pointer                = axg_fifo_pcm_pointer,
        .trigger                = axg_fifo_pcm_trigger,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct axg_fifo_match_data g12a_toddr_match_data = {
@@ -312,6 +314,7 @@ static const struct snd_soc_component_driver sm1_toddr_component_drv = {
        .hw_free                = axg_fifo_pcm_hw_free,
        .pointer                = axg_fifo_pcm_pointer,
        .trigger                = axg_fifo_pcm_trigger,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct axg_fifo_match_data sm1_toddr_match_data = {
index 1dfee1396843c4694e8c9c5a791f47b48b9b640a..ddc667956cf5eec96e81dc77ea467d1d8d79eb74 100644 (file)
@@ -242,7 +242,6 @@ static const struct snd_soc_component_driver g12a_toacodec_component_drv = {
        .dapm_routes            = g12a_toacodec_routes,
        .num_dapm_routes        = ARRAY_SIZE(g12a_toacodec_routes),
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver sm1_toacodec_component_drv = {
@@ -254,7 +253,6 @@ static const struct snd_soc_component_driver sm1_toacodec_component_drv = {
        .dapm_routes            = g12a_toacodec_routes,
        .num_dapm_routes        = ARRAY_SIZE(g12a_toacodec_routes),
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config g12a_toacodec_regmap_cfg = {
index 6c99052feafd89048f167e19700761e47dcdbbe8..579a04ad4d1973b9583264c90e93e043a88a64d9 100644 (file)
@@ -226,7 +226,6 @@ static const struct snd_soc_component_driver g12a_tohdmitx_component_drv = {
        .dapm_routes            = g12a_tohdmitx_routes,
        .num_dapm_routes        = ARRAY_SIZE(g12a_tohdmitx_routes),
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config g12a_tohdmitx_regmap_cfg = {
index 2870cfad813ac7bf6ea0fe3c839f4d3384ebad5a..80c5ed196961de974f6ac6408b5c153bc757ebbf 100644 (file)
@@ -13,7 +13,7 @@
 static struct snd_soc_dapm_widget *
 meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
 {
-       struct snd_soc_dapm_path *p = NULL;
+       struct snd_soc_dapm_path *p;
        struct snd_soc_dapm_widget *in;
 
        snd_soc_dapm_widget_for_each_source_path(w, p) {
index a9b8c4e77d40587d1e31d14db57355a5f7c09fb3..9c6b4dac689320d1f6a1ce5ce81e518fbffee44d 100644 (file)
@@ -234,7 +234,6 @@ static const struct snd_soc_component_driver t9015_codec_driver = {
        .num_dapm_routes        = ARRAY_SIZE(t9015_dapm_routes),
        .suspend_bias_off       = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config t9015_regmap_config = {
index 7afe1a1acc568ee69112cb9da94c23226edd0a1c..ac761d3a01c05a657dcbf1bde9549ac4c94f4dbb 100644 (file)
@@ -358,8 +358,8 @@ static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
         * Saif internally could be slave when working on EXTMASTER mode.
         * We just hide this to machine driver.
         */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                if (saif->id == saif->master_id)
                        scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
                else
@@ -663,7 +663,8 @@ static struct snd_soc_dai_driver mxs_saif_dai = {
 };
 
 static const struct snd_soc_component_driver mxs_saif_component = {
-       .name           = "mxs-saif",
+       .name                   = "mxs-saif",
+       .legacy_dai_naming      = 1,
 };
 
 static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
index 9433cc92775527f7a03404df389b9cb4cdb13a2b..b791a2ba5ce51d01fc30c1ec3d0c9353ec48ff17 100644 (file)
@@ -91,13 +91,13 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
 
        /* set codec DAI configuration */
        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BC_FC);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-                       SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
+                       SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_BP_FP);
        if (ret < 0)
                return ret;
 
@@ -129,14 +129,14 @@ static int magician_capture_hw_params(struct snd_pcm_substream *substream,
        /* set codec DAI configuration */
        ret = snd_soc_dai_set_fmt(codec_dai,
                        SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS);
+                       SND_SOC_DAIFMT_BC_FC);
        if (ret < 0)
                return ret;
 
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai,
                        SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS);
+                       SND_SOC_DAIFMT_BP_FP);
        if (ret < 0)
                return ret;
 
index 7e39210a0b38459561a30b3e3252be4d55082117..fb5a4390443fe10509f2915c3151be3ba9163f36 100644 (file)
@@ -171,11 +171,11 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        sspa->sp   = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
        sspa->ctrl = 0;
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                sspa->sp |= SSPA_SP_MSL;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                break;
        default:
                return -EINVAL;
@@ -456,10 +456,11 @@ static int mmp_sspa_close(struct snd_soc_component *component,
 }
 
 static const struct snd_soc_component_driver mmp_sspa_component = {
-       .name           = "mmp-sspa",
-       .mmap           = mmp_pcm_mmap,
-       .open           = mmp_sspa_open,
-       .close          = mmp_sspa_close,
+       .name                   = "mmp-sspa",
+       .mmap                   = mmp_pcm_mmap,
+       .open                   = mmp_sspa_open,
+       .close                  = mmp_sspa_close,
+       .legacy_dai_naming      = 1,
 };
 
 static int asoc_mmp_sspa_probe(struct platform_device *pdev)
index 7f13a35e9cc145342855c4286cf1059edfaa58a1..430dd446321e503feefd49dcf771a9d2789b635f 100644 (file)
@@ -372,10 +372,10 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 {
        struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBM_CFS:
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_BC_FP:
+       case SND_SOC_DAIFMT_BP_FP:
                break;
        default:
                return -EINVAL;
@@ -432,14 +432,14 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
 
        sscr1 |= SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
 
-       switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                break;
        default:
                return -EINVAL;
@@ -484,9 +484,9 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
        pxa_ssp_write_reg(ssp, SSCR1, sscr1);
        pxa_ssp_write_reg(ssp, SSPSP, sspsp);
 
-       switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBM_CFS:
+       switch (priv->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_BC_FP:
                scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
                pxa_ssp_write_reg(ssp, SSCR1, scfr);
 
@@ -848,16 +848,17 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
 };
 
 static const struct snd_soc_component_driver pxa_ssp_component = {
-       .name           = "pxa-ssp",
-       .pcm_construct  = pxa2xx_soc_pcm_new,
-       .open           = pxa2xx_soc_pcm_open,
-       .close          = pxa2xx_soc_pcm_close,
-       .hw_params      = pxa2xx_soc_pcm_hw_params,
-       .prepare        = pxa2xx_soc_pcm_prepare,
-       .trigger        = pxa2xx_soc_pcm_trigger,
-       .pointer        = pxa2xx_soc_pcm_pointer,
-       .suspend        = pxa_ssp_suspend,
-       .resume         = pxa_ssp_resume,
+       .name                   = "pxa-ssp",
+       .pcm_construct          = pxa2xx_soc_pcm_new,
+       .open                   = pxa2xx_soc_pcm_open,
+       .close                  = pxa2xx_soc_pcm_close,
+       .hw_params              = pxa2xx_soc_pcm_hw_params,
+       .prepare                = pxa2xx_soc_pcm_prepare,
+       .trigger                = pxa2xx_soc_pcm_trigger,
+       .pointer                = pxa2xx_soc_pcm_pointer,
+       .suspend                = pxa_ssp_suspend,
+       .resume                 = pxa_ssp_resume,
+       .legacy_dai_naming      = 1,
 };
 
 #ifdef CONFIG_OF
index 746e6ec9198b0d5f7cf17940ce594882916a4893..3e4c7040367226eb47c59a09fc9676aed381bcc1 100644 (file)
@@ -129,11 +129,11 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                break;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                pxa_i2s.master = 1;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                pxa_i2s.master = 0;
                break;
        default:
@@ -355,16 +355,17 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver pxa_i2s_component = {
-       .name           = "pxa-i2s",
-       .pcm_construct  = pxa2xx_soc_pcm_new,
-       .open           = pxa2xx_soc_pcm_open,
-       .close          = pxa2xx_soc_pcm_close,
-       .hw_params      = pxa2xx_soc_pcm_hw_params,
-       .prepare        = pxa2xx_soc_pcm_prepare,
-       .trigger        = pxa2xx_soc_pcm_trigger,
-       .pointer        = pxa2xx_soc_pcm_pointer,
-       .suspend        = pxa2xx_soc_pcm_suspend,
-       .resume         = pxa2xx_soc_pcm_resume,
+       .name                   = "pxa-i2s",
+       .pcm_construct          = pxa2xx_soc_pcm_new,
+       .open                   = pxa2xx_soc_pcm_open,
+       .close                  = pxa2xx_soc_pcm_close,
+       .hw_params              = pxa2xx_soc_pcm_hw_params,
+       .prepare                = pxa2xx_soc_pcm_prepare,
+       .trigger                = pxa2xx_soc_pcm_trigger,
+       .pointer                = pxa2xx_soc_pcm_pointer,
+       .suspend                = pxa2xx_soc_pcm_suspend,
+       .resume                 = pxa2xx_soc_pcm_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
index b0a4f7ca27515284f35e4a31cd67f98ef0d3df2e..e54b8961112f3f9a9d636874af1f23a1f258a6ee 100644 (file)
@@ -172,7 +172,7 @@ static int msm8916_qdsp6_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 
-       snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+       snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
        return apq8016_dai_init(rtd, qdsp6_dai_get_lpass_id(cpu_dai));
 }
 
index 3efa133d1c6410abe461f3c4ca35d47976bd3cdb..abaf694ee9a3a13be626e405370ff407ba4ae3c8 100644 (file)
@@ -293,6 +293,7 @@ static struct lpass_variant apq8016_data = {
 
 static const struct of_device_id apq8016_lpass_cpu_device_id[] __maybe_unused = {
        { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
+       { .compatible = "qcom,apq8016-lpass-cpu", .data = &apq8016_data },
        {}
 };
 MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
index e6846ad2b5fa46a55b69880cd338dec798b3e014..8a56f38dc7e86849ac5e0a9541636684e0e9554e 100644 (file)
@@ -472,6 +472,7 @@ static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
        .name = "lpass-cpu",
        .of_xlate_dai_name = asoc_qcom_of_xlate_dai_name,
+       .legacy_dai_naming = 1,
 };
 
 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
@@ -1090,6 +1091,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
        dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
        if (dsp_of_node) {
                dev_err(dev, "DSP exists and holds audio resources\n");
+               of_node_put(dsp_of_node);
                return -EBUSY;
        }
 
@@ -1102,6 +1104,11 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
        if (!match || !match->data)
                return -EINVAL;
 
+       if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) {
+               dev_warn(dev, "%s compatible is deprecated\n",
+                        match->compatible);
+       }
+
        drvdata->variant = (struct lpass_variant *)match->data;
        variant = drvdata->variant;
 
index 98c0efa1d0fec9054510482c973a7054a667d543..01dac32c50fda60782fdb3eadf9a02bd72e60824 100644 (file)
@@ -732,10 +732,10 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
        intf_cfg->cfg.sd_line_idx = module->sd_line_idx;
 
        switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_INTERNAL;
                break;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                /* CPU is slave */
                intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_EXTERNAL;
                break;
index 72c5719f1d253ef535a4360e196e1baf832e98e5..1530e98df16564d683d7f81001e6e699fb53ee15 100644 (file)
@@ -90,7 +90,7 @@ struct q6adm_session_map_node_v5 {
 static struct q6copp *q6adm_find_copp(struct q6adm *adm, int port_idx,
                                  int copp_idx)
 {
-       struct q6copp *c = NULL;
+       struct q6copp *c;
        struct q6copp *ret = NULL;
        unsigned long flags;
 
@@ -180,7 +180,7 @@ static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data)
                        u32 status;
                        u16 copp_id;
                        u16 reserved;
-               } __packed * open = data->payload;
+               } __packed *open = data->payload;
 
                copp = q6adm_find_copp(adm, port_idx, copp_idx);
                if (!copp)
@@ -217,7 +217,7 @@ static struct q6copp *q6adm_alloc_copp(struct q6adm *adm, int port_idx)
        idx = find_first_zero_bit(&adm->copp_bitmap[port_idx],
                                  MAX_COPPS_PER_PORT);
 
-       if (idx > MAX_COPPS_PER_PORT)
+       if (idx >= MAX_COPPS_PER_PORT)
                return ERR_PTR(-EBUSY);
 
        c = kzalloc(sizeof(*c), GFP_ATOMIC);
@@ -299,7 +299,7 @@ static struct q6copp *q6adm_find_matching_copp(struct q6adm *adm,
                                               int channel_mode, int bit_width,
                                               int app_type)
 {
-       struct q6copp *c = NULL;
+       struct q6copp *c;
        struct q6copp *ret = NULL;
        unsigned long flags;
 
index 625724852a7fb9a478727849c134add3e08bb3c9..919e326b9462b39dc316506c8c2987b699f93c4b 100644 (file)
@@ -1328,11 +1328,11 @@ int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg)
        pcfg->i2s_cfg.bit_width = cfg->bit_width;
        pcfg->i2s_cfg.data_format = AFE_LINEAR_PCM_DATA;
 
-       switch (cfg->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_INTERNAL;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* CPU is slave */
                pcfg->i2s_cfg.ws_src = AFE_PORT_CONFIG_I2S_WS_SRC_EXTERNAL;
                break;
index b74b67720ef437176b3919672f171c9e0d068ad4..5fc8088e63c8107214a365df955a75825958b4e3 100644 (file)
@@ -1205,17 +1205,18 @@ static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
 };
 
 static const struct snd_soc_component_driver q6asm_fe_dai_component = {
-       .name           = DRV_NAME,
-       .open           = q6asm_dai_open,
-       .hw_params      = q6asm_dai_hw_params,
-       .close          = q6asm_dai_close,
-       .prepare        = q6asm_dai_prepare,
-       .trigger        = q6asm_dai_trigger,
-       .pointer        = q6asm_dai_pointer,
-       .pcm_construct  = q6asm_dai_pcm_new,
-       .compress_ops   = &q6asm_dai_compress_ops,
-       .dapm_widgets   = q6asm_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
+       .name                   = DRV_NAME,
+       .open                   = q6asm_dai_open,
+       .hw_params              = q6asm_dai_hw_params,
+       .close                  = q6asm_dai_close,
+       .prepare                = q6asm_dai_prepare,
+       .trigger                = q6asm_dai_trigger,
+       .pointer                = q6asm_dai_pointer,
+       .pcm_construct          = q6asm_dai_pcm_new,
+       .compress_ops           = &q6asm_dai_compress_ops,
+       .dapm_widgets           = q6asm_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(q6asm_dapm_widgets),
+       .legacy_dai_naming      = 1,
 };
 
 static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
index 9251d8548965658959f46ef59ab1520928f83725..195780f75d05d2864d8f18e2ddd4636ff7494060 100644 (file)
@@ -513,7 +513,7 @@ int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
                return 0;
        }
 
-       buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
+       buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC);
        if (!buf) {
                spin_unlock_irqrestore(&ac->lock, flags);
                return -ENOMEM;
index efccb5c0b3e00509b6b557dd68f178d7b0c1c542..f5f7c64b23a27ddeb1c6fa69c7d3ff61e54ba2f3 100644 (file)
@@ -155,7 +155,7 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
                }
 
                snd_soc_dai_set_fmt(codec_dai,
-                                   SND_SOC_DAIFMT_CBS_CFS |
+                                   SND_SOC_DAIFMT_BC_FC |
                                    SND_SOC_DAIFMT_NB_NF |
                                    SND_SOC_DAIFMT_I2S);
 
index 34cdb99d4ed6ac5733d3289b7532bf29a32de826..da7469a6a267d1e6b741ed3fca3f542b023240c7 100644 (file)
 #include "../codecs/rt5682s.h"
 #include "common.h"
 #include "lpass.h"
+#include "qdsp6/q6afe.h"
 
 #define DEFAULT_MCLK_RATE              19200000
 #define RT5682_PLL_FREQ (48000 * 512)
+#define MI2S_BCLK_RATE         1536000
 
 struct sc7280_snd_data {
        struct snd_soc_card card;
@@ -79,6 +81,7 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
        case MI2S_PRIMARY:
        case LPASS_CDC_DMA_RX0:
        case LPASS_CDC_DMA_TX3:
+       case TX_CODEC_DMA_TX_3:
                for_each_rtd_codec_dais(rtd, i, codec_dai) {
                        rval = snd_soc_component_set_jack(component, &pdata->hs_jack, NULL);
                        if (rval != 0 && rval != -ENOTSUPP) {
@@ -164,10 +167,14 @@ static int sc7280_init(struct snd_soc_pcm_runtime *rtd)
        switch (cpu_dai->id) {
        case MI2S_PRIMARY:
        case LPASS_CDC_DMA_TX3:
+       case TX_CODEC_DMA_TX_3:
                return sc7280_headset_init(rtd);
        case LPASS_CDC_DMA_RX0:
        case LPASS_CDC_DMA_VA_TX0:
        case MI2S_SECONDARY:
+       case RX_CODEC_DMA_RX_0:
+       case SECONDARY_MI2S_RX:
+       case VA_CODEC_DMA_TX_0:
                return 0;
        case LPASS_DP_RX:
                return sc7280_hdmi_init(rtd);
@@ -195,6 +202,10 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream,
        switch (cpu_dai->id) {
        case LPASS_CDC_DMA_TX3:
        case LPASS_CDC_DMA_RX0:
+       case RX_CODEC_DMA_RX_0:
+       case SECONDARY_MI2S_RX:
+       case TX_CODEC_DMA_TX_3:
+       case VA_CODEC_DMA_TX_0:
                for_each_rtd_codec_dais(rtd, i, codec_dai) {
                        sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
                        if (sruntime != ERR_PTR(-ENOTSUPP))
@@ -245,6 +256,9 @@ static int sc7280_snd_prepare(struct snd_pcm_substream *substream)
        switch (cpu_dai->id) {
        case LPASS_CDC_DMA_RX0:
        case LPASS_CDC_DMA_TX3:
+       case RX_CODEC_DMA_RX_0:
+       case TX_CODEC_DMA_TX_3:
+       case VA_CODEC_DMA_TX_0:
                return sc7280_snd_swr_prepare(substream);
        default:
                break;
@@ -263,6 +277,9 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream)
        switch (cpu_dai->id) {
        case LPASS_CDC_DMA_RX0:
        case LPASS_CDC_DMA_TX3:
+       case RX_CODEC_DMA_RX_0:
+       case TX_CODEC_DMA_TX_3:
+       case VA_CODEC_DMA_TX_0:
                if (sruntime && data->stream_prepared[cpu_dai->id]) {
                        sdw_disable_stream(sruntime);
                        sdw_deprepare_stream(sruntime);
@@ -291,6 +308,10 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
                                               SNDRV_PCM_STREAM_PLAYBACK);
                }
                break;
+       case SECONDARY_MI2S_RX:
+               snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+                                              0, SNDRV_PCM_STREAM_PLAYBACK);
+               break;
        default:
                break;
        }
@@ -298,14 +319,26 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
 
 static int sc7280_snd_startup(struct snd_pcm_substream *substream)
 {
+       unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
        int ret = 0;
 
        switch (cpu_dai->id) {
        case MI2S_PRIMARY:
                ret = sc7280_rt5682_init(rtd);
                break;
+       case SECONDARY_MI2S_RX:
+               codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+
+               snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+                       MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+
+               snd_soc_dai_set_fmt(cpu_dai, fmt);
+               snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+               break;
        default:
                break;
        }
index 61fda790f3756022e6ef8299d9368442e3c50d08..d8d35563af00fda216649acbc3e8d1e08bb98fec 100644 (file)
@@ -316,8 +316,8 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
 
 static int sdm845_snd_startup(struct snd_pcm_substream *substream)
 {
-       unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
-       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+       unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
+       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_card *card = rtd->card;
        struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
@@ -356,7 +356,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
                snd_soc_dai_set_sysclk(cpu_dai,
                        Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
                        MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
-               snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+               snd_soc_dai_set_fmt(cpu_dai, fmt);
 
 
                break;
index 6e1184c8b672a68bd7bce6513ff5ab4a51023ad6..ce4a5713386a3681f6b17ce7ad3c59436554323c 100644 (file)
@@ -96,8 +96,8 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 
 static int sm8250_snd_startup(struct snd_pcm_substream *substream)
 {
-       unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
-       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+       unsigned int fmt = SND_SOC_DAIFMT_BP_FP;
+       unsigned int codec_dai_fmt = SND_SOC_DAIFMT_BC_FC;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
index bcdeddeba80c95d3d7df876acdaf3aaaaefcf12b..0c6bd9a019dbe8b333faee825bac211ff930f38d 100644 (file)
@@ -169,7 +169,7 @@ static struct snd_soc_card snd_soc_card_rk = {
 
 static int snd_rk_mc_probe(struct platform_device *pdev)
 {
-       int ret = 0;
+       int ret;
        struct snd_soc_card *card = &snd_soc_card_rk;
        struct device_node *np = pdev->dev.of_node;
        struct rk_drvdata *machine;
@@ -253,7 +253,7 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
                return dev_err_probe(&pdev->dev, ret,
                                     "Soc register card failed\n");
 
-       return ret;
+       return 0;
 }
 
 static const struct of_device_id rockchip_sound_of_match[] = {
index 4ce5d257938753a1818958a0414359a789d28027..f5f3540a9e18613e78522a0480ea6e496ccb3d44 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
 #include <linux/clk.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/spinlock.h>
@@ -54,8 +55,38 @@ struct rk_i2s_dev {
        const struct rk_i2s_pins *pins;
        unsigned int bclk_ratio;
        spinlock_t lock; /* tx/rx lock */
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *bclk_on;
+       struct pinctrl_state *bclk_off;
 };
 
+static int i2s_pinctrl_select_bclk_on(struct rk_i2s_dev *i2s)
+{
+       int ret = 0;
+
+       if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_on))
+               ret = pinctrl_select_state(i2s->pinctrl, i2s->bclk_on);
+
+       if (ret)
+               dev_err(i2s->dev, "bclk enable failed %d\n", ret);
+
+       return ret;
+}
+
+static int i2s_pinctrl_select_bclk_off(struct rk_i2s_dev *i2s)
+{
+
+       int ret = 0;
+
+       if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_off))
+               ret = pinctrl_select_state(i2s->pinctrl, i2s->bclk_off);
+
+       if (ret)
+               dev_err(i2s->dev, "bclk disable failed %d\n", ret);
+
+       return ret;
+}
+
 static int i2s_runtime_suspend(struct device *dev)
 {
        struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
@@ -92,39 +123,46 @@ static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
        return snd_soc_dai_get_drvdata(dai);
 }
 
-static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
+static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 {
        unsigned int val = 0;
        int retry = 10;
+       int ret = 0;
 
        spin_lock(&i2s->lock);
        if (on) {
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
-                                  I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
-
-               regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+                                        I2S_DMACR_TDE_ENABLE,
+                                        I2S_DMACR_TDE_ENABLE);
+               if (ret < 0)
+                       goto end;
+               ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+                                        I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                                        I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+               if (ret < 0)
+                       goto end;
                i2s->tx_start = true;
        } else {
                i2s->tx_start = false;
 
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
-                                  I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+                                        I2S_DMACR_TDE_ENABLE,
+                                        I2S_DMACR_TDE_DISABLE);
+               if (ret < 0)
+                       goto end;
 
                if (!i2s->rx_start) {
-                       regmap_update_bits(i2s->regmap, I2S_XFER,
-                                          I2S_XFER_TXS_START |
-                                          I2S_XFER_RXS_START,
-                                          I2S_XFER_TXS_STOP |
-                                          I2S_XFER_RXS_STOP);
-
+                       ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+                                                I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                                                I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+                       if (ret < 0)
+                               goto end;
                        udelay(150);
-                       regmap_update_bits(i2s->regmap, I2S_CLR,
-                                          I2S_CLR_TXC | I2S_CLR_RXC,
-                                          I2S_CLR_TXC | I2S_CLR_RXC);
-
+                       ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+                                                I2S_CLR_TXC | I2S_CLR_RXC,
+                                                I2S_CLR_TXC | I2S_CLR_RXC);
+                       if (ret < 0)
+                               goto end;
                        regmap_read(i2s->regmap, I2S_CLR, &val);
 
                        /* Should wait for clear operation to finish */
@@ -133,61 +171,80 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
                                retry--;
                                if (!retry) {
                                        dev_warn(i2s->dev, "fail to clear\n");
+                                       ret = -EBUSY;
                                        break;
                                }
                        }
                }
        }
+end:
        spin_unlock(&i2s->lock);
+       if (ret < 0)
+               dev_err(i2s->dev, "lrclk update failed\n");
+
+       return ret;
 }
 
-static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
+static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 {
        unsigned int val = 0;
        int retry = 10;
+       int ret = 0;
 
        spin_lock(&i2s->lock);
        if (on) {
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
-                                  I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
-
-               regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+                                        I2S_DMACR_RDE_ENABLE,
+                                        I2S_DMACR_RDE_ENABLE);
+               if (ret < 0)
+                       goto end;
+
+               ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+                                        I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                                        I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+               if (ret < 0)
+                       goto end;
                i2s->rx_start = true;
        } else {
                i2s->rx_start = false;
 
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
-                                  I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+                                        I2S_DMACR_RDE_ENABLE,
+                                        I2S_DMACR_RDE_DISABLE);
+               if (ret < 0)
+                       goto end;
 
                if (!i2s->tx_start) {
-                       regmap_update_bits(i2s->regmap, I2S_XFER,
-                                          I2S_XFER_TXS_START |
-                                          I2S_XFER_RXS_START,
-                                          I2S_XFER_TXS_STOP |
-                                          I2S_XFER_RXS_STOP);
-
+                       ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+                                                I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                                                I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+                       if (ret < 0)
+                               goto end;
                        udelay(150);
-                       regmap_update_bits(i2s->regmap, I2S_CLR,
-                                          I2S_CLR_TXC | I2S_CLR_RXC,
-                                          I2S_CLR_TXC | I2S_CLR_RXC);
-
+                       ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+                                                I2S_CLR_TXC | I2S_CLR_RXC,
+                                                I2S_CLR_TXC | I2S_CLR_RXC);
+                       if (ret < 0)
+                               goto end;
                        regmap_read(i2s->regmap, I2S_CLR, &val);
-
                        /* Should wait for clear operation to finish */
                        while (val) {
                                regmap_read(i2s->regmap, I2S_CLR, &val);
                                retry--;
                                if (!retry) {
                                        dev_warn(i2s->dev, "fail to clear\n");
+                                       ret = -EBUSY;
                                        break;
                                }
                        }
                }
        }
+end:
        spin_unlock(&i2s->lock);
+       if (ret < 0)
+               dev_err(i2s->dev, "lrclk update failed\n");
+
+       return ret;
 }
 
 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
@@ -199,13 +256,13 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 
        pm_runtime_get_sync(cpu_dai->dev);
        mask = I2S_CKR_MSS_MASK;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* Set source clock in Master mode */
                val = I2S_CKR_MSS_MASTER;
                i2s->is_master_mode = true;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                val = I2S_CKR_MSS_SLAVE;
                i2s->is_master_mode = false;
                break;
@@ -425,17 +482,25 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       rockchip_snd_rxctrl(i2s, 1);
+                       ret = rockchip_snd_rxctrl(i2s, 1);
                else
-                       rockchip_snd_txctrl(i2s, 1);
+                       ret = rockchip_snd_txctrl(i2s, 1);
+               if (ret < 0)
+                       return ret;
+               i2s_pinctrl_select_bclk_on(i2s);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       rockchip_snd_rxctrl(i2s, 0);
-               else
-                       rockchip_snd_txctrl(i2s, 0);
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       if (!i2s->tx_start)
+                               i2s_pinctrl_select_bclk_off(i2s);
+                       ret = rockchip_snd_rxctrl(i2s, 0);
+               } else {
+                       if (!i2s->rx_start)
+                               i2s_pinctrl_select_bclk_off(i2s);
+                       ret = rockchip_snd_txctrl(i2s, 0);
+               }
                break;
        default:
                ret = -EINVAL;
@@ -498,6 +563,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
 
 static const struct snd_soc_component_driver rockchip_i2s_component = {
        .name = DRV_NAME,
+       .legacy_dai_naming = 1,
 };
 
 static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg)
@@ -736,6 +802,22 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
        }
 
        i2s->bclk_ratio = 64;
+       i2s->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (!IS_ERR(i2s->pinctrl)) {
+               i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl, "bclk_on");
+               if (!IS_ERR_OR_NULL(i2s->bclk_on)) {
+                       i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl, "bclk_off");
+                       if (IS_ERR_OR_NULL(i2s->bclk_off)) {
+                               dev_err(&pdev->dev, "failed to find i2s bclk_off\n");
+                               ret = -EINVAL;
+                               goto err_clk;
+                       }
+               }
+       } else {
+               dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n");
+       }
+
+       i2s_pinctrl_select_bclk_off(i2s);
 
        dev_set_drvdata(&pdev->dev, i2s);
 
index 98700e75b82a1fbce1877d884672f2bec5eb1331..2550bd2a5e78c547bb358fae4ca969f2f638143f 100644 (file)
@@ -404,19 +404,17 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,
        int ret;
        bool is_tdm = i2s_tdm->tdm_mode;
 
-       ret = pm_runtime_get_sync(cpu_dai->dev);
-       if (ret < 0 && ret != -EACCES) {
-               pm_runtime_put_noidle(cpu_dai->dev);
+       ret = pm_runtime_resume_and_get(cpu_dai->dev);
+       if (ret < 0 && ret != -EACCES)
                return ret;
-       }
 
        mask = I2S_CKR_MSS_MASK;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                val = I2S_CKR_MSS_MASTER;
                i2s_tdm->is_master_mode = true;
                break;
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                val = I2S_CKR_MSS_SLAVE;
                i2s_tdm->is_master_mode = false;
                break;
@@ -1120,6 +1118,7 @@ static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
 
 static const struct snd_soc_component_driver rockchip_i2s_tdm_component = {
        .name = DRV_NAME,
+       .legacy_dai_naming = 1,
 };
 
 static bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg)
index 64d9891b6434faa61d759246ef6e90bb3e341826..a7549f8272359fcc920d9459b302d01d78008d4b 100644 (file)
@@ -405,6 +405,7 @@ static struct snd_soc_dai_driver rockchip_pdm_dai = {
 
 static const struct snd_soc_component_driver rockchip_pdm_component = {
        .name = "rockchip-pdm",
+       .legacy_dai_naming = 1,
 };
 
 static int rockchip_pdm_runtime_suspend(struct device *dev)
@@ -688,11 +689,9 @@ static int rockchip_pdm_resume(struct device *dev)
        struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
        int ret;
 
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               pm_runtime_put(dev);
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
                return ret;
-       }
 
        ret = regcache_sync(pdm->regmap);
 
index d027ca4b17964d24c0ea67c01c551b54cf3b3808..8bef572d3cbc1278e30c8660ca4d33150a8906d7 100644 (file)
@@ -225,6 +225,7 @@ static struct snd_soc_dai_driver rk_spdif_dai = {
 
 static const struct snd_soc_component_driver rk_spdif_component = {
        .name = "rockchip-spdif",
+       .legacy_dai_naming = 1,
 };
 
 static bool rk_spdif_wr_reg(struct device *dev, unsigned int reg)
index a2221ebb1b6ab5bed755fc1a402e0e39fc80185f..2a61e620cd3b0cc49dbd5148fe1637d35382ee57 100644 (file)
@@ -33,7 +33,8 @@ config SND_SAMSUNG_I2S
 
 config SND_SOC_SAMSUNG_NEO1973_WM8753
        tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
-       depends on MACH_NEO1973_GTA02
+       depends on MACH_NEO1973_GTA02 || COMPILE_TEST
+       depends on SND_SOC_I2C_AND_SPI
        select SND_S3C24XX_I2S
        select SND_SOC_WM8753
        select SND_SOC_BT_SCO
@@ -43,7 +44,8 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
 
 config SND_SOC_SAMSUNG_JIVE_WM8750
        tristate "SoC I2S Audio support for Jive"
-       depends on MACH_JIVE && I2C
+       depends on MACH_JIVE && I2C || COMPILE_TEST && ARM
+       depends on SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8750
        select SND_S3C2412_SOC_I2S
        help
@@ -69,7 +71,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
 
 config SND_SOC_SAMSUNG_S3C24XX_UDA134X
        tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
-       depends on ARCH_S3C24XX
+       depends on ARCH_S3C24XX || COMPILE_TEST
        select SND_S3C24XX_I2S
        select SND_SOC_L3
        select SND_SOC_UDA134X
@@ -81,21 +83,24 @@ config SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
        tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-       depends on ARCH_S3C24XX && I2C
+       depends on ARCH_S3C24XX || COMPILE_TEST
+       depends on I2C
        select SND_S3C24XX_I2S
        select SND_SOC_TLV320AIC23_I2C
        select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
        tristate "SoC I2S Audio support for Simtec Hermes board"
-       depends on ARCH_S3C24XX && I2C
+       depends on ARCH_S3C24XX || COMPILE_TEST
+       depends on I2C
        select SND_S3C24XX_I2S
        select SND_SOC_TLV320AIC3X
        select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_H1940_UDA1380
        tristate "Audio support for the HP iPAQ H1940"
-       depends on ARCH_H1940 && I2C
+       depends on ARCH_H1940 || COMPILE_TEST
+       depends on I2C
        select SND_S3C24XX_I2S
        select SND_SOC_UDA1380
        help
@@ -103,7 +108,8 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
 
 config SND_SOC_SAMSUNG_RX1950_UDA1380
        tristate "Audio support for the HP iPAQ RX1950"
-       depends on MACH_RX1950 && I2C
+       depends on MACH_RX1950 || COMPILE_TEST
+       depends on I2C
        select SND_S3C24XX_I2S
        select SND_SOC_UDA1380
        help
index bb0cf4244e00726517d2a9e213b81649cf70fa38..e7d52d27132ea1bf160b10f27230a383026845fc 100644 (file)
@@ -432,7 +432,6 @@ static const struct snd_soc_component_driver aries_component = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver aries_ext_dai[] = {
@@ -628,8 +627,10 @@ static int aries_audio_probe(struct platform_device *pdev)
                return -EINVAL;
 
        codec = of_get_child_by_name(dev->of_node, "codec");
-       if (!codec)
-               return -EINVAL;
+       if (!codec) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        for_each_card_prelinks(card, i, dai_link) {
                dai_link->codecs->of_node = of_parse_phandle(codec,
index 907266aee839f3da5fcbe4694d78510c527a056c..fa45a54ab18f9f113d0fe3f6438078df76e7f098 100644 (file)
@@ -8,7 +8,7 @@
 // Based on version from Arnaud Patard <arnaud.patard@rtp-net.org>
 
 #include <linux/types.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 
 #include <sound/soc.h>
index 70c827162be4d374dd26b6ac0122c6d3f67e78d5..9505200f3d11b45abd7bf4fe2db12f9c8ac8ca33 100644 (file)
@@ -671,11 +671,11 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                tmp |= mod_slave;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                /*
                 * Set default source clock in Master mode, only when the
                 * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any
@@ -1143,6 +1143,8 @@ static const struct snd_soc_component_driver samsung_i2s_component = {
 
        .suspend = i2s_suspend,
        .resume = i2s_resume,
+
+       .legacy_dai_naming = 1,
 };
 
 #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
index c98b68567a89d379b2bbe44e6324e875065c2c5c..e9f2334028bfc2bc865c97df63bf8d9c546879c4 100644 (file)
@@ -344,7 +344,7 @@ static int neo1973_probe(struct platform_device *pdev)
        return devm_snd_soc_register_card(dev, &neo1973);
 }
 
-struct platform_driver neo1973_audio = {
+static struct platform_driver neo1973_audio = {
        .driver = {
                .name = "neo1973-audio",
                .pm = &snd_soc_pm_ops,
index 4c4dfde0568febe454840bd6decbcb6f2ee35219..e859252ae5e6eb87b29c0a239a4590ca5f43b53f 100644 (file)
@@ -340,8 +340,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
                goto exit;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* Nothing to do, Master by default */
                break;
        default:
@@ -480,7 +480,8 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = {
 };
 
 static const struct snd_soc_component_driver s3c_pcm_component = {
-       .name           = "s3c-pcm",
+       .name                   = "s3c-pcm",
+       .legacy_dai_naming      = 1,
 };
 
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
index ff3acc94a454ca6bb37a4420ba951c6669f2b3ce..abf28321f7d7667b91d786906ccff05db763444f 100644 (file)
@@ -128,7 +128,7 @@ static int rx1950_startup(struct snd_pcm_substream *substream)
                                        &hw_rates);
 }
 
-struct gpio_desc *gpiod_speaker_power;
+static struct gpio_desc *gpiod_speaker_power;
 
 static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
                                struct snd_kcontrol *kcontrol, int event)
@@ -228,7 +228,7 @@ static int rx1950_probe(struct platform_device *pdev)
        return devm_snd_soc_register_card(dev, &rx1950_asoc);
 }
 
-struct platform_driver rx1950_audio = {
+static struct platform_driver rx1950_audio = {
        .driver = {
                .name = "rx1950-audio",
                .pm = &snd_soc_pm_ops,
index de66cc422e6eae5e22a75a87155d823a4acf808e..2b221cb0ed03aedcf827509bd267f99361fca76f 100644 (file)
 #include "regs-i2s-v2.h"
 #include "s3c-i2s-v2.h"
 
-#undef S3C_IIS_V2_SUPPORTED
-
-#if defined(CONFIG_CPU_S3C2412) \
-       || defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210)
-#define S3C_IIS_V2_SUPPORTED
-#endif
-
-#ifndef S3C_IIS_V2_SUPPORTED
-#error Unsupported CPU model
-#endif
-
 #define S3C2412_I2S_DEBUG_CON 0
 
 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
@@ -252,12 +241,12 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        iismod = readl(i2s->regs + S3C2412_IISMOD);
        pr_debug("hw_params r: IISMOD: %x \n", iismod);
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                i2s->master = 0;
                iismod |= S3C2412_IISMOD_SLAVE;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                i2s->master = 1;
                iismod &= ~S3C2412_IISMOD_SLAVE;
                break;
index ec1c6f9d76ac755652f45e5f8a2c89b3daff681f..0579a352961cca2486f69f81c3189f996ea05c83 100644 (file)
@@ -192,9 +192,10 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver s3c2412_i2s_component = {
-       .name           = "s3c2412-i2s",
-       .suspend        = s3c2412_i2s_suspend,
-       .resume         = s3c2412_i2s_resume,
+       .name                   = "s3c2412-i2s",
+       .suspend                = s3c2412_i2s_suspend,
+       .resume                 = s3c2412_i2s_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static int s3c2412_iis_dev_probe(struct platform_device *pdev)
index 0f46304eaa4f309dc03d3e5befaebe3e6375a224..7b7bbe007acd31510ebc3f3f3441e5845c05e694 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 
 #include <sound/soc.h>
@@ -169,11 +168,11 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
        pr_debug("hw_params r: IISMOD: %x \n", iismod);
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                iismod |= S3C2410_IISMOD_SLAVE;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                iismod &= ~S3C2410_IISMOD_SLAVE;
                break;
        default:
@@ -415,9 +414,10 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver s3c24xx_i2s_component = {
-       .name           = "s3c24xx-i2s",
-       .suspend        = s3c24xx_i2s_suspend,
-       .resume         = s3c24xx_i2s_resume,
+       .name                   = "s3c24xx-i2s",
+       .suspend                = s3c24xx_i2s_suspend,
+       .resume                 = s3c24xx_i2s_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
index 02372109c251ec02092b811ab9d4358cf21b9f86..da342da038804cf3b19053317f28ea7eac174e14 100644 (file)
@@ -216,7 +216,7 @@ static int snow_probe(struct platform_device *pdev)
                return dev_err_probe(&pdev->dev, ret,
                                     "snd_soc_register_card failed\n");
 
-       return ret;
+       return 0;
 }
 
 static int snow_remove(struct platform_device *pdev)
index 47b6d19e43ffb648554875b7520e272c31910aaa..7d815e237e5c6f92859d2b302d93410403ef72ec 100644 (file)
@@ -352,9 +352,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = {
 };
 
 static const struct snd_soc_component_driver samsung_spdif_component = {
-       .name           = "samsung-spdif",
-       .suspend        = spdif_suspend,
-       .resume         = spdif_resume,
+       .name                   = "samsung-spdif",
+       .suspend                = spdif_suspend,
+       .resume                 = spdif_resume,
+       .legacy_dai_naming      = 1,
 };
 
 static int spdif_probe(struct platform_device *pdev)
index e9a1eb6bdf66aeba24fd798f711201d6b5133ee4..f3edc2e3d9d7c492391e2c1f8eb682b87feeb410 100644 (file)
@@ -1646,10 +1646,10 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        int ret;
 
        /* set clock master audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                fsi->clk_master = 1; /* cpu is master */
                break;
        default:
index 475fc984f8c51d87a514dea3bd4ae10d5526328c..46d145cbaf29708e26cf03ef1a1a5f8d56897037 100644 (file)
@@ -307,7 +307,8 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = {
 };
 
 static const struct snd_soc_component_driver sh4_hac_component = {
-       .name           = "sh4-hac",
+       .name                   = "sh4-hac",
+       .legacy_dai_naming      = 1,
 };
 
 static int hac_soc_platform_probe(struct platform_device *pdev)
index eb762ab94d3eddfcda392491c2141e5bafc04de5..7e380d71b0f8857029936663e0d2562124caca39 100644 (file)
@@ -756,10 +756,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        /* set clock master for audio interface */
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBP_CFP:
+       case SND_SOC_DAIFMT_BC_FC:
                rdai->clk_master = 0;
                break;
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                rdai->clk_master = 1; /* cpu is master */
                break;
        default:
@@ -1813,11 +1813,12 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
  *             snd_soc_component
  */
 static const struct snd_soc_component_driver rsnd_soc_component = {
-       .name           = "rsnd",
-       .probe          = rsnd_debugfs_probe,
-       .hw_params      = rsnd_hw_params,
-       .hw_free        = rsnd_hw_free,
-       .pointer        = rsnd_pointer,
+       .name                   = "rsnd",
+       .probe                  = rsnd_debugfs_probe,
+       .hw_params              = rsnd_hw_params,
+       .hw_free                = rsnd_hw_free,
+       .pointer                = rsnd_pointer,
+       .legacy_dai_naming      = 1,
 };
 
 static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
@@ -1968,19 +1969,26 @@ static int rsnd_remove(struct platform_device *pdev)
                rsnd_cmd_remove,
                rsnd_adg_remove,
        };
-       int ret = 0, i;
+       int i;
 
        pm_runtime_disable(&pdev->dev);
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret |= rsnd_dai_call(remove, &rdai->playback, priv);
-               ret |= rsnd_dai_call(remove, &rdai->capture, priv);
+               int ret;
+
+               ret = rsnd_dai_call(remove, &rdai->playback, priv);
+               if (ret)
+                       dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i);
+
+               ret = rsnd_dai_call(remove, &rdai->capture, priv);
+               if (ret)
+                       dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i);
        }
 
        for (i = 0; i < ARRAY_SIZE(remove_func); i++)
                remove_func[i](priv);
 
-       return ret;
+       return 0;
 }
 
 static int __maybe_unused rsnd_suspend(struct device *dev)
index 4b8a63e336c778bbd269dcfca4a751a98f76fb18..281bc20d4c5d0c07dced62b6b356b66dd5c052f1 100644 (file)
@@ -67,6 +67,8 @@ static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
                shift  = 1;
                offset = 1;
                break;
+       default:
+               return;
        }
 
        for (i = 0; i < 4; i++) {
@@ -417,6 +419,7 @@ static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
        .name           = SSIU_NAME,
        .dma_req        = rsnd_ssiu_dma_req,
        .init           = rsnd_ssiu_init_gen2,
+       .quit           = rsnd_ssiu_quit,
        .start          = rsnd_ssiu_start_gen2,
        .stop           = rsnd_ssiu_stop_gen2,
        .get_status     = rsnd_ssiu_get_status,
index e392de7a262ef54c36f562145b103f1b03cb7e8a..0d0594a0e4f6cdb986127e7b77e1bb1a53617900 100644 (file)
@@ -767,7 +767,7 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
-       case SND_SOC_DAIFMT_CBC_CFC:
+       case SND_SOC_DAIFMT_BP_FP:
                break;
        default:
                dev_err(ssi->dev, "Codec should be clk and frame consumer\n");
@@ -906,10 +906,11 @@ static struct snd_soc_dai_driver rz_ssi_soc_dai[] = {
 };
 
 static const struct snd_soc_component_driver rz_ssi_soc_component = {
-       .name           = "rz-ssi",
-       .open           = rz_ssi_pcm_open,
-       .pointer        = rz_ssi_pcm_pointer,
-       .pcm_construct  = rz_ssi_pcm_new,
+       .name                   = "rz-ssi",
+       .open                   = rz_ssi_pcm_open,
+       .pointer                = rz_ssi_pcm_pointer,
+       .pcm_construct          = rz_ssi_pcm_new,
+       .legacy_dai_naming      = 1,
 };
 
 static int rz_ssi_probe(struct platform_device *pdev)
index 0a8a3c314a73d774fcaa77180aa00dc44b179b3c..f15ff36e793455f27222b4313a0f7ce217dd77c6 100644 (file)
@@ -540,13 +540,14 @@ static void siu_pcm_free(struct snd_soc_component *component,
 }
 
 const struct snd_soc_component_driver siu_component = {
-       .name           = DRV_NAME,
-       .open           = siu_pcm_open,
-       .close          = siu_pcm_close,
-       .prepare        = siu_pcm_prepare,
-       .trigger        = siu_pcm_trigger,
-       .pointer        = siu_pcm_pointer_dma,
-       .pcm_construct  = siu_pcm_new,
-       .pcm_destruct   = siu_pcm_free,
+       .name                   = DRV_NAME,
+       .open                   = siu_pcm_open,
+       .close                  = siu_pcm_close,
+       .prepare                = siu_pcm_prepare,
+       .trigger                = siu_pcm_trigger,
+       .pointer                = siu_pcm_pointer_dma,
+       .pcm_construct          = siu_pcm_new,
+       .pcm_destruct           = siu_pcm_free,
+       .legacy_dai_naming      = 1,
 };
 EXPORT_SYMBOL_GPL(siu_component);
index 15b01bcefca5c025ea26b119f08ca6ab0566b148..96cf523c227343e330ed291268e6d987f09d171c 100644 (file)
@@ -291,16 +291,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_BP_FC:
                ssicr |= CR_SCK_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                ssicr |= CR_SWS_MASTER;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
                break;
        default:
@@ -377,7 +377,8 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = {
 };
 
 static const struct snd_soc_component_driver sh4_ssi_component = {
-       .name           = "sh4-ssi",
+       .name                   = "sh4-ssi",
+       .legacy_dai_naming      = 1,
 };
 
 static int sh4_soc_dai_probe(struct platform_device *pdev)
index 4158f5aacfd373a95e9d03f6f2700d50acd635dc..285ab4c9c7168314ae34bead44a5229bc5d8b96b 100644 (file)
@@ -197,6 +197,12 @@ int snd_soc_card_late_probe(struct snd_soc_card *card)
        return 0;
 }
 
+void snd_soc_card_fixup_controls(struct snd_soc_card *card)
+{
+       if (card->fixup_controls)
+               card->fixup_controls(card);
+}
+
 int snd_soc_card_remove(struct snd_soc_card *card)
 {
        int ret = 0;
index 9574f86dd4de29946f2a7e791d84ec750ae514b8..e824ff1a9fc0961e9ef35f2ff6cd11c0b022c5c8 100644 (file)
@@ -1214,7 +1214,6 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
 {
        struct snd_soc_dai *cpu_dai;
        struct snd_soc_dai *codec_dai;
-       unsigned int inv_dai_fmt;
        unsigned int i;
        int ret;
 
@@ -1227,18 +1226,11 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
                        return ret;
        }
 
-       /*
-        * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
-        */
-       inv_dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
+       /* Flip the polarity for the "CPU" end of link */
+       dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
 
        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-               unsigned int fmt = dai_fmt;
-
-               if (snd_soc_component_is_codec(cpu_dai->component))
-                       fmt = inv_dai_fmt;
-
-               ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+               ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
                if (ret != 0 && ret != -ENOTSUPP)
                        return ret;
        }
@@ -2074,6 +2066,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
                goto probe_end;
 
        snd_soc_dapm_new_widgets(card);
+       snd_soc_card_fixup_controls(card);
 
        ret = snd_card_register(card->snd_card);
        if (ret < 0) {
@@ -2326,14 +2319,12 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card);
  * @card: Card to unregister
  *
  */
-int snd_soc_unregister_card(struct snd_soc_card *card)
+void snd_soc_unregister_card(struct snd_soc_card *card)
 {
        mutex_lock(&client_mutex);
        snd_soc_unbind_card(card, true);
        mutex_unlock(&client_mutex);
        dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
 
@@ -2497,7 +2488,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
 
        for (i = 0; i < count; i++) {
                dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
-                                          !component->driver->non_legacy_dai_naming);
+                                          component->driver->legacy_dai_naming);
                if (dai == NULL) {
                        ret = -ENOMEM;
                        goto err;
@@ -3312,6 +3303,61 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
 
+static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
+{
+       if (component->of_node) {
+               of_node_put(component->of_node);
+               component->of_node = NULL;
+       }
+}
+
+static int __snd_soc_of_get_dai_link_component_alloc(
+       struct device *dev, struct device_node *of_node,
+       struct snd_soc_dai_link_component **ret_component,
+       int *ret_num)
+{
+       struct snd_soc_dai_link_component *component;
+       int num;
+
+       /* Count the number of CPUs/CODECs */
+       num = of_count_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells");
+       if (num <= 0) {
+               if (num == -ENOENT)
+                       dev_err(dev, "No 'sound-dai' property\n");
+               else
+                       dev_err(dev, "Bad phandle in 'sound-dai'\n");
+               return num;
+       }
+       component = devm_kcalloc(dev, num, sizeof(*component), GFP_KERNEL);
+       if (!component)
+               return -ENOMEM;
+
+       *ret_component  = component;
+       *ret_num        = num;
+
+       return 0;
+}
+
+static int __snd_soc_of_get_dai_link_component_parse(
+       struct device_node *of_node,
+       struct snd_soc_dai_link_component *component, int index)
+{
+       struct of_phandle_args args;
+       int ret;
+
+       ret = of_parse_phandle_with_args(of_node, "sound-dai", "#sound-dai-cells",
+                                        index, &args);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_get_dai_name(&args, &component->dai_name);
+       if (ret < 0)
+               return ret;
+
+       component->of_node = args.np;
+       return 0;
+}
+
 /*
  * snd_soc_of_put_dai_link_codecs - Dereference device nodes in the codecs array
  * @dai_link: DAI link
@@ -3323,12 +3369,8 @@ void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link)
        struct snd_soc_dai_link_component *component;
        int index;
 
-       for_each_link_codecs(dai_link, index, component) {
-               if (!component->of_node)
-                       break;
-               of_node_put(component->of_node);
-               component->of_node = NULL;
-       }
+       for_each_link_codecs(dai_link, index, component)
+               __snd_soc_of_put_component(component);
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_codecs);
 
@@ -3350,41 +3392,19 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev,
                                   struct device_node *of_node,
                                   struct snd_soc_dai_link *dai_link)
 {
-       struct of_phandle_args args;
        struct snd_soc_dai_link_component *component;
-       char *name;
-       int index, num_codecs, ret;
-
-       /* Count the number of CODECs */
-       name = "sound-dai";
-       num_codecs = of_count_phandle_with_args(of_node, name,
-                                               "#sound-dai-cells");
-       if (num_codecs <= 0) {
-               if (num_codecs == -ENOENT)
-                       dev_err(dev, "No 'sound-dai' property\n");
-               else
-                       dev_err(dev, "Bad phandle in 'sound-dai'\n");
-               return num_codecs;
-       }
-       component = devm_kcalloc(dev,
-                                num_codecs, sizeof(*component),
-                                GFP_KERNEL);
-       if (!component)
-               return -ENOMEM;
-       dai_link->codecs = component;
-       dai_link->num_codecs = num_codecs;
+       int index, ret;
+
+       ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node,
+                                        &dai_link->codecs, &dai_link->num_codecs);
+       if (ret < 0)
+               return ret;
 
        /* Parse the list */
        for_each_link_codecs(dai_link, index, component) {
-               ret = of_parse_phandle_with_args(of_node, name,
-                                                "#sound-dai-cells",
-                                                index, &args);
+               ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index);
                if (ret)
                        goto err;
-               component->of_node = args.np;
-               ret = snd_soc_get_dai_name(&args, &component->dai_name);
-               if (ret < 0)
-                       goto err;
        }
        return 0;
 err:
@@ -3406,12 +3426,8 @@ void snd_soc_of_put_dai_link_cpus(struct snd_soc_dai_link *dai_link)
        struct snd_soc_dai_link_component *component;
        int index;
 
-       for_each_link_cpus(dai_link, index, component) {
-               if (!component->of_node)
-                       break;
-               of_node_put(component->of_node);
-               component->of_node = NULL;
-       }
+       for_each_link_cpus(dai_link, index, component)
+               __snd_soc_of_put_component(component);
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_put_dai_link_cpus);
 
@@ -3430,45 +3446,24 @@ int snd_soc_of_get_dai_link_cpus(struct device *dev,
                                 struct device_node *of_node,
                                 struct snd_soc_dai_link *dai_link)
 {
-       struct of_phandle_args args;
        struct snd_soc_dai_link_component *component;
-       char *name;
-       int index, num_codecs, ret;
-
-       /* Count the number of CODECs */
-       name = "sound-dai";
-       num_codecs = of_count_phandle_with_args(of_node, name,
-                                               "#sound-dai-cells");
-       if (num_codecs <= 0) {
-               if (num_codecs == -ENOENT)
-                       dev_err(dev, "No 'sound-dai' property\n");
-               else
-                       dev_err(dev, "Bad phandle in 'sound-dai'\n");
-               return num_codecs;
-       }
-       component = devm_kcalloc(dev,
-                                num_codecs, sizeof(*component),
-                                GFP_KERNEL);
-       if (!component)
-               return -ENOMEM;
-       dai_link->cpus = component;
-       dai_link->num_cpus = num_codecs;
+       int index, ret;
+
+       /* Count the number of CPUs */
+       ret = __snd_soc_of_get_dai_link_component_alloc(dev, of_node,
+                                        &dai_link->cpus, &dai_link->num_cpus);
+       if (ret < 0)
+               return ret;
 
        /* Parse the list */
        for_each_link_cpus(dai_link, index, component) {
-               ret = of_parse_phandle_with_args(of_node, name,
-                                                "#sound-dai-cells",
-                                                index, &args);
+               ret = __snd_soc_of_get_dai_link_component_parse(of_node, component, index);
                if (ret)
                        goto err;
-               component->of_node = args.np;
-               ret = snd_soc_get_dai_name(&args, &component->dai_name);
-               if (ret < 0)
-                       goto err;
        }
        return 0;
 err:
-       snd_soc_of_put_dai_link_codecs(dai_link);
+       snd_soc_of_put_dai_link_cpus(dai_link);
        dai_link->cpus = NULL;
        dai_link->num_cpus = 0;
        return ret;
index 6078afe335f88026b83bd1a580f95682934058d1..d530e8c2b77b1a83cc6c4559cd9c47e5ef30758d 100644 (file)
@@ -208,8 +208,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        int ret = -ENOTSUPP;
 
-       if (dai->driver->ops &&
-           dai->driver->ops->set_fmt)
+       if (dai->driver->ops && dai->driver->ops->set_fmt)
                ret = dai->driver->ops->set_fmt(dai, fmt);
 
        return soc_dai_ret(dai, ret);
index a8e842e02cdc2435626bfa71b4c4f124ababa42e..b05231414c1d0f6d8e8be7ee8bacdf2c4f70fa56 100644 (file)
@@ -370,14 +370,14 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
        case snd_soc_dapm_mixer_named_ctl:
                mc = (struct soc_mixer_control *)kcontrol->private_value;
 
-               if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
-                       dev_warn(widget->dapm->dev,
-                                "ASoC: Unsupported stereo autodisable control '%s'\n",
-                                ctrl_name);
-
                if (mc->autodisable) {
                        struct snd_soc_dapm_widget template;
 
+                       if (snd_soc_volsw_is_stereo(mc))
+                               dev_warn(widget->dapm->dev,
+                                        "ASoC: Unsupported stereo autodisable control '%s'\n",
+                                        ctrl_name);
+
                        name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
                                         "Autodisable");
                        if (!name) {
index d867f449d82db329fcfa8a579f3d55e101613cfb..bd88de056358355d5ac70e86778fa2df547de84b 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
 #include <linux/ctype.h>
@@ -177,20 +176,28 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       int platform_max;
-
-       if (!mc->platform_max)
-               mc->platform_max = mc->max;
-       platform_max = mc->platform_max;
-
-       if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       else
+       const char *vol_string = NULL;
+       int max;
+
+       max = uinfo->value.integer.max = mc->max - mc->min;
+       if (mc->platform_max && mc->platform_max < max)
+               max = mc->platform_max;
+
+       if (max == 1) {
+               /* Even two value controls ending in Volume should always be integer */
+               vol_string = strstr(kcontrol->id.name, " Volume");
+               if (vol_string && !strcmp(vol_string, " Volume"))
+                       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               else
+                       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       } else {
                uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       }
 
        uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
        uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = platform_max - mc->min;
+       uinfo->value.integer.max = max;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -203,7 +210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
  * Callback to provide information about a single mixer control, or a double
  * mixer control that spans 2 registers of the SX TLV type. SX TLV controls
  * have a range that represents both positive and negative values either side
- * of zero but without a sign bit.
+ * of zero but without a sign bit. min is the minimum register value, max is
+ * the number of steps.
  *
  * Returns 0 for success.
  */
@@ -212,12 +220,21 @@ int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol,
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
+       int max;
 
-       snd_soc_info_volsw(kcontrol, uinfo);
-       /* Max represents the number of levels in an SX control not the
-        * maximum value, so add the minimum value back on
-        */
-       uinfo->value.integer.max += mc->min;
+       if (mc->platform_max)
+               max = mc->platform_max;
+       else
+               max = mc->max;
+
+       if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+       uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = max;
 
        return 0;
 }
index a827cc3c158aeb8c14d834d9e7163b06361c13a4..5b99bf2dbd08501d128b18badac2b39c40f6f475 100644 (file)
@@ -1209,8 +1209,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
                return -EINVAL;
        }
        if (fe_substream->pcm->nonatomic && !be_substream->pcm->nonatomic) {
-               dev_warn(be->dev, "%s: FE is nonatomic but BE is not, forcing BE as nonatomic\n",
-                        __func__);
+               dev_dbg(be->dev, "FE is nonatomic but BE is not, forcing BE as nonatomic\n");
                be_substream->pcm->nonatomic = 1;
        }
 
index ae3968161509cd1ca15bcacddf9070a30a391ded..2cd3540cec0447a49a221b4592b45cd0177715ea 100644 (file)
@@ -104,7 +104,6 @@ static const struct snd_soc_component_driver test_component = {
        .name = "sound-soc-topology-test",
        .probe = d_probe,
        .remove = d_remove,
-       .non_legacy_dai_naming = 1,
 };
 
 /* ===== TOPOLOGY TEMPLATES ================================================= */
@@ -238,7 +237,6 @@ static int d_probe_null_comp(struct snd_soc_component *component)
 static const struct snd_soc_component_driver test_component_null_comp = {
        .name = "sound-soc-topology-test",
        .probe = d_probe_null_comp,
-       .non_legacy_dai_naming = 1,
 };
 
 static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
@@ -271,9 +269,7 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
-
+       snd_soc_unregister_card(&kunit_comp->card);
        snd_soc_unregister_component(test_dev);
 }
 
@@ -315,8 +311,7 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 
        snd_soc_unregister_component(test_dev);
 }
@@ -346,7 +341,6 @@ static int d_probe_null_fw(struct snd_soc_component *component)
 static const struct snd_soc_component_driver test_component_null_fw = {
        .name = "sound-soc-topology-test",
        .probe = d_probe_null_fw,
-       .non_legacy_dai_naming = 1,
 };
 
 static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
@@ -379,8 +373,7 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 
        snd_soc_unregister_component(test_dev);
 }
@@ -428,8 +421,7 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 
        snd_soc_unregister_component(test_dev);
 }
@@ -484,8 +476,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 
        snd_soc_unregister_component(test_dev);
 }
@@ -540,8 +531,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 
        snd_soc_unregister_component(test_dev);
 }
@@ -596,8 +586,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
        KUNIT_EXPECT_EQ(test, 0, ret);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 
        snd_soc_unregister_component(test_dev);
 }
@@ -655,8 +644,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes
        /* cleanup */
        snd_soc_unregister_component(test_dev);
 
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 }
 
 // TEST CASE
@@ -704,8 +692,7 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
        snd_soc_unregister_component(test_dev);
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 }
 
 // TEST CASE
@@ -757,8 +744,7 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
        }
 
        /* cleanup */
-       ret = snd_soc_unregister_card(&kunit_comp->card);
-       KUNIT_EXPECT_EQ(test, 0, ret);
+       snd_soc_unregister_card(&kunit_comp->card);
 }
 
 // TEST CASE
@@ -806,8 +792,7 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test)
                if (ret != 0 && ret != -EPROBE_DEFER)
                        KUNIT_FAIL(test, "Failed to register card");
 
-               ret = snd_soc_unregister_card(&kunit_comp->card);
-               KUNIT_EXPECT_EQ(test, 0, ret);
+               snd_soc_unregister_card(&kunit_comp->card);
        }
 
        /* cleanup */
index 3f9d314fba16804404de6938209af42564dafcaf..b101db85446ff02a9fca8c4c322dc8924618485f 100644 (file)
@@ -535,7 +535,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
                 * return an -EINVAL error and prevent the card from
                 * being configured.
                 */
-               if (IS_ENABLED(CONFIG_SND_CTL_VALIDATION) && sbe->max > 512)
+               if (sbe->max > 512)
                        k->access |= SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK;
 
                ext_ops = tplg->bytes_ext_ops;
index 594cb311ff30a9a370b0985eb1a4e3013f8bd367..70c380c0ac7b69b2d022bd35ce087ebc0df51d81 100644 (file)
@@ -141,7 +141,6 @@ static const struct snd_soc_component_driver dummy_codec = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_384000
index 4542868cd730f435bca5913e503e9fa9b49d1638..e90f173d067c9aba54b4e8e99933eca47913b003 100644 (file)
@@ -252,6 +252,13 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE
          When selected, the probe is handled in two steps, for example to
          avoid lockdeps if request_module is used in the probe.
 
+# Supported IPC versions
+config SND_SOC_SOF_IPC3
+       bool
+
+config SND_SOC_SOF_INTEL_IPC4
+       bool
+
 source "sound/soc/sof/amd/Kconfig"
 source "sound/soc/sof/imx/Kconfig"
 source "sound/soc/sof/intel/Kconfig"
index 92b5e83601be56aec774fa4156f30f2c33abd610..9a74ed116ed92a2263aaeed7ab0ab165428e1e88 100644 (file)
@@ -1,10 +1,18 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
 
 snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
-               control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
-               ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o\
-               ipc3-dtrace.o\
-               ipc4.o ipc4-loader.o
+               control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
+
+# IPC implementations
+ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
+snd-sof-objs +=        ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\
+               ipc3-dtrace.o
+endif
+ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),)
+snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o
+endif
+
+# SOF client support
 ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
 snd-sof-objs += sof-client.o
 endif
index 085232e04582ece53dc9d9659b2036cded7aebee..190c85d57047bfc54fc07f26bd5c21e5e3e401d0 100644 (file)
@@ -17,6 +17,7 @@ if SND_SOC_SOF_AMD_TOPLEVEL
 config SND_SOC_SOF_AMD_COMMON
        tristate
        select SND_SOC_SOF
+       select SND_SOC_SOF_IPC3
        select SND_SOC_SOF_PCI_DEV
        select SND_AMD_ACP_CONFIG
        select SND_SOC_ACPI if ACPI
index 40fbf11facba5536779b618e6313f87c9edb81f0..56cefd4a84fcdf3f624304d4239c0edeb984fffb 100644 (file)
 #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8         0xC3C
 #define ACPAXI2AXI_ATU_CTRL                    0xC40
 #define ACP_SOFT_RESET                         0x1000
+#define ACP_CONTROL                            0x1004
 
 #define ACP_I2S_PIN_CONFIG                     0x1400
 
 /* Registers from ACP_PGFSM block */
 #define ACP_PGFSM_CONTROL                      0x141C
 #define ACP_PGFSM_STATUS                       0x1420
+#define ACP_CLKMUX_SEL                         0x1424
 
 /* Registers from ACP_INTR block */
 #define ACP_EXTERNAL_INTR_ENB                  0x1800
index 0c272573df979281cb268a551c2edeb5b72a6d86..c40d2900dd36d33cb05ce51d91f87942e1c77116 100644 (file)
@@ -413,10 +413,46 @@ static int acp_init(struct snd_sof_dev *sdev)
                dev_err(sdev->dev, "ACP power on failed\n");
                return ret;
        }
+
+       snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01);
        /* Reset */
        return acp_reset(sdev);
 }
 
+int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
+{
+       int ret;
+
+       ret = acp_reset(sdev);
+       if (ret) {
+               dev_err(sdev->dev, "ACP Reset failed\n");
+               return ret;
+       }
+
+       snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
+
+int amd_sof_acp_resume(struct snd_sof_dev *sdev)
+{
+       int ret;
+
+       ret = acp_init(sdev);
+       if (ret) {
+               dev_err(sdev->dev, "ACP Init failed\n");
+               return ret;
+       }
+
+       snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03);
+
+       ret = acp_memory_init(sdev);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
+
 int amd_sof_acp_probe(struct snd_sof_dev *sdev)
 {
        struct pci_dev *pci = to_pci_dev(sdev->dev);
index 291b44c54bcc2d724f6f46427a129064c57baa18..4c42b8fd6abf185c278285fd0fbcece4be7da661 100644 (file)
@@ -216,6 +216,10 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
                       struct sof_ipc_dma_trace_params_ext *dtrace_params);
 int acp_sof_trace_release(struct snd_sof_dev *sdev);
 
+/* PM Callbacks */
+int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state);
+int amd_sof_acp_resume(struct snd_sof_dev *sdev);
+
 struct sof_amd_acp_desc {
        unsigned int host_bridge_id;
 };
index d5d9bcc2c997d8a5fce27afafb304c7984656884..3a7fed25a22674f9c014d0d4c9ad9e3440d69e3d 100644 (file)
@@ -49,6 +49,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = {
 
 static const struct sof_dev_desc renoir_desc = {
        .machines               = snd_soc_acpi_amd_sof_machines,
+       .use_acpi_target_states = true,
        .resindex_lpe_base      = 0,
        .resindex_pcicfg_base   = -1,
        .resindex_imr_base      = -1,
@@ -166,6 +167,9 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = {
        .id_table = rn_pci_ids,
        .probe = acp_pci_rn_probe,
        .remove = acp_pci_rn_remove,
+       .driver = {
+               .pm = &sof_pci_pm,
+       },
 };
 module_pci_driver(snd_sof_pci_amd_rn_driver);
 
index 70190365328ce4337315b09f7cc097e4b1dc6f40..9261c8bc2236d2a27d13fc3f436b8426022cfaa7 100644 (file)
@@ -173,6 +173,10 @@ struct snd_sof_dsp_ops sof_renoir_ops = {
        /* Trace Logger */
        .trace_init             = acp_sof_trace_init,
        .trace_release          = acp_sof_trace_release,
+
+       /* PM */
+       .suspend                = amd_sof_acp_suspend,
+       .resume                 = amd_sof_acp_resume,
 };
 EXPORT_SYMBOL(sof_renoir_ops);
 
index 47639b6344c8013ab6a3b48816c43ab8e3912b09..67139e15f862a114b0319ec88ddca489eac365a5 100644 (file)
@@ -167,11 +167,23 @@ static int sof_compr_set_params(struct snd_soc_component *component,
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
        struct snd_compr_runtime *crtd = cstream->runtime;
        struct sof_ipc_pcm_params_reply ipc_params_reply;
+       struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
+       struct sof_ipc_fw_version *v = &ready->version;
        struct snd_compr_tstamp *tstamp;
-       struct sof_ipc_pcm_params pcm;
+       struct sof_ipc_pcm_params *pcm;
        struct snd_sof_pcm *spcm;
+       size_t ext_data_size;
        int ret;
 
+       if (v->abi_version < SOF_ABI_VER(3, 22, 0)) {
+               dev_err(component->dev,
+                       "Compress params not supported with FW ABI version %d:%d:%d\n",
+                       SOF_ABI_VERSION_MAJOR(v->abi_version),
+                       SOF_ABI_VERSION_MINOR(v->abi_version),
+                       SOF_ABI_VERSION_PATCH(v->abi_version));
+               return -EINVAL;
+       }
+
        tstamp = crtd->private_data;
 
        spcm = snd_sof_find_spcm_dai(component, rtd);
@@ -179,40 +191,50 @@ static int sof_compr_set_params(struct snd_soc_component *component,
        if (!spcm)
                return -EINVAL;
 
+       ext_data_size = sizeof(params->codec);
+
+       if (sizeof(*pcm) + ext_data_size > sdev->ipc->max_payload_size)
+               return -EINVAL;
+
+       pcm = kzalloc(sizeof(*pcm) + ext_data_size, GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
        cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
        cstream->dma_buffer.dev.dev = sdev->dev;
        ret = snd_compr_malloc_pages(cstream, crtd->buffer_size);
        if (ret < 0)
-               return ret;
+               goto out;
 
        ret = create_page_table(component, cstream, crtd->dma_area, crtd->dma_bytes);
        if (ret < 0)
-               return ret;
-
-       memset(&pcm, 0, sizeof(pcm));
-
-       pcm.params.buffer.pages = PFN_UP(crtd->dma_bytes);
-       pcm.hdr.size = sizeof(pcm);
-       pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
-
-       pcm.comp_id = spcm->stream[cstream->direction].comp_id;
-       pcm.params.hdr.size = sizeof(pcm.params);
-       pcm.params.buffer.phy_addr = spcm->stream[cstream->direction].page_table.addr;
-       pcm.params.buffer.size = crtd->dma_bytes;
-       pcm.params.direction = cstream->direction;
-       pcm.params.channels = params->codec.ch_out;
-       pcm.params.rate = params->codec.sample_rate;
-       pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
-       pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
-       pcm.params.sample_container_bytes =
+               goto out;
+
+       pcm->params.buffer.pages = PFN_UP(crtd->dma_bytes);
+       pcm->hdr.size = sizeof(*pcm) + ext_data_size;
+       pcm->hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
+
+       pcm->comp_id = spcm->stream[cstream->direction].comp_id;
+       pcm->params.hdr.size = sizeof(pcm->params) + ext_data_size;
+       pcm->params.buffer.phy_addr = spcm->stream[cstream->direction].page_table.addr;
+       pcm->params.buffer.size = crtd->dma_bytes;
+       pcm->params.direction = cstream->direction;
+       pcm->params.channels = params->codec.ch_out;
+       pcm->params.rate = params->codec.sample_rate;
+       pcm->params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
+       pcm->params.frame_fmt = SOF_IPC_FRAME_S32_LE;
+       pcm->params.sample_container_bytes =
                snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32) >> 3;
-       pcm.params.host_period_bytes = params->buffer.fragment_size;
+       pcm->params.host_period_bytes = params->buffer.fragment_size;
+       pcm->params.ext_data_length = ext_data_size;
+
+       memcpy((u8 *)pcm->params.ext_data, &params->codec, ext_data_size);
 
-       ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
+       ret = sof_ipc_tx_message(sdev->ipc, pcm, sizeof(*pcm) + ext_data_size,
                                 &ipc_params_reply, sizeof(ipc_params_reply));
        if (ret < 0) {
                dev_err(component->dev, "error ipc failed\n");
-               return ret;
+               goto out;
        }
 
        tstamp->byte_offset = sdev->stream_box.offset + ipc_params_reply.posn_offset;
@@ -220,7 +242,10 @@ static int sof_compr_set_params(struct snd_soc_component *component,
 
        spcm->prepared[cstream->direction] = true;
 
-       return 0;
+out:
+       kfree(pcm);
+
+       return ret;
 }
 
 static int sof_compr_get_params(struct snd_soc_component *component,
index 53719c04658ffef9d4a9aba634ff8acf5b5b534e..c99b5e6c026c10dca012f656335a8e307ad934ca 100644 (file)
@@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
        ret = snd_sof_probe(sdev);
        if (ret < 0) {
                dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
-               return ret;
+               goto probe_err;
        }
 
        sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
@@ -317,6 +317,8 @@ dbg_err:
        snd_sof_free_debug(sdev);
 dsp_err:
        snd_sof_remove(sdev);
+probe_err:
+       sof_ops_free(sdev);
 
        /* all resources freed, update state to match */
        sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
@@ -374,6 +376,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
            !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
            !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
            !sof_ops(sdev)->ipc_msg_data) {
+               sof_ops_free(sdev);
                dev_err(dev, "error: missing mandatory ops\n");
                return -EINVAL;
        }
@@ -457,6 +460,8 @@ int snd_sof_device_remove(struct device *dev)
                snd_sof_remove(sdev);
        }
 
+       sof_ops_free(sdev);
+
        /* release firmware */
        snd_sof_fw_unload(sdev);
 
index cf1271eb29b23f93c25e2ff78b93d11ec87de04d..c5d797e97c0271d6b30dcc044257b87b068048b9 100644 (file)
@@ -428,7 +428,7 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
        }
 }
 
-void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
+void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg)
 {
        if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
            sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) {
@@ -441,8 +441,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
 
        /* dump vital information to the logs */
        snd_sof_ipc_dump(sdev);
-       snd_sof_dsp_dbg_dump(sdev, "Firmware exception",
-                            SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
+       snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
        sof_fw_trace_fw_crashed(sdev);
 }
 EXPORT_SYMBOL(snd_sof_handle_fw_exception);
index 9b8d5bb1e4491d245792991f21b44b490b9f499f..cc6e695f913a121b4fe2b6b33fc9e5ea7cbd7563 100644 (file)
@@ -15,6 +15,7 @@ config SND_SOC_SOF_IMX_COMMON
        tristate
        select SND_SOC_SOF_OF_DEV
        select SND_SOC_SOF
+       select SND_SOC_SOF_IPC3
        select SND_SOC_SOF_XTENSA
        select SND_SOC_SOF_COMPRESS
        help
index 0def2aa5581dac69ae09fb931de11e2c883b8364..3f54678e810baacfdaf8a9ee054b4eb0c7b1406e 100644 (file)
@@ -40,6 +40,7 @@ if SND_SOC_SOF_ACPI
 config SND_SOC_SOF_BAYTRAIL
        tristate "SOF support for Baytrail, Braswell and Cherrytrail"
        default SND_SOC_SOF_ACPI
+       select SND_SOC_SOF_IPC3
        select SND_SOC_SOF_INTEL_COMMON
        select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
        select SND_SOC_SOF_ACPI_DEV
@@ -60,6 +61,7 @@ config SND_SOC_SOF_BAYTRAIL
 config SND_SOC_SOF_BROADWELL
        tristate "SOF support for Broadwell"
        default SND_SOC_SOF_ACPI
+       select SND_SOC_SOF_IPC3
        select SND_SOC_SOF_INTEL_COMMON
        select SND_SOC_SOF_INTEL_HIFI_EP_IPC
        select SND_SOC_SOF_ACPI_DEV
@@ -85,6 +87,7 @@ config SND_SOC_SOF_MERRIFIELD
        tristate "SOF support for Tangier/Merrifield"
        default SND_SOC_SOF_PCI
        select SND_SOC_SOF_PCI_DEV
+       select SND_SOC_SOF_IPC3
        select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
        help
          This adds support for Sound Open Firmware for Intel(R) platforms
@@ -95,6 +98,8 @@ config SND_SOC_SOF_MERRIFIELD
 config SND_SOC_SOF_INTEL_APL
        tristate
        select SND_SOC_SOF_HDA_COMMON
+       select SND_SOC_SOF_IPC3
+       select SND_SOC_SOF_INTEL_IPC4
 
 config SND_SOC_SOF_APOLLOLAKE
        tristate "SOF support for Apollolake"
@@ -120,6 +125,8 @@ config SND_SOC_SOF_INTEL_CNL
        tristate
        select SND_SOC_SOF_HDA_COMMON
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+       select SND_SOC_SOF_IPC3
+       select SND_SOC_SOF_INTEL_IPC4
 
 config SND_SOC_SOF_CANNONLAKE
        tristate "SOF support for Cannonlake"
@@ -154,6 +161,8 @@ config SND_SOC_SOF_INTEL_ICL
        tristate
        select SND_SOC_SOF_HDA_COMMON
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+       select SND_SOC_SOF_IPC3
+       select SND_SOC_SOF_INTEL_IPC4
 
 config SND_SOC_SOF_ICELAKE
        tristate "SOF support for Icelake"
@@ -179,6 +188,8 @@ config SND_SOC_SOF_INTEL_TGL
        tristate
        select SND_SOC_SOF_HDA_COMMON
        select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+       select SND_SOC_SOF_IPC3
+       select SND_SOC_SOF_INTEL_IPC4
 
 config SND_SOC_SOF_TIGERLAKE
        tristate "SOF support for Tigerlake"
@@ -210,6 +221,22 @@ config SND_SOC_SOF_ALDERLAKE
          Say Y if you have such a device.
          If unsure select "N".
 
+config SND_SOC_SOF_INTEL_MTL
+       tristate
+       select SND_SOC_SOF_HDA_COMMON
+       select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+       select SND_SOC_SOF_INTEL_IPC4
+
+config SND_SOC_SOF_METEORLAKE
+       tristate "SOF support for Meteorlake"
+       default SND_SOC_SOF_PCI
+       select SND_SOC_SOF_INTEL_MTL
+       help
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the Meteorlake processors.
+         Say Y if you have such a device.
+         If unsure select "N".
+
 config SND_SOC_SOF_HDA_COMMON
        tristate
        select SND_SOC_SOF_INTEL_COMMON
index b9d51dc39ffa6a3c415d20f850613a246e0e3f81..a079159bb2f024e3c58184f8ee6cf0552caa16a9 100644 (file)
@@ -6,7 +6,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o
 snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
                                 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
                                 hda-dai.o hda-bus.o \
-                                apl.o cnl.o tgl.o icl.o hda-common-ops.o
+                                apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
 snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o
 
 snd-sof-intel-hda-objs := hda-codec.o
@@ -24,9 +24,11 @@ snd-sof-pci-intel-apl-objs := pci-apl.o
 snd-sof-pci-intel-cnl-objs := pci-cnl.o
 snd-sof-pci-intel-icl-objs := pci-icl.o
 snd-sof-pci-intel-tgl-objs := pci-tgl.o
+snd-sof-pci-intel-mtl-objs := pci-mtl.o
 
 obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_APL) += snd-sof-pci-intel-apl.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o
index 0cea280a6d2d3129334ecbf312bc60f80c09d0b8..084c245a952288a66cc3ef3e8c7fb874de9adeeb 100644 (file)
@@ -101,6 +101,7 @@ const struct sof_intel_dsp_desc apl_chip_info = {
        .ssp_base_offset = APL_SSP_BASE_OFFSET,
        .quirks = SOF_INTEL_PROCEN_FMT_QUIRK,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS,
 };
 EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
index ff5900b155dc99ad5c184a5aadec9d411833b844..bd9789b483b17960050d0f4f597ddd8483f4fde4 100644 (file)
@@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
                                   const char *ssp_str)
 {
        const char *tplg_filename = NULL;
-       char *filename;
-       char *split_ext;
+       const char *split_ext;
+       char *filename, *tmp;
 
-       filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
+       filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
        if (!filename)
                return NULL;
 
        /* this assumes a .tplg extension */
-       split_ext = strsep(&filename, ".");
-       if (split_ext) {
+       tmp = filename;
+       split_ext = strsep(&tmp, ".");
+       if (split_ext)
                tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
                                               "%s-%s.tplg",
                                               split_ext, ssp_str);
-               if (!tplg_filename)
-                       return NULL;
-       }
+       kfree(filename);
+
        return tplg_filename;
 }
 
index 26df780c702e8b3afc0feb1b9a22b5bff1aaa3f3..a446154f280328618f4e2350c4e25c7c3eccdee2 100644 (file)
@@ -681,11 +681,8 @@ static int sof_broadwell_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       desc = device_get_match_data(dev);
-       if (!desc)
-               return -ENODEV;
-
-       return sof_acpi_probe(pdev, device_get_match_data(dev));
+       desc = (const struct sof_dev_desc *)id->driver_data;
+       return sof_acpi_probe(pdev, desc);
 }
 
 /* acpi_driver definition */
index 4ed8381ecedaa9de4e3fff1a5ff3e857efa4c526..e6dc4ff531c3464c62fb0f9b4ead6cefe4c3ce42 100644 (file)
@@ -465,10 +465,7 @@ static int sof_baytrail_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       desc = device_get_match_data(&pdev->dev);
-       if (!desc)
-               return -ENODEV;
-
+       desc = (const struct sof_dev_desc *)id->driver_data;
        if (desc == &sof_acpi_baytrail_desc && soc_intel_is_byt_cr(pdev))
                desc = &sof_acpi_baytrailcr_desc;
 
index cd6e5f8a5eb4dfdad775c4f34d313ef3c7d32220..a064453f0bc3e58d92be7617c452d8e91e323079 100644 (file)
@@ -60,17 +60,23 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
 
                if (primary & SOF_IPC4_MSG_DIR_MASK) {
                        /* Reply received */
-                       struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
+                       if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+                               struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
 
-                       data->primary = primary;
-                       data->extension = extension;
+                               data->primary = primary;
+                               data->extension = extension;
 
-                       spin_lock_irq(&sdev->ipc_lock);
+                               spin_lock_irq(&sdev->ipc_lock);
 
-                       snd_sof_ipc_get_reply(sdev);
-                       snd_sof_ipc_reply(sdev, data->primary);
+                               snd_sof_ipc_get_reply(sdev);
+                               snd_sof_ipc_reply(sdev, data->primary);
 
-                       spin_unlock_irq(&sdev->ipc_lock);
+                               spin_unlock_irq(&sdev->ipc_lock);
+                       } else {
+                               dev_dbg_ratelimited(sdev->dev,
+                                                   "IPC reply before FW_READY: %#x|%#x\n",
+                                                   primary, extension);
+                       }
                } else {
                        /* Notification received */
                        notification_data.primary = primary;
@@ -124,15 +130,20 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
                                        CNL_DSP_REG_HIPCCTL,
                                        CNL_DSP_REG_HIPCCTL_DONE, 0);
 
-               spin_lock_irq(&sdev->ipc_lock);
+               if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+                       spin_lock_irq(&sdev->ipc_lock);
 
-               /* handle immediate reply from DSP core */
-               hda_dsp_ipc_get_reply(sdev);
-               snd_sof_ipc_reply(sdev, msg);
+                       /* handle immediate reply from DSP core */
+                       hda_dsp_ipc_get_reply(sdev);
+                       snd_sof_ipc_reply(sdev, msg);
 
-               cnl_ipc_dsp_done(sdev);
+                       cnl_ipc_dsp_done(sdev);
 
-               spin_unlock_irq(&sdev->ipc_lock);
+                       spin_unlock_irq(&sdev->ipc_lock);
+               } else {
+                       dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
+                                           msg);
+               }
 
                ipc_irq = true;
        }
@@ -401,6 +412,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_1_8,
 };
 EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@@ -430,6 +442,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_2_0,
 };
 EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
index 9823230d2ef4ab06ee5dfff5556b149900c123b7..556e883a32edb6a533a9e7b16f8d84a8f812448c 100644 (file)
 
 #include <sound/pcm_params.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/intel-nhlt.h>
+#include <sound/sof/ipc4/header.h>
+#include <uapi/sound/sof/header.h>
+#include "../ipc4-priv.h"
+#include "../ipc4-topology.h"
 #include "../sof-priv.h"
 #include "../sof-audio.h"
 #include "hda.h"
 
+/*
+ * The default method is to fetch NHLT from BIOS. With this parameter set
+ * it is possible to override that with NHLT in the SOF topology manifest.
+ */
+static bool hda_use_tplg_nhlt;
+module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
+MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
+
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 
 struct hda_pipe_params {
@@ -113,12 +126,8 @@ hda_link_stream_assign(struct hdac_bus *bus,
        }
 
        if (res) {
-               /*
-                * Decouple host and link DMA. The decoupled flag
-                * is updated in snd_hdac_ext_stream_decouple().
-                */
-               if (!res->decoupled)
-                       snd_hdac_ext_stream_decouple_locked(bus, res, true);
+               /* Make sure that host and link DMA is decoupled. */
+               snd_hdac_ext_stream_decouple_locked(bus, res, true);
 
                res->link_locked = 1;
                res->link_substream = substream;
@@ -171,7 +180,6 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
        struct hdac_ext_link *link;
        unsigned int format_val;
 
-       snd_hdac_ext_stream_decouple(bus, hext_stream, true);
        snd_hdac_ext_link_stream_reset(hext_stream);
 
        format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
@@ -208,7 +216,6 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
        struct hdac_bus *bus = hstream->bus;
        struct hdac_ext_link *link;
 
-       /* get stored dma data if resuming from system suspend */
        hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
        if (!hext_stream) {
                hext_stream = hda_link_stream_assign(bus, substream);
@@ -257,7 +264,6 @@ static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
        struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
        int ret;
 
-       dev_dbg(cpu_dai->dev, "%s: cmd=%d\n", __func__, cmd);
        if (!hext_stream)
                return 0;
 
@@ -369,8 +375,7 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
        return ret;
 }
 
-static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
+static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
        struct hdac_ext_stream *hext_stream =
                                snd_soc_dai_get_dma_data(dai, substream);
@@ -382,7 +387,7 @@ static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
        if (hext_stream && hext_stream->link_prepared)
                return 0;
 
-       dev_dbg(sdev->dev, "%s: prepare stream dir %d\n", __func__, substream->stream);
+       dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
 
        ret = hda_link_dma_prepare(substream);
        if (ret < 0)
@@ -408,13 +413,15 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
        struct snd_soc_dapm_widget *w;
        int ret;
 
+       dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
+               dai->name, substream->stream);
+
        ret = hda_link_dma_trigger(substream, cmd);
        if (ret < 0)
                return ret;
 
        w = snd_soc_dai_get_widget(dai, substream->stream);
 
-       dev_dbg(dai->dev, "%s: cmd=%d\n", __func__, cmd);
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
@@ -438,6 +445,91 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
+/*
+ * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
+ * (over IPC channel) and DMA state change (direct host register changes).
+ */
+static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
+                               int cmd, struct snd_soc_dai *dai)
+{
+       struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
+       struct snd_soc_pcm_runtime *rtd;
+       struct snd_sof_widget *swidget;
+       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dai *codec_dai;
+       struct hdac_stream *hstream;
+       struct snd_soc_dai *cpu_dai;
+       int ret;
+
+       dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
+               dai->name, substream->stream);
+
+       hstream = substream->runtime->private_data;
+       rtd = asoc_substream_to_rtd(substream);
+       cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+       w = snd_soc_dai_get_widget(dai, substream->stream);
+       swidget = w->dobj.private;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               snd_hdac_ext_link_stream_start(hext_stream);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       {
+               struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+               struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                 SOF_IPC4_PIPE_PAUSED);
+               if (ret < 0)
+                       return ret;
+
+               pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+               snd_hdac_ext_link_stream_clear(hext_stream);
+
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                 SOF_IPC4_PIPE_RESET);
+               if (ret < 0)
+                       return ret;
+
+               pipeline->state = SOF_IPC4_PIPE_RESET;
+
+               ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
+                       return ret;
+               }
+               break;
+       }
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       {
+               struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+               struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                 SOF_IPC4_PIPE_PAUSED);
+               if (ret < 0)
+                       return ret;
+
+               pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+               snd_hdac_ext_link_stream_clear(hext_stream);
+               break;
+       }
+       default:
+               dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int hda_dai_hw_free(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
@@ -454,7 +546,7 @@ static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
        .hw_params = hda_dai_hw_params,
        .hw_free = hda_dai_hw_free,
        .trigger = ipc3_hda_dai_trigger,
-       .prepare = ipc3_hda_dai_prepare,
+       .prepare = hda_dai_prepare,
 };
 
 static int hda_dai_suspend(struct hdac_bus *bus)
@@ -497,6 +589,14 @@ static int hda_dai_suspend(struct hdac_bus *bus)
 
        return 0;
 }
+
+static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
+       .hw_params = hda_dai_hw_params,
+       .hw_free = hda_dai_hw_free,
+       .trigger = ipc4_hda_dai_trigger,
+       .prepare = hda_dai_prepare,
+};
+
 #endif
 
 /* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
@@ -608,6 +708,64 @@ static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = {
        .shutdown = ssp_dai_shutdown,
 };
 
+static int ipc4_be_dai_common_trigger(struct snd_soc_dai *dai, int cmd, int stream)
+{
+       struct snd_sof_widget *pipe_widget;
+       struct sof_ipc4_pipeline *pipeline;
+       struct snd_sof_widget *swidget;
+       struct snd_soc_dapm_widget *w;
+       struct snd_sof_dev *sdev;
+       int ret;
+
+       w = snd_soc_dai_get_widget(dai, stream);
+       swidget = w->dobj.private;
+       pipe_widget = swidget->pipe_widget;
+       pipeline = pipe_widget->private;
+       sdev = snd_soc_component_get_drvdata(swidget->scomp);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                 SOF_IPC4_PIPE_PAUSED);
+               if (ret < 0)
+                       return ret;
+               pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                 SOF_IPC4_PIPE_RESET);
+               if (ret < 0)
+                       return ret;
+               pipeline->state = SOF_IPC4_PIPE_RESET;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                 SOF_IPC4_PIPE_PAUSED);
+               if (ret < 0)
+                       return ret;
+               pipeline->state = SOF_IPC4_PIPE_PAUSED;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int ipc4_be_dai_trigger(struct snd_pcm_substream *substream,
+                              int cmd, struct snd_soc_dai *dai)
+{
+       return ipc4_be_dai_common_trigger(dai, cmd, substream->stream);
+}
+
+static const struct snd_soc_dai_ops ipc4_dmic_dai_ops = {
+       .trigger = ipc4_be_dai_trigger,
+};
+
+static const struct snd_soc_dai_ops ipc4_ssp_dai_ops = {
+       .trigger = ipc4_be_dai_trigger,
+};
+
 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 {
        int i;
@@ -627,11 +785,51 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 #endif
                }
                break;
+       case SOF_INTEL_IPC4:
+       {
+               struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+               for (i = 0; i < ops->num_drv; i++) {
+                       if (strstr(ops->drv[i].name, "DMIC")) {
+                               ops->drv[i].ops = &ipc4_dmic_dai_ops;
+                               continue;
+                       }
+                       if (strstr(ops->drv[i].name, "SSP")) {
+                               ops->drv[i].ops = &ipc4_ssp_dai_ops;
+                               continue;
+                       }
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+                       if (strstr(ops->drv[i].name, "iDisp") ||
+                           strstr(ops->drv[i].name, "Analog") ||
+                           strstr(ops->drv[i].name, "Digital"))
+                               ops->drv[i].ops = &ipc4_hda_dai_ops;
+#endif
+               }
+
+               if (!hda_use_tplg_nhlt)
+                       ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
+
+               if (IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE))
+                       sdw_callback.trigger = ipc4_be_dai_common_trigger;
+
+               break;
+       }
        default:
                break;
        }
 }
 
+void hda_ops_free(struct snd_sof_dev *sdev)
+{
+       if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+               struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+               if (!hda_use_tplg_nhlt)
+                       intel_nhlt_free(ipc4_data->nhlt);
+       }
+}
+EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+
 /*
  * common dai driver for skl+ platforms.
  * some products who use this DAI array only physically have a subset of
index e24eea725acb43654700277319e61755e5c7993b..eddfd77ad90f4e2250fc12e7cc8ad9603c308c46 100644 (file)
@@ -617,6 +617,13 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
 #endif
        int ret, j;
 
+       /*
+        * The memory used for IMR boot loses its content in deeper than S3 state
+        * We must not try IMR boot on next power up (as it will fail).
+        */
+       if (sdev->system_suspend_target > SOF_SUSPEND_S3)
+               hda->skip_imr_boot = true;
+
        hda_sdw_int_enable(sdev, false);
 
        /* disable IPC interrupts */
@@ -743,7 +750,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
                        if (hlink->ref_count) {
                                ret = snd_hdac_ext_bus_link_power_up(hlink);
                                if (ret < 0) {
-                                       dev_dbg(sdev->dev,
+                                       dev_err(sdev->dev,
                                                "error %d in %s: failed to power up links",
                                                ret, __func__);
                                        return ret;
@@ -871,7 +878,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
                /* no link can be powered in s0ix state */
                ret = snd_hdac_ext_bus_link_power_down_all(bus);
                if (ret < 0) {
-                       dev_dbg(sdev->dev,
+                       dev_err(sdev->dev,
                                "error %d in %s: failed to power down links",
                                ret, __func__);
                        return ret;
@@ -940,13 +947,7 @@ void hda_dsp_d0i3_work(struct work_struct *work)
 
 int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
 {
-       struct sof_ipc_pm_core_config pm_core_config = {
-               .hdr = {
-                       .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
-                       .size = sizeof(pm_core_config),
-               },
-               .enable_mask = sdev->enabled_cores_mask | BIT(core),
-       };
+       const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
        int ret, ret1;
 
        /* power up core */
@@ -961,9 +962,12 @@ int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
        if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE)
                return 0;
 
+       /* No need to continue the set_core_state ops is not available */
+       if (!pm_ops->set_core_state)
+               return 0;
+
        /* Now notify DSP for secondary cores */
-       ret = sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
-                                &pm_core_config, sizeof(pm_core_config));
+       ret = pm_ops->set_core_state(sdev, core, true);
        if (ret < 0) {
                dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n",
                        core, ret);
index f08011249955279325bd36cd5ec193e94f850764..65e688f749eaf16955e29d2f7bd52273de024d99 100644 (file)
@@ -148,17 +148,23 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
 
                if (primary & SOF_IPC4_MSG_DIR_MASK) {
                        /* Reply received */
-                       struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
+                       if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+                               struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
 
-                       data->primary = primary;
-                       data->extension = extension;
+                               data->primary = primary;
+                               data->extension = extension;
 
-                       spin_lock_irq(&sdev->ipc_lock);
+                               spin_lock_irq(&sdev->ipc_lock);
 
-                       snd_sof_ipc_get_reply(sdev);
-                       snd_sof_ipc_reply(sdev, data->primary);
+                               snd_sof_ipc_get_reply(sdev);
+                               snd_sof_ipc_reply(sdev, data->primary);
 
-                       spin_unlock_irq(&sdev->ipc_lock);
+                               spin_unlock_irq(&sdev->ipc_lock);
+                       } else {
+                               dev_dbg_ratelimited(sdev->dev,
+                                                   "IPC reply before FW_READY: %#x|%#x\n",
+                                                   primary, extension);
+                       }
                } else {
                        /* Notification received */
 
@@ -225,16 +231,21 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
                 * place, the message might not yet be marked as expecting a
                 * reply.
                 */
-               spin_lock_irq(&sdev->ipc_lock);
+               if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+                       spin_lock_irq(&sdev->ipc_lock);
 
-               /* handle immediate reply from DSP core */
-               hda_dsp_ipc_get_reply(sdev);
-               snd_sof_ipc_reply(sdev, msg);
+                       /* handle immediate reply from DSP core */
+                       hda_dsp_ipc_get_reply(sdev);
+                       snd_sof_ipc_reply(sdev, msg);
 
-               /* set the done bit */
-               hda_dsp_ipc_dsp_done(sdev);
+                       /* set the done bit */
+                       hda_dsp_ipc_dsp_done(sdev);
 
-               spin_unlock_irq(&sdev->ipc_lock);
+                       spin_unlock_irq(&sdev->ipc_lock);
+               } else {
+                       dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
+                                           msg);
+               }
 
                ipc_irq = true;
        }
index 145d483bd129f15f6e013dd8a5ed105b859e2676..eb22eb3f6fee17fc38f53f77e8e1383a22fd2fcf 100644 (file)
@@ -99,7 +99,7 @@ out_put:
  * power on all host managed cores and only unstall/run the boot core to boot the
  * DSP then turn off all non boot cores (if any) is powered on.
  */
-static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
+int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
 {
        struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
        const struct sof_intel_dsp_desc *chip = hda->desc;
@@ -369,9 +369,15 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
 
 static int hda_dsp_boot_imr(struct snd_sof_dev *sdev)
 {
+       const struct sof_intel_dsp_desc *chip_info;
        int ret;
 
-       ret = cl_dsp_init(sdev, 0, true);
+       chip_info = get_chip_info(sdev->pdata);
+       if (chip_info->cl_init)
+               ret = chip_info->cl_init(sdev, 0, true);
+       else
+               ret = -EINVAL;
+
        if (!ret)
                hda_sdw_process_wakeen(sdev);
 
@@ -389,8 +395,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
        struct snd_dma_buffer dmab;
        int ret, ret1, i;
 
-       if (sdev->system_suspend_target < SOF_SUSPEND_S4 &&
-           hda->imrboot_supported && !sdev->first_boot) {
+       if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) {
                dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
                hda->boot_iteration = 0;
                ret = hda_dsp_boot_imr(sdev);
@@ -431,7 +436,10 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
                        "Attempting iteration %d of Core En/ROM load...\n", i);
 
                hda->boot_iteration = i + 1;
-               ret = cl_dsp_init(sdev, hext_stream->hstream.stream_tag, false);
+               if (chip_info->cl_init)
+                       ret = chip_info->cl_init(sdev, hext_stream->hstream.stream_tag, false);
+               else
+                       ret = -EINVAL;
 
                /* don't retry anymore if successful */
                if (!ret)
@@ -471,11 +479,14 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
         */
        hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS;
        ret = hda_cl_copy_fw(sdev, hext_stream);
-       if (!ret)
+       if (!ret) {
                dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
-       else
+               hda->skip_imr_boot = false;
+       } else {
                snd_sof_dsp_dbg_dump(sdev, "Firmware download failed",
                                     SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX);
+               hda->skip_imr_boot = true;
+       }
 
 cleanup:
        /*
@@ -530,7 +541,8 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
 
                /* Check if IMR boot is usable */
                if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) &&
-                   sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT)
+                   (sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT ||
+                    sdev->pdata->ipc_type == SOF_INTEL_IPC4))
                        hdev->imrboot_supported = true;
        }
 
index 31e85d4aae8cbe58bee266bdc258bb2e0a762e1f..56a533c63cb003b3d262ff17c600ac742e9bf245 100644 (file)
@@ -25,9 +25,9 @@ hda_compr_get_stream(struct snd_compr_stream *cstream)
        return cstream->runtime->private_data;
 }
 
-static int hda_probes_compr_assign(struct sof_client_dev *cdev,
-                                  struct snd_compr_stream *cstream,
-                                  struct snd_soc_dai *dai, u32 *stream_id)
+static int hda_probes_compr_startup(struct sof_client_dev *cdev,
+                                   struct snd_compr_stream *cstream,
+                                   struct snd_soc_dai *dai, u32 *stream_id)
 {
        struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
        struct hdac_ext_stream *hext_stream;
@@ -45,9 +45,9 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev,
        return 0;
 }
 
-static int hda_probes_compr_free(struct sof_client_dev *cdev,
-                                struct snd_compr_stream *cstream,
-                                struct snd_soc_dai *dai)
+static int hda_probes_compr_shutdown(struct sof_client_dev *cdev,
+                                    struct snd_compr_stream *cstream,
+                                    struct snd_soc_dai *dai)
 {
        struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
        struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
@@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
 
 /* SOF client implementation */
 static const struct sof_probes_host_ops hda_probes_ops = {
-       .assign = hda_probes_compr_assign,
-       .free = hda_probes_compr_free,
+       .startup = hda_probes_compr_startup,
+       .shutdown = hda_probes_compr_shutdown,
        .set_params = hda_probes_compr_set_params,
        .trigger = hda_probes_compr_trigger,
        .pointer = hda_probes_compr_pointer,
index d95ae17e81cc4711a0de6bb2dc2e5c15fc268192..b58662faa4aad530a80b848d3f5ee00ed66a8612 100644 (file)
@@ -116,13 +116,13 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
        int remain, ioc;
 
        period_bytes = hstream->period_bytes;
-       dev_dbg(sdev->dev, "%s: period_bytes:0x%x\n", __func__, period_bytes);
+       dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes);
        if (!period_bytes)
                period_bytes = hstream->bufsize;
 
        periods = hstream->bufsize / period_bytes;
 
-       dev_dbg(sdev->dev, "%s: periods:%d\n", __func__, periods);
+       dev_dbg(sdev->dev, "periods:%d\n", periods);
 
        remain = hstream->bufsize % period_bytes;
        if (remain)
@@ -271,7 +271,7 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
                                        HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN);
 
        if (!found) {
-               dev_dbg(sdev->dev, "%s: stream_tag %d not opened!\n",
+               dev_err(sdev->dev, "%s: stream_tag %d not opened!\n",
                        __func__, stream_tag);
                return -ENODEV;
        }
@@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
                return -ENODEV;
        }
 
+       if (!dmab) {
+               dev_err(sdev->dev, "error: no dma buffer allocated!\n");
+               return -ENODEV;
+       }
+
        if (hstream->posbuf)
                *hstream->posbuf = 0;
 
@@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
                return -ENODEV;
        }
 
-       /* decouple host and link DMA */
-       mask = 0x1 << hstream->index;
-       snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
-                               mask, mask);
-
        if (!dmab) {
                dev_err(sdev->dev, "error: no dma buffer allocated!\n");
                return -ENODEV;
        }
 
+       /* decouple host and link DMA */
+       mask = 0x1 << hstream->index;
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
+                               mask, mask);
+
        /* clear stream status */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
                                SOF_HDA_CL_DMA_SD_INT_MASK |
index bc07df1fc39f01f9411fa9e968bcbe46c7975204..8639ea63a10dbb1baceef97ab2710b27ea9b4ad5 100644 (file)
@@ -147,7 +147,7 @@ static int sdw_free_stream(struct device *dev,
        return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
 }
 
-static const struct sdw_intel_ops sdw_callback = {
+struct sdw_intel_ops sdw_callback = {
        .params_stream = sdw_params_stream,
        .free_stream = sdw_free_stream,
 };
@@ -353,7 +353,7 @@ static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
 
 struct hda_dsp_msg_code {
        u32 code;
-       const char *msg;
+       const char *text;
 };
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
@@ -382,10 +382,7 @@ module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
 MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
 #endif
 
-static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
-       {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"},
-       {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"},
-       {HDA_DSP_ROM_FW_ENTERED, "status: fw entered"},
+static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
        {HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
        {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
        {HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"},
@@ -404,26 +401,136 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
        {HDA_DSP_ROM_NULL_FW_ENTRY,     "error: null FW entry point"},
 };
 
-static void hda_dsp_get_status(struct snd_sof_dev *sdev, const char *level)
+#define FSR_ROM_STATE_ENTRY(state)     {FSR_STATE_ROM_##state, #state}
+static const struct hda_dsp_msg_code fsr_rom_state_names[] = {
+       FSR_ROM_STATE_ENTRY(INIT),
+       FSR_ROM_STATE_ENTRY(INIT_DONE),
+       FSR_ROM_STATE_ENTRY(CSE_MANIFEST_LOADED),
+       FSR_ROM_STATE_ENTRY(FW_MANIFEST_LOADED),
+       FSR_ROM_STATE_ENTRY(FW_FW_LOADED),
+       FSR_ROM_STATE_ENTRY(FW_ENTERED),
+       FSR_ROM_STATE_ENTRY(VERIFY_FEATURE_MASK),
+       FSR_ROM_STATE_ENTRY(GET_LOAD_OFFSET),
+       FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT),
+       FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT_DONE),
+       /* CSE states */
+       FSR_ROM_STATE_ENTRY(CSE_IMR_REQUEST),
+       FSR_ROM_STATE_ENTRY(CSE_IMR_GRANTED),
+       FSR_ROM_STATE_ENTRY(CSE_VALIDATE_IMAGE_REQUEST),
+       FSR_ROM_STATE_ENTRY(CSE_IMAGE_VALIDATED),
+       FSR_ROM_STATE_ENTRY(CSE_IPC_IFACE_INIT),
+       FSR_ROM_STATE_ENTRY(CSE_IPC_RESET_PHASE_1),
+       FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL_ENTRY),
+       FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL),
+       FSR_ROM_STATE_ENTRY(CSE_IPC_DOWN),
+};
+
+#define FSR_BRINGUP_STATE_ENTRY(state) {FSR_STATE_BRINGUP_##state, #state}
+static const struct hda_dsp_msg_code fsr_bringup_state_names[] = {
+       FSR_BRINGUP_STATE_ENTRY(INIT),
+       FSR_BRINGUP_STATE_ENTRY(INIT_DONE),
+       FSR_BRINGUP_STATE_ENTRY(HPSRAM_LOAD),
+       FSR_BRINGUP_STATE_ENTRY(UNPACK_START),
+       FSR_BRINGUP_STATE_ENTRY(IMR_RESTORE),
+       FSR_BRINGUP_STATE_ENTRY(FW_ENTERED),
+};
+
+#define FSR_WAIT_STATE_ENTRY(state)    {FSR_WAIT_FOR_##state, #state}
+static const struct hda_dsp_msg_code fsr_wait_state_names[] = {
+       FSR_WAIT_STATE_ENTRY(IPC_BUSY),
+       FSR_WAIT_STATE_ENTRY(IPC_DONE),
+       FSR_WAIT_STATE_ENTRY(CACHE_INVALIDATION),
+       FSR_WAIT_STATE_ENTRY(LP_SRAM_OFF),
+       FSR_WAIT_STATE_ENTRY(DMA_BUFFER_FULL),
+       FSR_WAIT_STATE_ENTRY(CSE_CSR),
+};
+
+#define FSR_MODULE_NAME_ENTRY(mod)     [FSR_MOD_##mod] = #mod
+static const char * const fsr_module_names[] = {
+       FSR_MODULE_NAME_ENTRY(ROM),
+       FSR_MODULE_NAME_ENTRY(ROM_BYP),
+       FSR_MODULE_NAME_ENTRY(BASE_FW),
+       FSR_MODULE_NAME_ENTRY(LP_BOOT),
+       FSR_MODULE_NAME_ENTRY(BRNGUP),
+       FSR_MODULE_NAME_ENTRY(ROM_EXT),
+};
+
+static const char *
+hda_dsp_get_state_text(u32 code, const struct hda_dsp_msg_code *msg_code,
+                      size_t array_size)
 {
-       const struct sof_intel_dsp_desc *chip;
-       u32 status;
        int i;
 
-       chip = get_chip_info(sdev->pdata);
-       status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
-                                 chip->rom_status_reg);
-
-       for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
-               if (status == hda_dsp_rom_msg[i].code) {
-                       dev_printk(level, sdev->dev, "%s - code %8.8x\n",
-                                  hda_dsp_rom_msg[i].msg, status);
-                       return;
-               }
+       for (i = 0; i < array_size; i++) {
+               if (code == msg_code[i].code)
+                       return msg_code[i].text;
        }
 
+       return NULL;
+}
+
+static void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level)
+{
+       const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
+       const char *state_text, *error_text, *module_text;
+       u32 fsr, state, wait_state, module, error_code;
+
+       fsr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg);
+       state = FSR_TO_STATE_CODE(fsr);
+       wait_state = FSR_TO_WAIT_STATE_CODE(fsr);
+       module = FSR_TO_MODULE_CODE(fsr);
+
+       if (module > FSR_MOD_ROM_EXT)
+               module_text = "unknown";
+       else
+               module_text = fsr_module_names[module];
+
+       if (module == FSR_MOD_BRNGUP)
+               state_text = hda_dsp_get_state_text(state, fsr_bringup_state_names,
+                                                   ARRAY_SIZE(fsr_bringup_state_names));
+       else
+               state_text = hda_dsp_get_state_text(state, fsr_rom_state_names,
+                                                   ARRAY_SIZE(fsr_rom_state_names));
+
        /* not for us, must be generic sof message */
-       dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
+       if (!state_text) {
+               dev_printk(level, sdev->dev, "%#010x: unknown ROM status value\n", fsr);
+               return;
+       }
+
+       if (wait_state) {
+               const char *wait_state_text;
+
+               wait_state_text = hda_dsp_get_state_text(wait_state, fsr_wait_state_names,
+                                                        ARRAY_SIZE(fsr_wait_state_names));
+               if (!wait_state_text)
+                       wait_state_text = "unknown";
+
+               dev_printk(level, sdev->dev,
+                          "%#010x: module: %s, state: %s, waiting for: %s, %s\n",
+                          fsr, module_text, state_text, wait_state_text,
+                          fsr & FSR_HALTED ? "not running" : "running");
+       } else {
+               dev_printk(level, sdev->dev, "%#010x: module: %s, state: %s, %s\n",
+                          fsr, module_text, state_text,
+                          fsr & FSR_HALTED ? "not running" : "running");
+       }
+
+       error_code = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + 4);
+       if (!error_code)
+               return;
+
+       error_text = hda_dsp_get_state_text(error_code, hda_dsp_rom_fw_error_texts,
+                                           ARRAY_SIZE(hda_dsp_rom_fw_error_texts));
+       if (!error_text)
+               error_text = "unknown";
+
+       if (state == FSR_STATE_FW_ENTERED)
+               dev_printk(level, sdev->dev, "status code: %#x (%s)\n", error_code,
+                          error_text);
+       else
+               dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code,
+                          error_text);
 }
 
 static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
@@ -482,7 +589,7 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
        u32 stack[HDA_DSP_STACK_DUMP_SIZE];
 
        /* print ROM/FW status */
-       hda_dsp_get_status(sdev, level);
+       hda_dsp_get_state(sdev, level);
 
        if (flags & SOF_DBG_DUMP_REGS) {
                u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS);
@@ -669,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
        return tplg_filename;
 }
 
-static int dmic_topology_fixup(struct snd_sof_dev *sdev,
-                              const char **tplg_filename,
-                              const char *idisp_str,
-                              int *dmic_found)
+static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
+                                     const char **tplg_filename,
+                                     const char *idisp_str,
+                                     int *dmic_found,
+                                     bool tplg_fixup)
 {
-       const char *default_tplg_filename = *tplg_filename;
-       const char *fixed_tplg_filename;
        const char *dmic_str;
        int dmic_num;
 
@@ -701,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
                break;
        }
 
-       fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
-                                             idisp_str, dmic_str);
-       if (!fixed_tplg_filename)
-               return -ENOMEM;
+       if (tplg_fixup) {
+               const char *default_tplg_filename = *tplg_filename;
+               const char *fixed_tplg_filename;
+
+               fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
+                                                     idisp_str, dmic_str);
+               if (!fixed_tplg_filename)
+                       return -ENOMEM;
+               *tplg_filename = fixed_tplg_filename;
+       }
 
        dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
        *dmic_found = dmic_num;
-       *tplg_filename = fixed_tplg_filename;
 
        return 0;
 }
@@ -1114,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
                 *  - one external HDAudio codec
                 */
                if (!*mach && codec_num <= 2) {
+                       bool tplg_fixup;
+
                        hda_mach = snd_soc_acpi_intel_hda_machines;
 
                        dev_info(bus->dev, "using HDA machine driver %s now\n",
@@ -1125,8 +1238,15 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
                                idisp_str = "";
 
                        /* topology: use the info from hda_machines */
-                       tplg_filename = hda_mach->sof_tplg_filename;
-                       ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
+                       if (pdata->tplg_filename) {
+                               tplg_fixup = false;
+                               tplg_filename = pdata->tplg_filename;
+                       } else {
+                               tplg_fixup = true;
+                               tplg_filename = hda_mach->sof_tplg_filename;
+                       }
+                       ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
+                                                        tplg_fixup);
                        if (ret < 0)
                                return;
 
@@ -1290,30 +1410,37 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
                }
                if (mach && mach->link_mask) {
                        int dmic_num = 0;
+                       bool tplg_fixup;
+                       const char *tplg_filename;
 
                        mach->mach_params.links = mach->links;
                        mach->mach_params.link_mask = mach->link_mask;
                        mach->mach_params.platform = dev_name(sdev->dev);
-                       pdata->fw_filename = pdata->desc->default_fw_filename[pdata->ipc_type];
-                       pdata->tplg_filename = mach->sof_tplg_filename;
+
+                       if (pdata->tplg_filename) {
+                               tplg_fixup = false;
+                       } else {
+                               tplg_fixup = true;
+                               tplg_filename = mach->sof_tplg_filename;
+                       }
 
                        /*
                         * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
-                        * link 2 and 3, thus we only try to enable dmics if all conditions
-                        * are true:
-                        * a) link 2 and 3 are not used by SoundWire
+                        * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
+                        * if all conditions are true:
+                        * a) 2 or fewer links are used by SoundWire
                         * b) the NHLT table reports the presence of microphones
                         */
-                       if (!(mach->link_mask & GENMASK(3, 2))) {
-                               const char *tplg_filename = mach->sof_tplg_filename;
+                       if (hweight_long(mach->link_mask) <= 2) {
                                int ret;
 
-                               ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
+                               ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
+                                                                &dmic_num, tplg_fixup);
                                if (ret < 0)
                                        return NULL;
-
-                               pdata->tplg_filename = tplg_filename;
                        }
+                       if (tplg_fixup)
+                               pdata->tplg_filename = tplg_filename;
                        mach->mach_params.dmic_num = dmic_num;
 
                        dev_dbg(sdev->dev,
@@ -1359,18 +1486,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
        mach = snd_soc_acpi_find_machine(desc->machines);
        if (mach) {
                bool add_extension = false;
+               bool tplg_fixup = false;
 
                /*
                 * If tplg file name is overridden, use it instead of
                 * the one set in mach table
                 */
-               if (!sof_pdata->tplg_filename)
+               if (!sof_pdata->tplg_filename) {
                        sof_pdata->tplg_filename = mach->sof_tplg_filename;
+                       tplg_fixup = true;
+               }
 
                /* report to machine driver if any DMICs are found */
                mach->mach_params.dmic_num = check_dmic_num(sdev);
 
-               if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
+               if (tplg_fixup &&
+                   mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
                    mach->mach_params.dmic_num) {
                        tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
                                                       "%s%s%d%s",
@@ -1393,8 +1524,10 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
                /* report SSP link mask to machine driver */
                mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
 
-               if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
+               if (tplg_fixup &&
+                   mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
                    mach->mach_params.i2s_link_mask) {
+                       const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
                        int ssp_num;
 
                        if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
@@ -1404,6 +1537,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
                        /* fls returns 1-based results, SSPs indices are 0-based */
                        ssp_num = fls(mach->mach_params.i2s_link_mask) - 1;
 
+                       if (ssp_num >= chip->ssp_count) {
+                               dev_err(sdev->dev, "Invalid SSP %d, max on this platform is %d\n",
+                                       ssp_num, chip->ssp_count);
+                               return NULL;
+                       }
+
                        tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
                                                       "%s%s%d",
                                                       sof_pdata->tplg_filename,
@@ -1416,7 +1555,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
                        add_extension = true;
                }
 
-               if (add_extension) {
+               if (tplg_fixup && add_extension) {
                        tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
                                                       "%s%s",
                                                       sof_pdata->tplg_filename,
index 06476ffe96d73a77cdc74498c130f66e9cdb6313..5ef3e8775e364172b2dd0f69e057e3480872250e 100644 (file)
 
 #define HDA_DSP_STACK_DUMP_SIZE                        32
 
+/* ROM/FW status register */
+#define FSR_STATE_MASK                         GENMASK(23, 0)
+#define FSR_WAIT_STATE_MASK                    GENMASK(27, 24)
+#define FSR_MODULE_MASK                                GENMASK(30, 28)
+#define FSR_HALTED                             BIT(31)
+#define FSR_TO_STATE_CODE(x)                   ((x) & FSR_STATE_MASK)
+#define FSR_TO_WAIT_STATE_CODE(x)              (((x) & FSR_WAIT_STATE_MASK) >> 24)
+#define FSR_TO_MODULE_CODE(x)                  (((x) & FSR_MODULE_MASK) >> 28)
+
+/* Wait states */
+#define FSR_WAIT_FOR_IPC_BUSY                  0x1
+#define FSR_WAIT_FOR_IPC_DONE                  0x2
+#define FSR_WAIT_FOR_CACHE_INVALIDATION                0x3
+#define FSR_WAIT_FOR_LP_SRAM_OFF               0x4
+#define FSR_WAIT_FOR_DMA_BUFFER_FULL           0x5
+#define FSR_WAIT_FOR_CSE_CSR                   0x6
+
+/* Module codes */
+#define FSR_MOD_ROM                            0x0
+#define FSR_MOD_ROM_BYP                                0x1
+#define FSR_MOD_BASE_FW                                0x2
+#define FSR_MOD_LP_BOOT                                0x3
+#define FSR_MOD_BRNGUP                         0x4
+#define FSR_MOD_ROM_EXT                                0x5
+
+/* State codes (module dependent) */
+/* Module independent states */
+#define FSR_STATE_INIT                         0x0
+#define FSR_STATE_INIT_DONE                    0x1
+#define FSR_STATE_FW_ENTERED                   0x5
+
+/* ROM states */
+#define FSR_STATE_ROM_INIT                     FSR_STATE_INIT
+#define FSR_STATE_ROM_INIT_DONE                        FSR_STATE_INIT_DONE
+#define FSR_STATE_ROM_CSE_MANIFEST_LOADED      0x2
+#define FSR_STATE_ROM_FW_MANIFEST_LOADED       0x3
+#define FSR_STATE_ROM_FW_FW_LOADED             0x4
+#define FSR_STATE_ROM_FW_ENTERED               FSR_STATE_FW_ENTERED
+#define FSR_STATE_ROM_VERIFY_FEATURE_MASK      0x6
+#define FSR_STATE_ROM_GET_LOAD_OFFSET          0x7
+#define FSR_STATE_ROM_FETCH_ROM_EXT            0x8
+#define FSR_STATE_ROM_FETCH_ROM_EXT_DONE       0x9
+
+/* (ROM) CSE states */
+#define FSR_STATE_ROM_CSE_IMR_REQUEST                  0x10
+#define FSR_STATE_ROM_CSE_IMR_GRANTED                  0x11
+#define FSR_STATE_ROM_CSE_VALIDATE_IMAGE_REQUEST       0x12
+#define FSR_STATE_ROM_CSE_IMAGE_VALIDATED              0x13
+
+#define FSR_STATE_ROM_CSE_IPC_IFACE_INIT       0x20
+#define FSR_STATE_ROM_CSE_IPC_RESET_PHASE_1    0x21
+#define FSR_STATE_ROM_CSE_IPC_OPERATIONAL_ENTRY        0x22
+#define FSR_STATE_ROM_CSE_IPC_OPERATIONAL      0x23
+#define FSR_STATE_ROM_CSE_IPC_DOWN             0x24
+
+/* BRINGUP (or BRNGUP) states */
+#define FSR_STATE_BRINGUP_INIT                 FSR_STATE_INIT
+#define FSR_STATE_BRINGUP_INIT_DONE            FSR_STATE_INIT_DONE
+#define FSR_STATE_BRINGUP_HPSRAM_LOAD          0x2
+#define FSR_STATE_BRINGUP_UNPACK_START         0X3
+#define FSR_STATE_BRINGUP_IMR_RESTORE          0x4
+#define FSR_STATE_BRINGUP_FW_ENTERED           FSR_STATE_FW_ENTERED
+
 /* ROM  status/error values */
 #define HDA_DSP_ROM_STS_MASK                   GENMASK(23, 0)
 #define HDA_DSP_ROM_INIT                       0x1
@@ -419,6 +482,7 @@ enum sof_hda_D0_substate {
 /* represents DSP HDA controller frontend - i.e. host facing control */
 struct sof_intel_hda_dev {
        bool imrboot_supported;
+       bool skip_imr_boot;
 
        int boot_iteration;
 
@@ -605,6 +669,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned
                                              int direction);
 int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
                   struct hdac_ext_stream *hext_stream);
+int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
 #define HDA_CL_STREAM_FORMAT 0x40
 
 /* pre and post fw run ops */
@@ -716,6 +781,8 @@ extern struct snd_sof_dsp_ops sof_tgl_ops;
 int sof_tgl_ops_init(struct snd_sof_dev *sdev);
 extern struct snd_sof_dsp_ops sof_icl_ops;
 int sof_icl_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_mtl_ops;
+int sof_mtl_ops_init(struct snd_sof_dev *sdev);
 
 extern const struct sof_intel_dsp_desc apl_chip_info;
 extern const struct sof_intel_dsp_desc cnl_chip_info;
@@ -725,6 +792,7 @@ extern const struct sof_intel_dsp_desc tglh_chip_info;
 extern const struct sof_intel_dsp_desc ehl_chip_info;
 extern const struct sof_intel_dsp_desc jsl_chip_info;
 extern const struct sof_intel_dsp_desc adls_chip_info;
+extern const struct sof_intel_dsp_desc mtl_chip_info;
 
 /* Probes support */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
@@ -767,11 +835,13 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_f
 extern int sof_hda_position_quirk;
 
 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops);
+void hda_ops_free(struct snd_sof_dev *sdev);
 
 /* IPC4 */
 irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
 int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
 irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context);
 int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
+extern struct sdw_intel_ops sdw_callback;
 
 #endif
index f19517dffd62426a42958e2069f2728a90b80b50..4e37b7fe06274db5356be18e5056a5170eba82ca 100644 (file)
@@ -152,6 +152,7 @@ const struct sof_intel_dsp_desc icl_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_2_0,
 };
 EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
new file mode 100644 (file)
index 0000000..96239eb
--- /dev/null
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+//
+
+/*
+ * Hardware interface for audio DSP on Meteorlake.
+ */
+
+#include <linux/firmware.h>
+#include <sound/sof/ipc4/header.h>
+#include "../ipc4-priv.h"
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+#include "mtl.h"
+
+static const struct snd_sof_debugfs_map mtl_dsp_debugfs[] = {
+       {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
+       {"pp", HDA_DSP_PP_BAR,  0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
+       {"dsp", HDA_DSP_BAR,  0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
+static void mtl_ipc_host_done(struct snd_sof_dev *sdev)
+{
+       /*
+        * clear busy interrupt to tell dsp controller this interrupt has been accepted,
+        * not trigger it again
+        */
+       snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR,
+                                      MTL_DSP_REG_HFIPCXTDR_BUSY, MTL_DSP_REG_HFIPCXTDR_BUSY);
+       /*
+        * clear busy bit to ack dsp the msg has been processed and send reply msg to dsp
+        */
+       snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDA,
+                                      MTL_DSP_REG_HFIPCXTDA_BUSY, 0);
+}
+
+static void mtl_ipc_dsp_done(struct snd_sof_dev *sdev)
+{
+       /*
+        * set DONE bit - tell DSP we have received the reply msg from DSP, and processed it,
+        * don't send more reply to host
+        */
+       snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA,
+                                      MTL_DSP_REG_HFIPCXIDA_DONE, MTL_DSP_REG_HFIPCXIDA_DONE);
+
+       /* unmask Done interrupt */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,
+                               MTL_DSP_REG_HFIPCXCTL_DONE, MTL_DSP_REG_HFIPCXCTL_DONE);
+}
+
+/* Check if an IPC IRQ occurred */
+static bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
+{
+       u32 irq_status;
+       u32 hfintipptr;
+
+       /* read Interrupt IP Pointer */
+       hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
+       irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS);
+
+       dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status);
+
+       if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_IPC))
+               return true;
+
+       return false;
+}
+
+/* Check if an SDW IRQ occurred */
+static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
+{
+       u32 irq_status;
+       u32 hfintipptr;
+
+       /* read Interrupt IP Pointer */
+       hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
+       irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr + MTL_DSP_IRQSTS);
+
+       if (irq_status != U32_MAX && (irq_status & MTL_DSP_IRQSTS_SDW))
+               return true;
+
+       return false;
+}
+
+static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+{
+       struct sof_ipc4_msg *msg_data = msg->msg_data;
+
+       /* send the message via mailbox */
+       if (msg_data->data_size)
+               sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
+                                 msg_data->data_size);
+
+       snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDDY,
+                         msg_data->extension);
+       snd_sof_dsp_write(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDR,
+                         msg_data->primary | MTL_DSP_REG_HFIPCXIDR_BUSY);
+
+       return 0;
+}
+
+static void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
+
+       /* enable IPC DONE and BUSY interrupts */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
+                               MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE,
+                               MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE);
+}
+
+static void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
+
+       /* disable IPC DONE and BUSY interrupts */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
+                               MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);
+}
+
+static int mtl_enable_interrupts(struct snd_sof_dev *sdev)
+{
+       u32 hfintipptr;
+       u32 irqinten;
+       u32 host_ipc;
+       u32 hipcie;
+       int ret;
+
+       /* read Interrupt IP Pointer */
+       hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
+
+       /* Enable Host IPC and SOUNDWIRE */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr,
+                               MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK,
+                               MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK);
+
+       /* check if operation was successful */
+       host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
+       irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
+                                           (irqinten & host_ipc) == host_ipc,
+                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0) {
+               dev_err(sdev->dev, "failed to enable Host IPC and/or SOUNDWIRE\n");
+               return ret;
+       }
+
+       /* Set Host IPC interrupt enable */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE,
+                               MTL_DSP_REG_HfHIPCIE_IE_MASK, MTL_DSP_REG_HfHIPCIE_IE_MASK);
+
+       /* check if operation was successful */
+       host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK;
+       hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
+                                           (hipcie & host_ipc) == host_ipc,
+                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0) {
+               dev_err(sdev->dev, "failed to set Host IPC interrupt enable\n");
+               return ret;
+       }
+
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE,
+                               MTL_DSP_REG_HfSNDWIE_IE_MASK, MTL_DSP_REG_HfSNDWIE_IE_MASK);
+       host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK;
+       hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
+                                           (hipcie & host_ipc) == host_ipc,
+                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to set SoundWire IPC interrupt enable\n");
+
+       return ret;
+}
+
+static int mtl_disable_interrupts(struct snd_sof_dev *sdev)
+{
+       u32 hfintipptr;
+       u32 irqinten;
+       u32 host_ipc;
+       u32 hipcie;
+       int ret1;
+       int ret;
+
+       /* read Interrupt IP Pointer */
+       hfintipptr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFINTIPPTR) & MTL_HFINTIPPTR_PTR_MASK;
+
+       /* Disable Host IPC and SOUNDWIRE */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, hfintipptr,
+                               MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK, 0);
+
+       /* check if operation was successful */
+       host_ipc = MTL_IRQ_INTEN_L_HOST_IPC_MASK | MTL_IRQ_INTEN_L_SOUNDWIRE_MASK;
+       irqinten = snd_sof_dsp_read(sdev, HDA_DSP_BAR, hfintipptr);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, hfintipptr, irqinten,
+                                           (irqinten & host_ipc) == 0,
+                                           HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
+       /* Continue to disable other interrupts when error happens */
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to disable Host IPC and SoundWire\n");
+
+       /* Set Host IPC interrupt disable */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE,
+                               MTL_DSP_REG_HfHIPCIE_IE_MASK, 0);
+
+       /* check if operation was successful */
+       host_ipc = MTL_DSP_REG_HfHIPCIE_IE_MASK;
+       hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE);
+       ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfHIPCIE, hipcie,
+                                            (hipcie & host_ipc) == 0,
+                                            HDA_DSP_REG_POLL_INTERVAL_US,
+                                            HDA_DSP_RESET_TIMEOUT_US);
+       if (ret1 < 0) {
+               dev_err(sdev->dev, "failed to set Host IPC interrupt disable\n");
+               if (!ret)
+                       ret = ret1;
+       }
+
+       /* Set SoundWire IPC interrupt disable */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE,
+                               MTL_DSP_REG_HfSNDWIE_IE_MASK, 0);
+       host_ipc = MTL_DSP_REG_HfSNDWIE_IE_MASK;
+       hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE);
+       ret1 = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP_REG_HfSNDWIE, hipcie,
+                                            (hipcie & host_ipc) == 0,
+                                            HDA_DSP_REG_POLL_INTERVAL_US,
+                                            HDA_DSP_RESET_TIMEOUT_US);
+       if (ret1 < 0) {
+               dev_err(sdev->dev, "failed to set SoundWire IPC interrupt disable\n");
+               if (!ret)
+                       ret = ret1;
+       }
+
+       return ret;
+}
+
+/* pre fw run operations */
+static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
+{
+       u32 dsphfpwrsts;
+       u32 dsphfdsscs;
+       u32 cpa;
+       u32 pgs;
+       int ret;
+
+       /* Set the DSP subsystem power on */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
+                               MTL_HFDSSCS_SPA_MASK, MTL_HFDSSCS_SPA_MASK);
+
+       /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+       usleep_range(1000, 1010);
+
+       /* poll with timeout to check if operation successful */
+       cpa = MTL_HFDSSCS_CPA_MASK;
+       dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,
+                                           (dsphfdsscs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
+                                           HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0) {
+               dev_err(sdev->dev, "failed to enable DSP subsystem\n");
+               return ret;
+       }
+
+       /* Power up gated-DSP-0 domain in order to access the DSP shim register block. */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
+                               MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG);
+
+       usleep_range(1000, 1010);
+
+       /* poll with timeout to check if operation successful */
+       pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK;
+       dsphfpwrsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFPWRSTS);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts,
+                                           (dsphfpwrsts & pgs) == pgs,
+                                           HDA_DSP_REG_POLL_INTERVAL_US,
+                                           HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to power up gated DSP domain\n");
+
+       /* make sure SoundWire is not power-gated */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, MTL_HFPWRCTL,
+                               MTL_HfPWRCTL_WPIOXPG(1), MTL_HfPWRCTL_WPIOXPG(1));
+       return ret;
+}
+
+static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+{
+       int ret;
+
+       if (sdev->first_boot) {
+               struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+               ret = hda_sdw_startup(sdev);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "could not startup SoundWire links\n");
+                       return ret;
+               }
+
+               /* Check if IMR boot is usable */
+               if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT))
+                       hdev->imrboot_supported = true;
+       }
+
+       hda_sdw_int_enable(sdev, true);
+       return 0;
+}
+
+static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+{
+       char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
+       u32 romdbgsts;
+       u32 romdbgerr;
+       u32 fwsts;
+       u32 fwlec;
+
+       fwsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_STS);
+       fwlec = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_ROM_ERROR);
+       romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY);
+       romdbgerr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY_ERROR);
+
+       dev_err(sdev->dev, "ROM status: %#x, ROM error: %#x\n", fwsts, fwlec);
+       dev_err(sdev->dev, "ROM debug status: %#x, ROM debug error: %#x\n", romdbgsts,
+               romdbgerr);
+       romdbgsts = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFFLGPXQWY + 0x8 * 3);
+       dev_printk(level, sdev->dev, "ROM feature bit%s enabled\n",
+                  romdbgsts & BIT(24) ? "" : " not");
+}
+
+static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)
+{
+       int val;
+
+       val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE);
+       if (val != U32_MAX && val & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK)
+               return true;
+
+       return false;
+}
+
+static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)
+{
+       unsigned int cpa;
+       u32 dspcxctl;
+       int ret;
+
+       /* Only the primary core can be powered up by the host */
+       if (core != SOF_DSP_PRIMARY_CORE || mtl_dsp_primary_core_is_enabled(sdev))
+               return 0;
+
+       /* Program the owner of the IP & shim registers (10: Host CPU) */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
+                               MTL_DSP2CXCTL_PRIMARY_CORE_OSEL,
+                               0x2 << MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT);
+
+       /* enable SPA bit */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
+                               MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK,
+                               MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK);
+
+       /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+       usleep_range(1000, 1010);
+
+       /* poll with timeout to check if operation successful */
+       cpa = MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK;
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
+                                           (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
+                                           HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0)
+               dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
+                       __func__);
+
+       return ret;
+}
+
+static int mtl_dsp_core_power_down(struct snd_sof_dev *sdev, int core)
+{
+       u32 dspcxctl;
+       int ret;
+
+       /* Only the primary core can be powered down by the host */
+       if (core != SOF_DSP_PRIMARY_CORE || !mtl_dsp_primary_core_is_enabled(sdev))
+               return 0;
+
+       /* disable SPA bit */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE,
+                               MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK, 0);
+
+       /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+       usleep_range(1000, 1010);
+
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
+                                           !(dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK),
+                                           HDA_DSP_REG_POLL_INTERVAL_US,
+                                           HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to power down primary core\n");
+
+       return ret;
+}
+
+static int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
+       unsigned int status;
+       u32 ipc_hdr;
+       int ret;
+
+       /* step 1: purge FW request */
+       ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL;
+       if (!imr_boot)
+               ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9);
+
+       snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
+
+       /* step 2: power up primary core */
+       ret = mtl_dsp_core_power_up(sdev, SOF_DSP_PRIMARY_CORE);
+       if (ret < 0) {
+               if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+                       dev_err(sdev->dev, "dsp core 0/1 power up failed\n");
+               goto err;
+       }
+
+       dev_dbg(sdev->dev, "Primary core power up successful\n");
+
+       /* step 3: wait for IPC DONE bit from ROM */
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, chip->ipc_ack, status,
+                                           ((status & chip->ipc_ack_mask) == chip->ipc_ack_mask),
+                                           HDA_DSP_REG_POLL_INTERVAL_US, MTL_DSP_PURGE_TIMEOUT_US);
+       if (ret < 0) {
+               if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+                       dev_err(sdev->dev, "timeout waiting for purge IPC done\n");
+               goto err;
+       }
+
+       /* set DONE bit to clear the reply IPC message */
+       snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask,
+                                      chip->ipc_ack_mask);
+
+       /* step 4: enable interrupts */
+       ret = mtl_enable_interrupts(sdev);
+       if (ret < 0) {
+               if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+                       dev_err(sdev->dev, "%s: failed to enable interrupts\n", __func__);
+               goto err;
+       }
+
+       mtl_enable_ipc_interrupts(sdev);
+
+       /*
+        * ACE workaround: don't wait for ROM INIT.
+        * The platform cannot catch ROM_INIT_DONE because of a very short
+        * timing window. Follow the recommendations and skip this part.
+        */
+
+       return 0;
+
+err:
+       snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0);
+       mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
+       return ret;
+}
+
+static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
+{
+       struct sof_ipc4_msg notification_data = {{ 0 }};
+       struct snd_sof_dev *sdev = context;
+       bool ipc_irq = false;
+       u32 hipcida;
+       u32 hipctdr;
+
+       hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
+
+       /* reply message from DSP */
+       if (hipcida & MTL_DSP_REG_HFIPCXIDA_DONE) {
+               /* DSP received the message */
+               snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL,
+                                       MTL_DSP_REG_HFIPCXCTL_DONE, 0);
+
+               mtl_ipc_dsp_done(sdev);
+
+               ipc_irq = true;
+       }
+
+       hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
+       if (hipctdr & MTL_DSP_REG_HFIPCXTDR_BUSY) {
+               /* Message from DSP (reply or notification) */
+               u32 extension = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDDY);
+               u32 primary = hipctdr & MTL_DSP_REG_HFIPCXTDR_MSG_MASK;
+
+               /*
+                * ACE fw sends a new fw ipc message to host to
+                * notify the status of the last host ipc message
+                */
+               if (primary & SOF_IPC4_MSG_DIR_MASK) {
+                       /* Reply received */
+                       if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+                               struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
+
+                               data->primary = primary;
+                               data->extension = extension;
+
+                               spin_lock_irq(&sdev->ipc_lock);
+
+                               snd_sof_ipc_get_reply(sdev);
+                               snd_sof_ipc_reply(sdev, data->primary);
+
+                               spin_unlock_irq(&sdev->ipc_lock);
+                       } else {
+                               dev_dbg_ratelimited(sdev->dev,
+                                                   "IPC reply before FW_READY: %#x|%#x\n",
+                                                   primary, extension);
+                       }
+               } else {
+                       /* Notification received */
+                       notification_data.primary = primary;
+                       notification_data.extension = extension;
+
+                       sdev->ipc->msg.rx_data = &notification_data;
+                       snd_sof_ipc_msgs_rx(sdev);
+                       sdev->ipc->msg.rx_data = NULL;
+               }
+
+               mtl_ipc_host_done(sdev);
+
+               ipc_irq = true;
+       }
+
+       if (!ipc_irq) {
+               /* This interrupt is not shared so no need to return IRQ_NONE. */
+               dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+       return MTL_DSP_MBOX_UPLINK_OFFSET;
+}
+
+static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+       return MTL_SRAM_WINDOW_OFFSET(id);
+}
+
+static int mtl_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
+{
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       struct hdac_bus *bus = sof_to_bus(sdev);
+#endif
+       u32 dsphfdsscs;
+       u32 cpa;
+       int ret;
+       int i;
+
+       mtl_disable_ipc_interrupts(sdev);
+       ret = mtl_disable_interrupts(sdev);
+       if (ret)
+               return ret;
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       hda_codec_jack_wake_enable(sdev, runtime_suspend);
+       /* power down all hda link */
+       snd_hdac_ext_bus_link_power_down_all(bus);
+#endif
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
+                               MTL_HFPWRCTL_WPDSPHPXPG, 0);
+
+       /* Set the DSP subsystem power down */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
+                               MTL_HFDSSCS_SPA_MASK, 0);
+
+       /* Wait for unstable CPA read (1 then 0 then 1) just after setting SPA bit */
+       usleep_range(1000, 1010);
+
+       /* poll with timeout to check if operation successful */
+       cpa = MTL_HFDSSCS_CPA_MASK;
+       dsphfdsscs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);
+       ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFDSSCS, dsphfdsscs,
+                                           (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US,
+                                       HDA_DSP_RESET_TIMEOUT_US);
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to disable DSP subsystem\n");
+
+       /* reset ref counts for all cores */
+       for (i = 0; i < chip->cores_num; i++)
+               sdev->dsp_core_ref_count[i] = 0;
+
+       /* TODO: need to reset controller? */
+
+       /* display codec can be powered off after link reset */
+       hda_codec_i915_display_power(sdev, false);
+
+       return 0;
+}
+
+static int mtl_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
+{
+       const struct sof_dsp_power_state target_dsp_state = {
+               .state = target_state,
+               .substate = target_state == SOF_DSP_PM_D0 ?
+                               SOF_HDA_DSP_PM_D0I3 : 0,
+       };
+       int ret;
+
+       ret = mtl_suspend(sdev, false);
+       if (ret < 0)
+               return ret;
+
+       return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
+}
+
+static int mtl_dsp_runtime_suspend(struct snd_sof_dev *sdev)
+{
+       const struct sof_dsp_power_state target_state = {
+               .state = SOF_DSP_PM_D3,
+       };
+       int ret;
+
+       ret = mtl_suspend(sdev, true);
+       if (ret < 0)
+               return ret;
+
+       return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int mtl_resume(struct snd_sof_dev *sdev, bool runtime_resume)
+{
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       struct hdac_ext_link *hlink = NULL;
+#endif
+
+       /* display codec must be powered before link reset */
+       hda_codec_i915_display_power(sdev, true);
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       /* check jack status */
+       if (runtime_resume) {
+               hda_codec_jack_wake_enable(sdev, false);
+               if (sdev->system_suspend_target == SOF_SUSPEND_NONE)
+                       hda_codec_jack_check(sdev);
+       }
+
+       /* turn off the links that were off before suspend */
+       list_for_each_entry(hlink, &bus->hlink_list, list) {
+               if (!hlink->ref_count)
+                       snd_hdac_ext_bus_link_power_down(hlink);
+       }
+
+       /* check dma status and clean up CORB/RIRB buffers */
+       if (!bus->cmd_dma_state)
+               snd_hdac_bus_stop_cmd_io(bus);
+#endif
+
+       return 0;
+}
+
+static int mtl_dsp_resume(struct snd_sof_dev *sdev)
+{
+       const struct sof_dsp_power_state target_state = {
+               .state = SOF_DSP_PM_D0,
+               .substate = SOF_HDA_DSP_PM_D0I0,
+       };
+       int ret;
+
+       ret = mtl_resume(sdev, false);
+       if (ret < 0)
+               return ret;
+
+       return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int mtl_dsp_runtime_resume(struct snd_sof_dev *sdev)
+{
+       const struct sof_dsp_power_state target_state = {
+               .state = SOF_DSP_PM_D0,
+       };
+       int ret;
+
+       ret = mtl_resume(sdev, true);
+       if (ret < 0)
+               return ret;
+
+       return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static void mtl_ipc_dump(struct snd_sof_dev *sdev)
+{
+       u32 hipcctl;
+       u32 hipcida;
+       u32 hipctdr;
+
+       /* read IPC status */
+       hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXIDA);
+       hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXCTL);
+       hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP_REG_HFIPCXTDR);
+
+       /* dump the IPC regs */
+       /* TODO: parse the raw msg */
+       dev_err(sdev->dev,
+               "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
+               hipcida, hipctdr, hipcctl);
+}
+
+/* Meteorlake ops */
+struct snd_sof_dsp_ops sof_mtl_ops;
+EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+int sof_mtl_ops_init(struct snd_sof_dev *sdev)
+{
+       struct sof_ipc4_fw_data *ipc4_data;
+
+       /* common defaults */
+       memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+       /* shutdown */
+       sof_mtl_ops.shutdown = hda_dsp_shutdown;
+
+       /* doorbell */
+       sof_mtl_ops.irq_thread = mtl_ipc_irq_thread;
+
+       /* ipc */
+       sof_mtl_ops.send_msg = mtl_ipc_send_msg;
+       sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
+       sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
+
+       /* debug */
+       sof_mtl_ops.debug_map = mtl_dsp_debugfs;
+       sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);
+       sof_mtl_ops.dbg_dump = mtl_dsp_dump;
+       sof_mtl_ops.ipc_dump = mtl_ipc_dump;
+
+       /* pre/post fw run */
+       sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
+       sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run;
+
+       /* parse platform specific extended manifest */
+       sof_mtl_ops.parse_platform_ext_manifest = NULL;
+
+       /* dsp core get/put */
+       /* TODO: add core_get and core_put */
+
+       /* PM */
+       sof_mtl_ops.suspend = mtl_dsp_suspend;
+       sof_mtl_ops.resume = mtl_dsp_resume;
+       sof_mtl_ops.runtime_suspend = mtl_dsp_runtime_suspend;
+       sof_mtl_ops.runtime_resume = mtl_dsp_runtime_resume;
+
+       sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
+       if (!sdev->private)
+               return -ENOMEM;
+
+       ipc4_data = sdev->private;
+       ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
+
+       /* set DAI ops */
+       hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
+
+       return 0;
+};
+EXPORT_SYMBOL_NS(sof_mtl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+const struct sof_intel_dsp_desc mtl_chip_info = {
+       .cores_num = 3,
+       .init_core_mask = BIT(0),
+       .host_managed_cores_mask = BIT(0),
+       .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+       .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+       .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+       .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+       .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+       .rom_status_reg = MTL_DSP_ROM_STS,
+       .rom_init_timeout       = 300,
+       .ssp_count = ICL_SSP_COUNT,
+       .ssp_base_offset = CNL_SSP_BASE_OFFSET,
+       .sdw_shim_base = SDW_SHIM_BASE_ACE,
+       .sdw_alh_base = SDW_ALH_BASE_ACE,
+       .check_sdw_irq = mtl_dsp_check_sdw_irq,
+       .check_ipc_irq = mtl_dsp_check_ipc_irq,
+       .cl_init = mtl_dsp_cl_init,
+       .hw_ip_version = SOF_INTEL_ACE_1_0,
+};
+EXPORT_SYMBOL_NS(mtl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
new file mode 100644 (file)
index 0000000..788bf0e
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2020-2022 Intel Corporation. All rights reserved.
+ */
+
+/* DSP Registers */
+#define MTL_HFDSSCS                    0x1000
+#define MTL_HFDSSCS_SPA_MASK           BIT(16)
+#define MTL_HFDSSCS_CPA_MASK           BIT(24)
+#define MTL_HFSNDWIE                   0x114C
+#define MTL_HFPWRCTL                   0x1D18
+#define MTL_HfPWRCTL_WPIOXPG(x)                BIT((x) + 8)
+#define MTL_HFPWRCTL_WPDSPHPXPG                BIT(0)
+#define MTL_HFPWRSTS                   0x1D1C
+#define MTL_HFPWRSTS_DSPHPXPGS_MASK    BIT(0)
+#define MTL_HFINTIPPTR                 0x1108
+#define MTL_IRQ_INTEN_L_HOST_IPC_MASK  BIT(0)
+#define MTL_IRQ_INTEN_L_SOUNDWIRE_MASK BIT(6)
+#define MTL_HFINTIPPTR_PTR_MASK                GENMASK(20, 0)
+
+#define MTL_DSP2CXCAP_PRIMARY_CORE     0x178D00
+#define MTL_DSP2CXCTL_PRIMARY_CORE     0x178D04
+#define MTL_DSP2CXCTL_PRIMARY_CORE_SPA_MASK BIT(0)
+#define MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK BIT(8)
+#define MTL_DSP2CXCTL_PRIMARY_CORE_OSEL GENMASK(25, 24)
+#define MTL_DSP2CXCTL_PRIMARY_CORE_OSEL_SHIFT 24
+
+/* IPC Registers */
+#define MTL_DSP_REG_HFIPCXTDR          0x73200
+#define MTL_DSP_REG_HFIPCXTDR_BUSY     BIT(31)
+#define MTL_DSP_REG_HFIPCXTDR_MSG_MASK GENMASK(30, 0)
+#define MTL_DSP_REG_HFIPCXTDA          0x73204
+#define MTL_DSP_REG_HFIPCXTDA_BUSY     BIT(31)
+#define MTL_DSP_REG_HFIPCXIDR          0x73210
+#define MTL_DSP_REG_HFIPCXIDR_BUSY     BIT(31)
+#define MTL_DSP_REG_HFIPCXIDR_MSG_MASK GENMASK(30, 0)
+#define MTL_DSP_REG_HFIPCXIDA          0x73214
+#define MTL_DSP_REG_HFIPCXIDA_DONE     BIT(31)
+#define MTL_DSP_REG_HFIPCXIDA_MSG_MASK GENMASK(30, 0)
+#define MTL_DSP_REG_HFIPCXCTL          0x73228
+#define MTL_DSP_REG_HFIPCXCTL_BUSY     BIT(0)
+#define MTL_DSP_REG_HFIPCXCTL_DONE     BIT(1)
+#define MTL_DSP_REG_HFIPCXTDDY         0x73300
+#define MTL_DSP_REG_HFIPCXIDDY         0x73380
+#define MTL_DSP_REG_HfHIPCIE           0x1140
+#define MTL_DSP_REG_HfHIPCIE_IE_MASK   BIT(0)
+#define MTL_DSP_REG_HfSNDWIE           0x114C
+#define MTL_DSP_REG_HfSNDWIE_IE_MASK   GENMASK(3, 0)
+
+#define MTL_DSP_IRQSTS                 0x20
+#define MTL_DSP_IRQSTS_IPC             BIT(0)
+#define MTL_DSP_IRQSTS_SDW             BIT(6)
+
+#define MTL_DSP_PURGE_TIMEOUT_US       20000000 /* 20s */
+#define MTL_DSP_REG_POLL_INTERVAL_US   10      /* 10 us */
+
+/* Memory windows */
+#define MTL_SRAM_WINDOW_OFFSET(x)      (0x180000 + 0x8000 * (x))
+
+#define MTL_DSP_MBOX_UPLINK_OFFSET     (MTL_SRAM_WINDOW_OFFSET(0) + 0x1000)
+#define MTL_DSP_MBOX_UPLINK_SIZE       0x1000
+#define MTL_DSP_MBOX_DOWNLINK_OFFSET   MTL_SRAM_WINDOW_OFFSET(1)
+#define MTL_DSP_MBOX_DOWNLINK_SIZE     0x1000
+
+/* FW registers */
+#define MTL_DSP_ROM_STS                        MTL_SRAM_WINDOW_OFFSET(0) /* ROM status */
+#define MTL_DSP_ROM_ERROR              (MTL_SRAM_WINDOW_OFFSET(0) + 0x4) /* ROM error code */
+
+#define MTL_DSP_REG_HFFLGPXQWY         0x163200 /* ROM debug status */
+#define MTL_DSP_REG_HFFLGPXQWY_ERROR   0x163204 /* ROM debug error code */
+#define MTL_DSP_REG_HfIMRIS1           0x162088
+#define MTL_DSP_REG_HfIMRIS1_IU_MASK   BIT(0)
+
index 2de3658eb8178ca1f81726cd3a6ed8390419e2ce..998e219011f01c64273babb746fcbabdfef15440 100644 (file)
@@ -44,6 +44,7 @@ static const struct sof_dev_desc bxt_desc = {
        .nocodec_tplg_filename = "sof-apl-nocodec.tplg",
        .ops = &sof_apl_ops,
        .ops_init = sof_apl_ops_init,
+       .ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc glk_desc = {
index 87e587aef9c9d53a4ba075829e9e86142e99336d..c797356f7028b2d39a0b47f054b5867d18e33986 100644 (file)
@@ -73,6 +73,7 @@ static const struct sof_dev_desc cfl_desc = {
        .nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
        .ops = &sof_cnl_ops,
        .ops_init = sof_cnl_ops_init,
+       .ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc cml_desc = {
index 1c7f16ce531e0d097e1b56b7cb9a4280fb9f6428..48f24f8ace26184041e352dbb760f368e7e9108f 100644 (file)
@@ -45,6 +45,7 @@ static const struct sof_dev_desc icl_desc = {
        .nocodec_tplg_filename = "sof-icl-nocodec.tplg",
        .ops = &sof_icl_ops,
        .ops_init = sof_icl_ops_init,
+       .ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc jsl_desc = {
diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c
new file mode 100644 (file)
index 0000000..899b00d
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2018-2022 Intel Corporation. All rights reserved.
+//
+// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.h"
+#include "mtl.h"
+
+static const struct sof_dev_desc mtl_desc = {
+       .use_acpi_target_states = true,
+       .machines               = snd_soc_acpi_intel_mtl_machines,
+       .alt_machines           = snd_soc_acpi_intel_mtl_sdw_machines,
+       .resindex_lpe_base      = 0,
+       .resindex_pcicfg_base   = -1,
+       .resindex_imr_base      = -1,
+       .irqindex_host_ipc      = -1,
+       .chip_info = &mtl_chip_info,
+       .ipc_supported_mask     = BIT(SOF_INTEL_IPC4),
+       .ipc_default            = SOF_INTEL_IPC4,
+       .default_fw_path = {
+               [SOF_INTEL_IPC4] = "intel/sof-ipc4/mtl",
+       },
+       .default_tplg_path = {
+               [SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
+       },
+       .default_fw_filename = {
+               [SOF_INTEL_IPC4] = "dsp_basefw.bin",
+       },
+       .nocodec_tplg_filename = "sof-mtl-nocodec.tplg",
+       .ops = &sof_mtl_ops,
+       .ops_init = sof_mtl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+       { PCI_DEVICE(0x8086, 0x7E28), /* MTL */
+               .driver_data = (unsigned long)&mtl_desc},
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_mtl_driver = {
+       .name = "sof-audio-pci-intel-mtl",
+       .id_table = sof_pci_ids,
+       .probe = hda_pci_intel_probe,
+       .remove = sof_pci_remove,
+       .shutdown = sof_pci_shutdown,
+       .driver = {
+               .pm = &sof_pci_pm,
+       },
+};
+module_pci_driver(snd_sof_pci_intel_mtl_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
index 58a9bd92a23766c21a550b8e6c1cc3ee3bc3675b..ccc44ba3ad94d767123b7b873e973600b91f92c5 100644 (file)
@@ -73,6 +73,7 @@ static const struct sof_dev_desc tglh_desc = {
        .nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
        .ops = &sof_tgl_ops,
        .ops_init = sof_tgl_ops_init,
+       .ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc ehl_desc = {
index 1fd7b485d8212efb190a95a42e24298d2fc0902c..638159bee864515e93c75829cff7561b4c36c814 100644 (file)
@@ -20,6 +20,7 @@ enum sof_intel_hw_ip_version {
        SOF_INTEL_CAVS_1_8,     /* CannonLake, CometLake, CoffeeLake */
        SOF_INTEL_CAVS_2_0,     /* IceLake, JasperLake */
        SOF_INTEL_CAVS_2_5,     /* TigerLake, AlderLake */
+       SOF_INTEL_ACE_1_0,      /* MeteorLake */
 };
 
 /*
@@ -185,6 +186,7 @@ struct sof_intel_dsp_desc {
        enum sof_intel_hw_ip_version hw_ip_version;
        bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
        bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
+       int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
 };
 
 extern struct snd_sof_dsp_ops sof_tng_ops;
index 1ddc492f1b13a9365dbbc3a338b1419af32fbb0b..6dfb4786c7824620556aa564b6f9243e5e0fb034 100644 (file)
@@ -24,40 +24,30 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
 
 static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
 {
-       struct sof_ipc_pm_core_config pm_core_config = {
-               .hdr = {
-                       .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
-                       .size = sizeof(pm_core_config),
-               },
-               .enable_mask = sdev->enabled_cores_mask | BIT(core),
-       };
+       const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
 
        /* power up primary core if not already powered up and return */
        if (core == SOF_DSP_PRIMARY_CORE)
                return hda_dsp_enable_core(sdev, BIT(core));
 
-       /* notify DSP for secondary cores */
-       return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
-                                &pm_core_config, sizeof(pm_core_config));
+       if (pm_ops->set_core_state)
+               return pm_ops->set_core_state(sdev, core, true);
+
+       return 0;
 }
 
 static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
 {
-       struct sof_ipc_pm_core_config pm_core_config = {
-               .hdr = {
-                       .cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
-                       .size = sizeof(pm_core_config),
-               },
-               .enable_mask = sdev->enabled_cores_mask & ~BIT(core),
-       };
+       const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
 
        /* power down primary core and return */
        if (core == SOF_DSP_PRIMARY_CORE)
                return hda_dsp_core_reset_power_down(sdev, BIT(core));
 
-       /* notify DSP for secondary cores */
-       return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
-                                &pm_core_config, sizeof(pm_core_config));
+       if (pm_ops->set_core_state)
+               return pm_ops->set_core_state(sdev, core, false);
+
+       return 0;
 }
 
 /* Tigerlake ops */
@@ -137,6 +127,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_2_5,
 };
 EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@@ -159,6 +150,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_2_5,
 };
 EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@@ -181,6 +173,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_2_5,
 };
 EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@@ -203,6 +196,7 @@ const struct sof_intel_dsp_desc adls_chip_info = {
        .sdw_alh_base = SDW_ALH_BASE,
        .check_sdw_irq  = hda_common_check_sdw_irq,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
+       .cl_init = cl_dsp_init,
        .hw_ip_version = SOF_INTEL_CAVS_2_5,
 };
 EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
index c5aef5fc056b59f1da77d379f6bfd903abb46257..6ed3f9b6a0c4e60084d98ac022992d903c815bec 100644 (file)
@@ -155,12 +155,22 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
 
        init_waitqueue_head(&msg->waitq);
 
-       /*
-        * Use IPC3 ops as it is the only available version now. With the addition of new IPC
-        * versions, this will need to be modified to use the selected version at runtime.
-        */
-       ipc->ops = &ipc3_ops;
-       ops = ipc->ops;
+       switch (sdev->pdata->ipc_type) {
+#if defined(CONFIG_SND_SOC_SOF_IPC3)
+       case SOF_IPC:
+               ops = &ipc3_ops;
+               break;
+#endif
+#if defined(CONFIG_SND_SOC_SOF_INTEL_IPC4)
+       case SOF_INTEL_IPC4:
+               ops = &ipc4_ops;
+               break;
+#endif
+       default:
+               dev_err(sdev->dev, "Not supported IPC version: %d\n",
+                       sdev->pdata->ipc_type);
+               return NULL;
+       }
 
        /* check for mandatory ops */
        if (!ops->tx_msg || !ops->rx_msg || !ops->set_get_data || !ops->get_reply) {
@@ -190,6 +200,8 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
                return NULL;
        }
 
+       ipc->ops = ops;
+
        return ipc;
 }
 EXPORT_SYMBOL(snd_sof_ipc_init);
index b4e1343f9138f0251eaf73866400deabb8487924..b815b0244d9e43b82d32cf238a0e194c557c447d 100644 (file)
@@ -18,6 +18,7 @@
 enum sof_dtrace_state {
        SOF_DTRACE_DISABLED,
        SOF_DTRACE_STOPPED,
+       SOF_DTRACE_INITIALIZING,
        SOF_DTRACE_ENABLED,
 };
 
@@ -32,6 +33,15 @@ struct sof_dtrace_priv {
        enum sof_dtrace_state dtrace_state;
 };
 
+static bool trace_pos_update_expected(struct sof_dtrace_priv *priv)
+{
+       if (priv->dtrace_state == SOF_DTRACE_ENABLED ||
+           priv->dtrace_state == SOF_DTRACE_INITIALIZING)
+               return true;
+
+       return false;
+}
+
 static int trace_filter_append_elem(struct snd_sof_dev *sdev, u32 key, u32 value,
                                    struct sof_ipc_trace_filter_elem *elem_list,
                                    int capacity, int *counter)
@@ -157,9 +167,8 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
        msg->elem_cnt = num_elems;
        memcpy(&msg->elems[0], elems, num_elems * sizeof(*elems));
 
-       ret = pm_runtime_get_sync(sdev->dev);
+       ret = pm_runtime_resume_and_get(sdev->dev);
        if (ret < 0 && ret != -EACCES) {
-               pm_runtime_put_noidle(sdev->dev);
                dev_err(sdev->dev, "enabling device failed: %d\n", ret);
                goto error;
        }
@@ -242,6 +251,21 @@ static int debugfs_create_trace_filter(struct snd_sof_dev *sdev)
        return 0;
 }
 
+static bool sof_dtrace_set_host_offset(struct sof_dtrace_priv *priv, u32 new_offset)
+{
+       u32 host_offset = READ_ONCE(priv->host_offset);
+
+       if (host_offset != new_offset) {
+               /* This is a bit paranoid and unlikely that it is needed */
+               u32 ret = cmpxchg(&priv->host_offset, host_offset, new_offset);
+
+               if (ret == host_offset)
+                       return true;
+       }
+
+       return false;
+}
+
 static size_t sof_dtrace_avail(struct snd_sof_dev *sdev,
                               loff_t pos, size_t buffer_size)
 {
@@ -274,7 +298,7 @@ static size_t sof_wait_dtrace_avail(struct snd_sof_dev *sdev, loff_t pos,
        if (ret)
                return ret;
 
-       if (priv->dtrace_state != SOF_DTRACE_ENABLED && priv->dtrace_draining) {
+       if (priv->dtrace_draining && !trace_pos_update_expected(priv)) {
                /*
                 * tracing has ended and all traces have been
                 * read by client, return EOF
@@ -328,6 +352,10 @@ static ssize_t dfsentry_dtrace_read(struct file *file, char __user *buffer,
                return -EIO;
        }
 
+       /* no new trace data */
+       if (!avail)
+               return 0;
+
        /* make sure count is <= avail */
        if (count > avail)
                count = avail;
@@ -358,7 +386,7 @@ static int dfsentry_dtrace_release(struct inode *inode, struct file *file)
 
        /* avoid duplicate traces at next open */
        if (priv->dtrace_state != SOF_DTRACE_ENABLED)
-               priv->host_offset = 0;
+               sof_dtrace_set_host_offset(priv, 0);
 
        return 0;
 }
@@ -434,7 +462,7 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
        params.buffer.pages = priv->dma_trace_pages;
        params.stream_tag = 0;
 
-       priv->host_offset = 0;
+       sof_dtrace_set_host_offset(priv, 0);
        priv->dtrace_draining = false;
 
        ret = sof_dtrace_host_init(sdev, &priv->dmatb, &params);
@@ -442,9 +470,10 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
                dev_err(sdev->dev, "Host dtrace init failed: %d\n", ret);
                return ret;
        }
-       dev_dbg(sdev->dev, "%s: stream_tag: %d\n", __func__, params.stream_tag);
+       dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag);
 
        /* send IPC to the DSP */
+       priv->dtrace_state = SOF_DTRACE_INITIALIZING;
        ret = sof_ipc_tx_message(sdev->ipc, &params, sizeof(params), &ipc_reply, sizeof(ipc_reply));
        if (ret < 0) {
                dev_err(sdev->dev, "can't set params for DMA for trace %d\n", ret);
@@ -452,17 +481,18 @@ static int ipc3_dtrace_enable(struct snd_sof_dev *sdev)
        }
 
 start:
+       priv->dtrace_state = SOF_DTRACE_ENABLED;
+
        ret = sof_dtrace_host_trigger(sdev, SNDRV_PCM_TRIGGER_START);
        if (ret < 0) {
                dev_err(sdev->dev, "Host dtrace trigger start failed: %d\n", ret);
                goto trace_release;
        }
 
-       priv->dtrace_state = SOF_DTRACE_ENABLED;
-
        return 0;
 
 trace_release:
+       priv->dtrace_state = SOF_DTRACE_DISABLED;
        sof_dtrace_host_release(sdev);
        return ret;
 }
@@ -514,8 +544,7 @@ static int ipc3_dtrace_init(struct snd_sof_dev *sdev)
                goto table_err;
 
        priv->dma_trace_pages = ret;
-       dev_dbg(sdev->dev, "%s: dma_trace_pages: %d\n", __func__,
-               priv->dma_trace_pages);
+       dev_dbg(sdev->dev, "dma_trace_pages: %d\n", priv->dma_trace_pages);
 
        if (sdev->first_boot) {
                ret = debugfs_create_dtrace(sdev);
@@ -546,11 +575,9 @@ int ipc3_dtrace_posn_update(struct snd_sof_dev *sdev,
        if (!sdev->fw_trace_is_supported)
                return 0;
 
-       if (priv->dtrace_state == SOF_DTRACE_ENABLED &&
-           priv->host_offset != posn->host_offset) {
-               priv->host_offset = posn->host_offset;
+       if (trace_pos_update_expected(priv) &&
+           sof_dtrace_set_host_offset(priv, posn->host_offset))
                wake_up(&priv->trace_sleep);
-       }
 
        if (posn->overflow != 0)
                dev_err(sdev->dev,
index f3c741b4951982516897ba0e94f27abe812a62fb..bf423ca4e97bb4fe62feb401ff760d9880c6a8d5 100644 (file)
@@ -75,13 +75,12 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev,
        elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header);
        elems_counter = elems_size / sizeof(struct sof_config_elem);
 
-       dev_dbg(sdev->dev, "%s can hold up to %d config elements\n",
-               __func__, elems_counter);
+       dev_dbg(sdev->dev, "manifest can hold up to %d config elements\n", elems_counter);
 
        for (i = 0; i < elems_counter; ++i) {
                elem = &config->elems[i];
-               dev_dbg(sdev->dev, "%s get index %d token %d val %d\n",
-                       __func__, i, elem->token, elem->value);
+               dev_dbg(sdev->dev, "get index %d token %d val %d\n",
+                       i, elem->token, elem->value);
                switch (elem->token) {
                case SOF_EXT_MAN_CONFIG_EMPTY:
                        /* unused memory space is zero filled - mapped to EMPTY elements */
@@ -110,7 +109,7 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev,
        return 0;
 }
 
-static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
+static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmware *fw)
 {
        const struct sof_ext_man_header *head;
 
@@ -132,6 +131,8 @@ static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
                return head->full_size;
 
        /* otherwise given fw don't have an extended manifest */
+       dev_dbg(sdev->dev, "Unexpected extended manifest magic number: %#x\n",
+               head->magic);
        return 0;
 }
 
@@ -148,7 +149,7 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
 
        head = (struct sof_ext_man_header *)fw->data;
        remaining = head->full_size - head->header_size;
-       ext_man_size = ipc3_fw_ext_man_size(fw);
+       ext_man_size = ipc3_fw_ext_man_size(sdev, fw);
 
        /* Assert firmware starts with extended manifest */
        if (ext_man_size <= 0)
@@ -323,10 +324,10 @@ static int sof_ipc3_load_fw_to_dsp(struct snd_sof_dev *sdev)
        header = (struct snd_sof_fw_header *)(fw->data + plat_data->fw_offset);
        load_module = sof_ops(sdev)->load_module;
        if (!load_module) {
-               dev_dbg(sdev->dev, "%s: Using generic module loading\n", __func__);
+               dev_dbg(sdev->dev, "Using generic module loading\n");
                load_module = sof_ipc3_parse_module_memcpy;
        } else {
-               dev_dbg(sdev->dev, "%s: Using custom module loading\n", __func__);
+               dev_dbg(sdev->dev, "Using custom module loading\n");
        }
 
        /* parse each module */
index c8774a891d6fae80626fce84ba028dac059fc10c..9c6a84bdeca75301aa6ee56a55d4b35672a57971 100644 (file)
@@ -115,6 +115,9 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
                        pcm.params.no_stream_position = 1;
        }
 
+       if (platform_params->cont_update_posn)
+               pcm.params.cont_update_posn = 1;
+
        dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
 
        /* send hw_params IPC to the DSP */
@@ -344,10 +347,10 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
                        channels->min, channels->max);
                break;
        case SOF_DAI_AMD_DMIC:
-               rate->min = private->dai_config->acpdmic.fsync_rate;
-               rate->max = private->dai_config->acpdmic.fsync_rate;
-               channels->min = private->dai_config->acpdmic.tdm_slots;
-               channels->max = private->dai_config->acpdmic.tdm_slots;
+               rate->min = private->dai_config->acpdmic.pdm_rate;
+               rate->max = private->dai_config->acpdmic.pdm_rate;
+               channels->min = private->dai_config->acpdmic.pdm_ch;
+               channels->max = private->dai_config->acpdmic.pdm_ch;
 
                dev_dbg(component->dev,
                        "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
index 10740c55294dc0ed91167ad825a3f1ae180d6e98..b2cc046b9f606c84c566a423d88fc9d229e2a0ec 100644 (file)
@@ -17,6 +17,9 @@
 /* Full volume for default values */
 #define VOL_ZERO_DB    BIT(VOLUME_FWL)
 
+/* size of tplg ABI in bytes */
+#define SOF_IPC3_TPLG_ABI_SIZE 3
+
 struct sof_widget_data {
        int ctrl_type;
        int ipc_cmd;
@@ -263,6 +266,16 @@ static const struct sof_topology_token afe_tokens[] = {
                offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
 };
 
+/* ACPDMIC */
+static const struct sof_topology_token acpdmic_tokens[] = {
+       {SOF_TKN_AMD_ACPDMIC_RATE,
+               SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)},
+       {SOF_TKN_AMD_ACPDMIC_CH,
+               SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
+};
+
 /* Core tokens */
 static const struct sof_topology_token core_tokens[] = {
        {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -297,6 +310,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
        [SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
        [SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
        [SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
+       [SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
 };
 
 /**
@@ -1117,20 +1131,22 @@ static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_so
        struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
        struct sof_dai_private_data *private = dai->private;
        u32 size = sizeof(*config);
+       int ret;
 
        /* handle master/slave and inverted clocks */
        sof_dai_set_format(hw_config, config);
 
-       /* init IPC */
-       memset(&config->acpdmic, 0, sizeof(config->acpdmic));
        config->hdr.size = size;
 
-       config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
-       config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+       /* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
+       ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples,
+                                   slink->num_tuples, size, slink->num_hw_configs);
+       if (ret < 0)
+               return ret;
 
        dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
-                config->dai_index, config->acpdmic.tdm_slots,
-                config->acpdmic.fsync_rate);
+                config->dai_index, config->acpdmic.pdm_ch,
+                config->acpdmic.pdm_rate);
 
        dai->number_configs = 1;
        dai->current_config = 0;
@@ -1436,8 +1452,8 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
        if (ret < 0)
                goto free;
 
-       dev_dbg(scomp->dev, "%s dai %s: type %d index %d\n",
-               __func__, swidget->widget->name, comp_dai->type, comp_dai->dai_index);
+       dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
+               swidget->widget->name, comp_dai->type, comp_dai->dai_index);
        sof_dbg_comp_config(scomp, &comp_dai->config);
 
        /* now update DAI config */
@@ -1628,6 +1644,7 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
        return 0;
 err:
        kfree(scontrol->ipc_control_data);
+       scontrol->ipc_control_data = NULL;
        return ret;
 }
 
@@ -2302,6 +2319,45 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
        return -EINVAL;
 }
 
+static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
+                                  struct snd_soc_tplg_manifest *man)
+{
+       u32 size = le32_to_cpu(man->priv.size);
+       u32 abi_version;
+
+       /* backward compatible with tplg without ABI info */
+       if (!size) {
+               dev_dbg(scomp->dev, "No topology ABI info\n");
+               return 0;
+       }
+
+       if (size != SOF_IPC3_TPLG_ABI_SIZE) {
+               dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+                       __func__, size);
+               return -EINVAL;
+       }
+
+       dev_info(scomp->dev,
+                "Topology: ABI %d:%d:%d Kernel ABI %hhu:%hhu:%hhu\n",
+                man->priv.data[0], man->priv.data[1], man->priv.data[2],
+                SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+       abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
+
+       if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
+               dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
+               return -EINVAL;
+       }
+
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
+           SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
+               dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /* token list for each topology object */
 static enum sof_tokens host_token_list[] = {
        SOF_CORE_TOKENS,
@@ -2412,4 +2468,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
        .dai_get_clk = sof_ipc3_dai_get_clk,
        .set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
        .tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
+       .parse_manifest = sof_ipc3_parse_manifest,
 };
index dff5feaad3703605926280884909e9fbcda9b883..82fa320253beffc49e3497007daa117e6b7cd246 100644 (file)
@@ -147,6 +147,8 @@ static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
                case SOF_IPC_TRACE_DMA_PARAMS:
                        str2 = "DMA_PARAMS"; break;
                case SOF_IPC_TRACE_DMA_POSITION:
+                       if (!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS))
+                               return;
                        str2 = "DMA_POSITION"; break;
                case SOF_IPC_TRACE_DMA_PARAMS_EXT:
                        str2 = "DMA_PARAMS_EXT"; break;
@@ -290,7 +292,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
                dev_err(sdev->dev,
                        "ipc tx timed out for %#x (msg/reply size: %d/%zu)\n",
                        hdr->cmd, hdr->size, msg->reply_size);
-               snd_sof_handle_fw_exception(ipc->sdev);
+               snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout");
                ret = -ETIMEDOUT;
        } else {
                ret = msg->reply_error;
@@ -299,7 +301,8 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
                                "ipc tx error for %#x (msg/reply size: %d/%zu): %d\n",
                                hdr->cmd, hdr->size, msg->reply_size, ret);
                } else {
-                       ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
+                       if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
+                               ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
                        if (msg->reply_size)
                                /* copy the data returned from DSP */
                                memcpy(reply_data, msg->reply_data,
@@ -755,13 +758,10 @@ int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev)
                return -EINVAL;
        }
 
-       if (SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
-               if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
-                       dev_warn(sdev->dev, "FW ABI is more recent than kernel\n");
-               } else {
-                       dev_err(sdev->dev, "FW ABI is more recent than kernel\n");
-                       return -EINVAL;
-               }
+       if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
+           SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
+               dev_err(sdev->dev, "FW ABI is more recent than kernel\n");
+               return -EINVAL;
        }
 
        if (ready->flags & SOF_IPC_INFO_BUILD) {
@@ -1037,6 +1037,23 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
        ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd);
 }
 
+static int sof_ipc3_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
+{
+       struct sof_ipc_pm_core_config core_cfg = {
+               .hdr.size = sizeof(core_cfg),
+               .hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
+       };
+       struct sof_ipc_reply reply;
+
+       if (on)
+               core_cfg.enable_mask = sdev->enabled_cores_mask | BIT(core_idx);
+       else
+               core_cfg.enable_mask = sdev->enabled_cores_mask & ~BIT(core_idx);
+
+       return sof_ipc3_tx_msg(sdev, &core_cfg, sizeof(core_cfg),
+                              &reply, sizeof(reply), false);
+}
+
 static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
 {
        struct sof_ipc_pm_ctx pm_ctx = {
@@ -1063,6 +1080,7 @@ static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
 static const struct sof_ipc_pm_ops ipc3_pm_ops = {
        .ctx_save = sof_ipc3_ctx_save,
        .ctx_restore = sof_ipc3_ctx_restore,
+       .set_core_state = sof_ipc3_set_core_state,
 };
 
 const struct sof_ipc_ops ipc3_ops = {
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
new file mode 100644 (file)
index 0000000..0d5a578
--- /dev/null
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+//
+
+#include "sof-priv.h"
+#include "sof-audio.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+
+static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
+{
+       struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+       struct snd_soc_component *scomp = scontrol->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       const struct sof_ipc_ops *iops = sdev->ipc->ops;
+       struct sof_ipc4_msg *msg = &cdata->msg;
+       struct snd_sof_widget *swidget;
+       bool widget_found = false;
+
+       /* find widget associated with the control */
+       list_for_each_entry(swidget, &sdev->widget_list, list) {
+               if (swidget->comp_id == scontrol->comp_id) {
+                       widget_found = true;
+                       break;
+               }
+       }
+
+       if (!widget_found) {
+               dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+               return -ENOENT;
+       }
+
+       /*
+        * Volatile controls should always be part of static pipelines and the widget use_count
+        * would always be > 0 in this case. For the others, just return the cached value if the
+        * widget is not set up.
+        */
+       if (!swidget->use_count)
+               return 0;
+
+       msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
+       msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
+
+       return iops->set_get_data(sdev, msg, msg->data_size, set);
+}
+
+static int
+sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+                        struct snd_sof_control *scontrol)
+{
+       struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+       struct sof_ipc4_gain *gain = swidget->private;
+       struct sof_ipc4_msg *msg = &cdata->msg;
+       struct sof_ipc4_gain_data data;
+       bool all_channels_equal = true;
+       u32 value;
+       int ret, i;
+
+       /* check if all channel values are equal */
+       value = cdata->chanv[0].value;
+       for (i = 1; i < scontrol->num_channels; i++) {
+               if (cdata->chanv[i].value != value) {
+                       all_channels_equal = false;
+                       break;
+               }
+       }
+
+       /*
+        * notify DSP with a single IPC message if all channel values are equal. Otherwise send
+        * a separate IPC for each channel.
+        */
+       for (i = 0; i < scontrol->num_channels; i++) {
+               if (all_channels_equal) {
+                       data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+                       data.init_val = cdata->chanv[0].value;
+               } else {
+                       data.channels = cdata->chanv[i].channel;
+                       data.init_val = cdata->chanv[i].value;
+               }
+
+               /* set curve type and duration from topology */
+               data.curve_duration = gain->data.curve_duration;
+               data.curve_type = gain->data.curve_type;
+
+               msg->data_ptr = &data;
+               msg->data_size = sizeof(data);
+
+               ret = sof_ipc4_set_get_kcontrol_data(scontrol, true);
+               msg->data_ptr = NULL;
+               msg->data_size = 0;
+               if (ret < 0) {
+                       dev_err(sdev->dev, "Failed to set volume update for %s\n",
+                               scontrol->name);
+                       return ret;
+               }
+
+               if (all_channels_equal)
+                       break;
+       }
+
+       return 0;
+}
+
+static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+       struct snd_soc_component *scomp = scontrol->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       unsigned int channels = scontrol->num_channels;
+       struct snd_sof_widget *swidget;
+       bool widget_found = false;
+       bool change = false;
+       unsigned int i;
+       int ret;
+
+       /* update each channel */
+       for (i = 0; i < channels; i++) {
+               u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
+                                        scontrol->volume_table, scontrol->max + 1);
+
+               change = change || (value != cdata->chanv[i].value);
+               cdata->chanv[i].channel = i;
+               cdata->chanv[i].value = value;
+       }
+
+       if (!pm_runtime_active(scomp->dev))
+               return change;
+
+       /* find widget associated with the control */
+       list_for_each_entry(swidget, &sdev->widget_list, list) {
+               if (swidget->comp_id == scontrol->comp_id) {
+                       widget_found = true;
+                       break;
+               }
+       }
+
+       if (!widget_found) {
+               dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+               return false;
+       }
+
+       ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
+       if (ret < 0)
+               return false;
+
+       return change;
+}
+
+static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+       unsigned int channels = scontrol->num_channels;
+       unsigned int i;
+
+       for (i = 0; i < channels; i++)
+               ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
+                                                               scontrol->volume_table,
+                                                               scontrol->max + 1);
+
+       return 0;
+}
+
+/* set up all controls for the widget */
+static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+       struct snd_sof_control *scontrol;
+       int ret;
+
+       list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
+               if (scontrol->comp_id == swidget->comp_id) {
+                       ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
+                       if (ret < 0) {
+                               dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n",
+                                       __func__, scontrol->comp_id, swidget->widget->name);
+                               return ret;
+                       }
+               }
+
+       return 0;
+}
+
+static int
+sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
+{
+       int i;
+
+       /* init the volume table */
+       scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
+       if (!scontrol->volume_table)
+               return -ENOMEM;
+
+       /* populate the volume table */
+       for (i = 0; i < size ; i++) {
+               u32 val = vol_compute_gain(i, tlv);
+               u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
+
+               scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
+                                               SOF_IPC4_VOL_ZERO_DB : q31val;
+       }
+
+       return 0;
+}
+
+const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
+       .volume_put = sof_ipc4_volume_put,
+       .volume_get = sof_ipc4_volume_get,
+       .widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
+       .set_up_volume_table = sof_ipc4_set_up_volume_table,
+};
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
new file mode 100644 (file)
index 0000000..7328723
--- /dev/null
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+
+#include <sound/pcm_params.h>
+#include <sound/sof/ipc4/header.h>
+#include "sof-audio.h"
+#include "sof-priv.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+{
+       struct sof_ipc4_msg msg = {{ 0 }};
+       u32 primary;
+
+       dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
+
+       primary = state;
+       primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
+       primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
+       primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+       msg.primary = primary;
+
+       return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+}
+EXPORT_SYMBOL(sof_ipc4_set_pipeline_state);
+
+static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
+                                     struct snd_pcm_substream *substream, int state)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_sof_widget *pipeline_widget;
+       struct snd_soc_dapm_widget_list *list;
+       struct snd_soc_dapm_widget *widget;
+       struct sof_ipc4_pipeline *pipeline;
+       struct snd_sof_widget *swidget;
+       struct snd_sof_pcm *spcm;
+       int ret = 0;
+       int num_widgets;
+
+       spcm = snd_sof_find_spcm_dai(component, rtd);
+       if (!spcm)
+               return -EINVAL;
+
+       list = spcm->stream[substream->stream].list;
+
+       for_each_dapm_widgets(list, num_widgets, widget) {
+               swidget = widget->dobj.private;
+
+               if (!swidget)
+                       continue;
+
+               /*
+                * set pipeline state for both FE and BE pipelines for RUNNING state.
+                * For PAUSE/RESET, set the pipeline state only for the FE pipeline.
+                */
+               switch (state) {
+               case SOF_IPC4_PIPE_PAUSED:
+               case SOF_IPC4_PIPE_RESET:
+                       if (!WIDGET_IS_AIF(swidget->id))
+                               continue;
+                       break;
+               default:
+                       break;
+               }
+
+               /* find pipeline widget for the pipeline that this widget belongs to */
+               pipeline_widget = swidget->pipe_widget;
+               pipeline = (struct sof_ipc4_pipeline *)pipeline_widget->private;
+
+               if (pipeline->state == state)
+                       continue;
+
+               /* first set the pipeline to PAUSED state */
+               if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
+                       ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+                                                         SOF_IPC4_PIPE_PAUSED);
+                       if (ret < 0) {
+                               dev_err(sdev->dev, "failed to pause pipeline %d\n",
+                                       swidget->pipeline_id);
+                               return ret;
+                       }
+               }
+
+               pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+               if (pipeline->state == state)
+                       continue;
+
+               /* then set the final state */
+               ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, state);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "failed to set state %d for pipeline %d\n",
+                               state, swidget->pipeline_id);
+                       break;
+               }
+
+               pipeline->state = state;
+       }
+
+       return ret;
+}
+
+static int sof_ipc4_pcm_trigger(struct snd_soc_component *component,
+                               struct snd_pcm_substream *substream, int cmd)
+{
+       int state;
+
+       /* determine the pipeline state */
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               state = SOF_IPC4_PIPE_PAUSED;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_START:
+               state = SOF_IPC4_PIPE_RUNNING;
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               state = SOF_IPC4_PIPE_PAUSED;
+               break;
+       default:
+               dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd);
+               return -EINVAL;
+       }
+
+       /* set the pipeline state */
+       return sof_ipc4_trigger_pipelines(component, substream, state);
+}
+
+static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
+                               struct snd_pcm_substream *substream)
+{
+       return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET);
+}
+
+static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
+                                                struct snd_pcm_hw_params *params)
+{
+       struct snd_sof_dai_link *slink;
+       struct snd_sof_dai *dai;
+       bool dai_link_found = false;
+       int i;
+
+       list_for_each_entry(slink, &sdev->dai_link_list, list) {
+               if (!strcmp(slink->link->name, link_name)) {
+                       dai_link_found = true;
+                       break;
+               }
+       }
+
+       if (!dai_link_found)
+               return;
+
+       for (i = 0; i < slink->num_hw_configs; i++) {
+               struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i];
+
+               if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) {
+                       /* set current config for all DAI's with matching name */
+                       list_for_each_entry(dai, &sdev->dai_list, list)
+                               if (!strcmp(slink->link->name, dai->name))
+                                       dai->current_config = le32_to_cpu(hw_config->id);
+                       break;
+               }
+       }
+}
+
+static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+                                      struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
+       struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
+       struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+       struct sof_ipc4_copier *ipc4_copier;
+       struct snd_soc_dpcm *dpcm;
+
+       if (!dai) {
+               dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
+                       rtd->dai_link->name);
+               return -EINVAL;
+       }
+
+       ipc4_copier = dai->private;
+       if (!ipc4_copier) {
+               dev_err(component->dev, "%s: No private data found for DAI %s\n",
+                       __func__, rtd->dai_link->name);
+               return -EINVAL;
+       }
+
+       /* always set BE format to 32-bits for both playback and capture */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+
+       rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency;
+       rate->max = rate->min;
+
+       /*
+        * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required
+        * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI
+        * pipeline gets triggered and the pipeline widgets are freed.
+        */
+       for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
+               struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+               fe->dai_link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
+       }
+
+       switch (ipc4_copier->dai_type) {
+       case SOF_DAI_INTEL_SSP:
+               ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
+       .trigger = sof_ipc4_pcm_trigger,
+       .hw_free = sof_ipc4_pcm_hw_free,
+       .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
+};
index 2b71d5675933d749a6535a6e3aab792836f205f3..9492fe1796c2f1f13613ea9b8bdc6fe279cc671a 100644 (file)
  * @manifest_fw_hdr_offset: FW header offset in the manifest
  * @num_fw_modules : Number of modules in base FW
  * @fw_modules: Array of base FW modules
+ * @nhlt: NHLT table either from the BIOS or the topology manifest
  */
 struct sof_ipc4_fw_data {
        u32 manifest_fw_hdr_offset;
        int num_fw_modules;
        void *fw_modules;
+       void *nhlt;
 };
 
 /**
@@ -40,5 +42,10 @@ struct sof_ipc4_fw_module {
 };
 
 extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
+extern const struct sof_ipc_tplg_ops ipc4_tplg_ops;
+extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops;
+extern const struct sof_ipc_pcm_ops ipc4_pcm_ops;
+
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
 
 #endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
new file mode 100644 (file)
index 0000000..af072b4
--- /dev/null
@@ -0,0 +1,1921 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+//
+#include <uapi/sound/sof/tokens.h>
+#include <sound/pcm_params.h>
+#include <sound/sof/ext_manifest4.h>
+#include <sound/intel-nhlt.h>
+#include "sof-priv.h"
+#include "sof-audio.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+#include "ops.h"
+
+#define SOF_IPC4_GAIN_PARAM_ID  0
+#define SOF_IPC4_TPLG_ABI_SIZE 6
+
+static DEFINE_IDA(alh_group_ida);
+
+static const struct sof_topology_token ipc4_sched_tokens[] = {
+       {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_pipeline, lp_mode)}
+};
+
+static const struct sof_topology_token pipeline_tokens[] = {
+       {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
+               offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
+};
+
+static const struct sof_topology_token ipc4_comp_tokens[] = {
+       {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_base_module_cfg, cpc)},
+       {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
+};
+
+static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = {
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_base_module_cfg, ibs)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_base_module_cfg, obs)},
+};
+
+static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, bit_depth)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, ch_map)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, ch_cfg)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+               get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
+};
+
+static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, bit_depth)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, ch_map)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, ch_cfg)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+               get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
+       {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
+};
+
+static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = {
+       {SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
+};
+
+static const struct sof_topology_token ipc4_copier_tokens[] = {
+       {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
+};
+
+static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
+       {SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               0},
+};
+
+static const struct sof_topology_token dai_tokens[] = {
+       {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
+               offsetof(struct sof_ipc4_copier, dai_type)},
+       {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_copier, dai_index)},
+};
+
+/* Component extended tokens */
+static const struct sof_topology_token comp_ext_tokens[] = {
+       {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
+               offsetof(struct snd_sof_widget, uuid)},
+};
+
+static const struct sof_topology_token gain_tokens[] = {
+       {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+               get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
+       {SOF_TKN_GAIN_RAMP_DURATION,
+               SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_gain_data, curve_duration)},
+       {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+               get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
+};
+
+/* SRC */
+static const struct sof_topology_token src_tokens[] = {
+       {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc4_src, sink_rate)},
+};
+
+static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
+       [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
+       [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
+       [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
+               ARRAY_SIZE(ipc4_sched_tokens)},
+       [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
+               ARRAY_SIZE(comp_ext_tokens)},
+       [SOF_COMP_TOKENS] = {"IPC4 Component tokens",
+               ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
+       [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
+               ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
+       [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
+               ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
+       [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens",
+               ipc4_audio_format_buffer_size_tokens,
+               ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)},
+       [SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens",
+               ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)},
+       [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
+               ARRAY_SIZE(ipc4_copier_tokens)},
+       [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
+               ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
+       [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
+       [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
+};
+
+static void sof_ipc4_dbg_audio_format(struct device *dev,
+                                     struct sof_ipc4_audio_format *format,
+                                     size_t object_size, int num_format)
+{
+       struct sof_ipc4_audio_format *fmt;
+       void *ptr = format;
+       int i;
+
+       for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) {
+               fmt = ptr;
+               dev_dbg(dev,
+                       " #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
+                       i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
+                       fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg);
+       }
+}
+
+/**
+ * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
+ * @scomp: pointer to pointer to SOC component
+ * @swidget: pointer to struct snd_sof_widget containing tuples
+ * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
+ * @has_out_format: true if available_fmt contains output format
+ *
+ * Return: 0 if successful
+ */
+static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
+                                 struct snd_sof_widget *swidget,
+                                 struct sof_ipc4_available_audio_format *available_fmt,
+                                 bool has_out_format)
+{
+       struct sof_ipc4_base_module_cfg *base_config;
+       struct sof_ipc4_audio_format *out_format;
+       int audio_fmt_num = 0;
+       int ret, i;
+
+       ret = sof_update_ipc_object(scomp, &audio_fmt_num,
+                                   SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(audio_fmt_num), 1);
+       if (ret || audio_fmt_num <= 0) {
+               dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num);
+               return -EINVAL;
+       }
+       available_fmt->audio_fmt_num = audio_fmt_num;
+
+       dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num);
+
+       base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL);
+       if (!base_config)
+               return -ENOMEM;
+
+       /* set cpc and is_pages for all base_cfg */
+       for (i = 0; i < available_fmt->audio_fmt_num; i++) {
+               ret = sof_update_ipc_object(scomp, &base_config[i],
+                                           SOF_COMP_TOKENS, swidget->tuples,
+                                           swidget->num_tuples, sizeof(*base_config), 1);
+               if (ret) {
+                       dev_err(scomp->dev, "parse comp tokens failed %d\n", ret);
+                       goto err_in;
+               }
+       }
+
+       /* copy the ibs/obs for each base_cfg */
+       ret = sof_update_ipc_object(scomp, base_config,
+                                   SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(*base_config),
+                                   available_fmt->audio_fmt_num);
+       if (ret) {
+               dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret);
+               goto err_in;
+       }
+
+       for (i = 0; i < available_fmt->audio_fmt_num; i++)
+               dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i,
+                       base_config[i].ibs, base_config[i].obs,
+                       base_config[i].cpc, base_config[i].is_pages);
+
+       ret = sof_update_ipc_object(scomp, &base_config->audio_fmt,
+                                   SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(*base_config),
+                                   available_fmt->audio_fmt_num);
+       if (ret) {
+               dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret);
+               goto err_in;
+       }
+
+       dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name);
+       sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt,
+                                 sizeof(*base_config),
+                                 available_fmt->audio_fmt_num);
+
+       available_fmt->base_config = base_config;
+
+       if (!has_out_format)
+               return 0;
+
+       out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL);
+       if (!out_format) {
+               ret = -ENOMEM;
+               goto err_in;
+       }
+
+       ret = sof_update_ipc_object(scomp, out_format,
+                                   SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(*out_format),
+                                   available_fmt->audio_fmt_num);
+
+       if (ret) {
+               dev_err(scomp->dev, "parse output audio_fmt tokens failed\n");
+               goto err_out;
+       }
+
+       available_fmt->out_audio_fmt = out_format;
+       dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name);
+       sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format),
+                                 available_fmt->audio_fmt_num);
+
+       return 0;
+
+err_out:
+       kfree(out_format);
+err_in:
+       kfree(base_config);
+
+       return ret;
+}
+
+/* release the memory allocated in sof_ipc4_get_audio_fmt */
+static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt)
+
+{
+       kfree(available_fmt->base_config);
+       available_fmt->base_config = NULL;
+       kfree(available_fmt->out_audio_fmt);
+       available_fmt->out_audio_fmt = NULL;
+}
+
+static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget)
+{
+       kfree(swidget->private);
+}
+
+static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules;
+       int i;
+
+       if (!fw_modules) {
+               dev_err(sdev->dev, "no fw_module information\n");
+               return -EINVAL;
+       }
+
+       /* set module info */
+       for (i = 0; i < ipc4_data->num_fw_modules; i++) {
+               if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) {
+                       swidget->module_info = &fw_modules[i];
+                       return 0;
+               }
+       }
+
+       dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
+               swidget->widget->name, &swidget->uuid);
+       return -EINVAL;
+}
+
+static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
+{
+       struct sof_ipc4_fw_module *fw_module;
+       uint32_t type;
+       int ret;
+
+       ret = sof_ipc4_widget_set_module_info(swidget);
+       if (ret)
+               return ret;
+
+       fw_module = swidget->module_info;
+
+       msg->primary = fw_module->man4_module_entry.id;
+       msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
+       msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+       msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id);
+       msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
+
+       type = fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP ? 1 : 0;
+       msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
+
+       return 0;
+}
+
+static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_available_audio_format *available_fmt;
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct sof_ipc4_copier *ipc4_copier;
+       int node_type = 0;
+       int ret, i;
+
+       ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
+       if (!ipc4_copier)
+               return -ENOMEM;
+
+       swidget->private = ipc4_copier;
+       available_fmt = &ipc4_copier->available_fmt;
+
+       dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+       ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
+       if (ret)
+               goto free_copier;
+
+       available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
+                                                GFP_KERNEL);
+       if (!available_fmt->dma_buffer_size) {
+               ret = -ENOMEM;
+               goto free_available_fmt;
+       }
+
+       ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
+                                   SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(u32),
+                                   available_fmt->audio_fmt_num);
+       if (ret) {
+               dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
+                       swidget->widget->name);
+               goto err;
+       }
+
+       dev_dbg(scomp->dev, "dma buffer size:\n");
+       for (i = 0; i < available_fmt->audio_fmt_num; i++)
+               dev_dbg(scomp->dev, "%d: %u\n", i,
+                       available_fmt->dma_buffer_size[i]);
+
+       ret = sof_update_ipc_object(scomp, &node_type,
+                                   SOF_COPIER_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(node_type), 1);
+
+       if (ret) {
+               dev_err(scomp->dev, "parse host copier node type token failed %d\n",
+                       ret);
+               goto err;
+       }
+       dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
+
+       ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
+       ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+       if (!ipc4_copier->gtw_attr) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+       ipc4_copier->data.gtw_cfg.config_length =
+               sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+
+       /* set up module info and message header */
+       ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
+       if (ret)
+               goto free_gtw_attr;
+
+       return 0;
+
+free_gtw_attr:
+       kfree(ipc4_copier->gtw_attr);
+err:
+       kfree(available_fmt->dma_buffer_size);
+free_available_fmt:
+       sof_ipc4_free_audio_fmt(available_fmt);
+free_copier:
+       kfree(ipc4_copier);
+       swidget->private = NULL;
+       return ret;
+}
+
+static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_copier *ipc4_copier = swidget->private;
+       struct sof_ipc4_available_audio_format *available_fmt;
+
+       if (!ipc4_copier)
+               return;
+
+       available_fmt = &ipc4_copier->available_fmt;
+       kfree(available_fmt->dma_buffer_size);
+       kfree(available_fmt->base_config);
+       kfree(available_fmt->out_audio_fmt);
+       kfree(ipc4_copier->gtw_attr);
+       kfree(ipc4_copier);
+       swidget->private = NULL;
+}
+
+static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_available_audio_format *available_fmt;
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dai *dai = swidget->private;
+       struct sof_ipc4_copier *ipc4_copier;
+       int node_type = 0;
+       int ret, i;
+
+       ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
+       if (!ipc4_copier)
+               return -ENOMEM;
+
+       available_fmt = &ipc4_copier->available_fmt;
+
+       dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+       ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
+       if (ret)
+               goto free_copier;
+
+       available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
+                                                GFP_KERNEL);
+       if (!available_fmt->dma_buffer_size) {
+               ret = -ENOMEM;
+               goto free_available_fmt;
+       }
+
+       ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
+                                   SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(u32),
+                                   available_fmt->audio_fmt_num);
+       if (ret) {
+               dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
+                       swidget->widget->name);
+               goto err;
+       }
+
+       for (i = 0; i < available_fmt->audio_fmt_num; i++)
+               dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i,
+                       available_fmt->dma_buffer_size[i]);
+
+       ret = sof_update_ipc_object(scomp, &node_type,
+                                   SOF_COPIER_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(node_type), 1);
+       if (ret) {
+               dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
+               goto err;
+       }
+
+       ret = sof_update_ipc_object(scomp, ipc4_copier,
+                                   SOF_DAI_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(u32), 1);
+       if (ret) {
+               dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
+               goto err;
+       }
+
+       dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
+               node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
+
+       ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
+
+       switch (ipc4_copier->dai_type) {
+       case SOF_DAI_INTEL_ALH:
+       {
+               struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+               struct sof_ipc4_alh_configuration_blob *blob;
+               struct snd_sof_widget *w;
+
+               blob = kzalloc(sizeof(*blob), GFP_KERNEL);
+               if (!blob) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               list_for_each_entry(w, &sdev->widget_list, list) {
+                       if (w->widget->sname &&
+                           strcmp(w->widget->sname, swidget->widget->sname))
+                               continue;
+
+                       blob->alh_cfg.count++;
+               }
+
+               ipc4_copier->copier_config = (uint32_t *)blob;
+               ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
+               break;
+       }
+       case SOF_DAI_INTEL_SSP:
+               /* set SSP DAI index as the node_id */
+               ipc4_copier->data.gtw_cfg.node_id |=
+                       SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
+               break;
+       case SOF_DAI_INTEL_DMIC:
+               /* set DMIC DAI index as the node_id */
+               ipc4_copier->data.gtw_cfg.node_id |=
+                       SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
+               break;
+       default:
+               ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+               if (!ipc4_copier->gtw_attr) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+               ipc4_copier->data.gtw_cfg.config_length =
+                       sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+               break;
+       }
+
+       dai->scomp = scomp;
+       dai->private = ipc4_copier;
+
+       /* set up module info and message header */
+       ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
+       if (ret)
+               goto free_copier_config;
+
+       return 0;
+
+free_copier_config:
+       kfree(ipc4_copier->copier_config);
+err:
+       kfree(available_fmt->dma_buffer_size);
+free_available_fmt:
+       sof_ipc4_free_audio_fmt(available_fmt);
+free_copier:
+       kfree(ipc4_copier);
+       dai->private = NULL;
+       dai->scomp = NULL;
+       return ret;
+}
+
+static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_available_audio_format *available_fmt;
+       struct snd_sof_dai *dai = swidget->private;
+       struct sof_ipc4_copier *ipc4_copier;
+
+       if (!dai)
+               return;
+
+       if (!dai->private) {
+               kfree(dai);
+               swidget->private = NULL;
+               return;
+       }
+
+       ipc4_copier = dai->private;
+       available_fmt = &ipc4_copier->available_fmt;
+
+       kfree(available_fmt->dma_buffer_size);
+       kfree(available_fmt->base_config);
+       kfree(available_fmt->out_audio_fmt);
+       if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
+           ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
+               kfree(ipc4_copier->copier_config);
+       kfree(dai->private);
+       kfree(dai);
+       swidget->private = NULL;
+}
+
+static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct sof_ipc4_pipeline *pipeline;
+       int ret;
+
+       pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
+       if (!pipeline)
+               return -ENOMEM;
+
+       ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(*pipeline), 1);
+       if (ret) {
+               dev_err(scomp->dev, "parsing scheduler tokens failed\n");
+               goto err;
+       }
+
+       /* parse one set of pipeline tokens */
+       ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(*swidget), 1);
+       if (ret) {
+               dev_err(scomp->dev, "parsing pipeline tokens failed\n");
+               goto err;
+       }
+
+       /* TODO: Get priority from topology */
+       pipeline->priority = 0;
+
+       dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n",
+               swidget->widget->name, swidget->pipeline_id,
+               pipeline->priority, pipeline->lp_mode);
+
+       swidget->private = pipeline;
+
+       pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
+       pipeline->msg.primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+       pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
+       pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+       pipeline->msg.extension = pipeline->lp_mode;
+       pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+
+       return 0;
+err:
+       kfree(pipeline);
+       return ret;
+}
+
+static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_fw_module *fw_module;
+       struct snd_sof_control *scontrol;
+       struct sof_ipc4_gain *gain;
+       int ret;
+
+       gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+       if (!gain)
+               return -ENOMEM;
+
+       swidget->private = gain;
+
+       gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+       gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
+
+       /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
+       ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false);
+       if (ret)
+               goto err;
+
+       ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(gain->data), 1);
+       if (ret) {
+               dev_err(scomp->dev, "Parsing gain tokens failed\n");
+               goto err;
+       }
+
+       dev_dbg(scomp->dev,
+               "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
+               swidget->widget->name, gain->data.curve_type, gain->data.curve_duration,
+               gain->data.init_val, gain->base_config.cpc);
+
+       ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
+       if (ret)
+               goto err;
+
+       fw_module = swidget->module_info;
+
+       /* update module ID for all kcontrols for this widget */
+       list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
+               if (scontrol->comp_id == swidget->comp_id) {
+                       struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+                       struct sof_ipc4_msg *msg = &cdata->msg;
+
+                       msg->primary |= fw_module->man4_module_entry.id;
+               }
+
+       return 0;
+err:
+       sof_ipc4_free_audio_fmt(&gain->available_fmt);
+       kfree(gain);
+       swidget->private = NULL;
+       return ret;
+}
+
+static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_gain *gain = swidget->private;
+
+       if (!gain)
+               return;
+
+       sof_ipc4_free_audio_fmt(&gain->available_fmt);
+       kfree(swidget->private);
+       swidget->private = NULL;
+}
+
+static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct sof_ipc4_mixer *mixer;
+       int ret;
+
+       dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+       mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+       if (!mixer)
+               return -ENOMEM;
+
+       swidget->private = mixer;
+
+       /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
+       ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
+       if (ret)
+               goto err;
+
+       ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       sof_ipc4_free_audio_fmt(&mixer->available_fmt);
+       kfree(mixer);
+       swidget->private = NULL;
+       return ret;
+}
+
+static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct sof_ipc4_src *src;
+       int ret;
+
+       dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+       src = kzalloc(sizeof(*src), GFP_KERNEL);
+       if (!src)
+               return -ENOMEM;
+
+       swidget->private = src;
+
+       /* The out_audio_fmt in topology is ignored as it is not required by SRC */
+       ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false);
+       if (ret)
+               goto err;
+
+       ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
+                                   swidget->num_tuples, sizeof(src), 1);
+       if (ret) {
+               dev_err(scomp->dev, "Parsing SRC tokens failed\n");
+               goto err;
+       }
+
+       dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
+
+       ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       sof_ipc4_free_audio_fmt(&src->available_fmt);
+       kfree(src);
+       swidget->private = NULL;
+       return ret;
+}
+
+static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_src *src = swidget->private;
+
+       if (!src)
+               return;
+
+       sof_ipc4_free_audio_fmt(&src->available_fmt);
+       kfree(swidget->private);
+       swidget->private = NULL;
+}
+
+static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_mixer *mixer = swidget->private;
+
+       if (!mixer)
+               return;
+
+       sof_ipc4_free_audio_fmt(&mixer->available_fmt);
+       kfree(swidget->private);
+       swidget->private = NULL;
+}
+
+static void
+sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+                                  struct sof_ipc4_base_module_cfg *base_config)
+{
+       struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+       struct snd_sof_widget *pipe_widget;
+       struct sof_ipc4_pipeline *pipeline;
+       int task_mem, queue_mem;
+       int ibs, bss, total;
+
+       ibs = base_config->ibs;
+       bss = base_config->is_pages;
+
+       task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
+       task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
+
+       if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
+               task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
+               task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
+               task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
+       } else {
+               task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
+               task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
+       }
+
+       ibs = SOF_IPC4_FW_ROUNDUP(ibs);
+       queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
+
+       total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
+
+       pipe_widget = swidget->pipe_widget;
+       pipeline = pipe_widget->private;
+       pipeline->mem_usage += total;
+}
+
+static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
+                                             struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+       int max_instances = fw_module->man4_module_entry.instance_max_count;
+
+       swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
+       if (swidget->instance_id < 0) {
+               dev_err(sdev->dev, "failed to assign instance id for widget %s",
+                       swidget->widget->name);
+               return swidget->instance_id;
+       }
+
+       return 0;
+}
+
+static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
+                                  struct snd_sof_widget *swidget,
+                                  struct sof_ipc4_base_module_cfg *base_config,
+                                  struct sof_ipc4_audio_format *out_format,
+                                  struct snd_pcm_hw_params *params,
+                                  struct sof_ipc4_available_audio_format *available_fmt,
+                                  size_t object_offset)
+{
+       void *ptr = available_fmt->ref_audio_fmt;
+       u32 valid_bits;
+       u32 channels;
+       u32 rate;
+       int sample_valid_bits;
+       int i;
+
+       if (!ptr) {
+               dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               sample_valid_bits = 16;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               sample_valid_bits = 24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               sample_valid_bits = 32;
+               break;
+       default:
+               dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
+               return -EINVAL;
+       }
+
+       if (!available_fmt->audio_fmt_num) {
+               dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
+               return -EINVAL;
+       }
+
+       /*
+        * Search supported audio formats to match rate, channels ,and
+        * sample_valid_bytes from runtime params
+        */
+       for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
+               struct sof_ipc4_audio_format *fmt = ptr;
+
+               rate = fmt->sampling_frequency;
+               channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+               valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+               if (params_rate(params) == rate && params_channels(params) == channels &&
+                   sample_valid_bits == valid_bits) {
+                       dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n",
+                               rate, valid_bits, channels, i);
+
+                       /* copy ibs/obs and input format */
+                       memcpy(base_config, &available_fmt->base_config[i],
+                              sizeof(struct sof_ipc4_base_module_cfg));
+
+                       /* copy output format */
+                       if (out_format)
+                               memcpy(out_format, &available_fmt->out_audio_fmt[i],
+                                      sizeof(struct sof_ipc4_audio_format));
+                       break;
+               }
+       }
+
+       if (i == available_fmt->audio_fmt_num) {
+               dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
+                       __func__, params_rate(params), sample_valid_bits, params_channels(params));
+               return -EINVAL;
+       }
+
+       dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
+       sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
+                                 sizeof(*base_config), 1);
+       if (out_format) {
+               dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
+               sof_ipc4_dbg_audio_format(sdev->dev, out_format,
+                                         sizeof(*out_format), 1);
+       }
+
+       /* Return the index of the matched format */
+       return i;
+}
+
+static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_copier *ipc4_copier = NULL;
+       struct snd_sof_widget *pipe_widget;
+       struct sof_ipc4_pipeline *pipeline;
+
+       /* reset pipeline memory usage */
+       pipe_widget = swidget->pipe_widget;
+       pipeline = pipe_widget->private;
+       pipeline->mem_usage = 0;
+
+       if (WIDGET_IS_AIF(swidget->id)) {
+               ipc4_copier = swidget->private;
+       } else if (WIDGET_IS_DAI(swidget->id)) {
+               struct snd_sof_dai *dai = swidget->private;
+
+               ipc4_copier = dai->private;
+               if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
+                       struct sof_ipc4_alh_configuration_blob *blob;
+                       unsigned int group_id;
+
+                       blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
+                       if (blob->alh_cfg.count > 1) {
+                               group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) -
+                                          ALH_MULTI_GTW_BASE;
+                               ida_free(&alh_group_ida, group_id);
+                       }
+               }
+       }
+
+       if (ipc4_copier) {
+               kfree(ipc4_copier->ipc_config_data);
+               ipc4_copier->ipc_config_data = NULL;
+               ipc4_copier->ipc_config_size = 0;
+       }
+}
+
+#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
+static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+                                       int *sample_rate, int *channel_count, int *bit_depth)
+{
+       struct snd_soc_tplg_hw_config *hw_config;
+       struct snd_sof_dai_link *slink;
+       bool dai_link_found = false;
+       bool hw_cfg_found = false;
+       int i;
+
+       /* get current hw_config from link */
+       list_for_each_entry(slink, &sdev->dai_link_list, list) {
+               if (!strcmp(slink->link->name, dai->name)) {
+                       dai_link_found = true;
+                       break;
+               }
+       }
+
+       if (!dai_link_found) {
+               dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < slink->num_hw_configs; i++) {
+               hw_config = &slink->hw_configs[i];
+               if (dai->current_config == le32_to_cpu(hw_config->id)) {
+                       hw_cfg_found = true;
+                       break;
+               }
+       }
+
+       if (!hw_cfg_found) {
+               dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
+                       dai->name);
+               return -EINVAL;
+       }
+
+       *bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
+       *channel_count = le32_to_cpu(hw_config->tdm_slots);
+       *sample_rate = le32_to_cpu(hw_config->fsync_rate);
+
+       dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n",
+               *sample_rate, *bit_depth, *channel_count);
+
+       return 0;
+}
+
+static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+                                         struct snd_pcm_hw_params *params, u32 dai_index,
+                                         u32 linktype, u8 dir, u32 **dst, u32 *len)
+{
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct nhlt_specific_cfg *cfg;
+       int sample_rate, channel_count;
+       int bit_depth, ret;
+       u32 nhlt_type;
+
+       /* convert to NHLT type */
+       switch (linktype) {
+       case SOF_DAI_INTEL_DMIC:
+               nhlt_type = NHLT_LINK_DMIC;
+               bit_depth = params_width(params);
+               channel_count = params_channels(params);
+               sample_rate = params_rate(params);
+               break;
+       case SOF_DAI_INTEL_SSP:
+               nhlt_type = NHLT_LINK_SSP;
+               ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
+                                                  &bit_depth);
+               if (ret < 0)
+                       return ret;
+               break;
+       default:
+               return 0;
+       }
+
+       dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n",
+               dai_index, nhlt_type, dir);
+
+       /* find NHLT blob with matching params */
+       cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
+                                          bit_depth, bit_depth, channel_count, sample_rate,
+                                          dir, 0);
+
+       if (!cfg) {
+               dev_err(sdev->dev,
+                       "no matching blob for sample rate: %d sample width: %d channels: %d\n",
+                       sample_rate, bit_depth, channel_count);
+               return -EINVAL;
+       }
+
+       /* config length should be in dwords */
+       *len = cfg->size >> 2;
+       *dst = (u32 *)cfg->caps;
+
+       return 0;
+}
+#else
+static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+                                         struct snd_pcm_hw_params *params, u32 dai_index,
+                                         u32 linktype, u8 dir, u32 **dst, u32 *len)
+{
+       return 0;
+}
+#endif
+
+static int
+sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
+                              struct snd_pcm_hw_params *fe_params,
+                              struct snd_sof_platform_stream_params *platform_params,
+                              struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+       struct sof_ipc4_available_audio_format *available_fmt;
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_copier_data *copier_data;
+       struct snd_pcm_hw_params *ref_params;
+       struct sof_ipc4_copier *ipc4_copier;
+       struct snd_sof_dai *dai;
+       struct snd_mask *fmt;
+       int out_sample_valid_bits;
+       size_t ref_audio_fmt_size;
+       void **ipc_config_data;
+       int *ipc_config_size;
+       u32 **data;
+       int ipc_size, ret;
+
+       dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
+
+       switch (swidget->id) {
+       case snd_soc_dapm_aif_in:
+       case snd_soc_dapm_aif_out:
+       {
+               struct sof_ipc4_gtw_attributes *gtw_attr;
+               struct snd_sof_widget *pipe_widget;
+               struct sof_ipc4_pipeline *pipeline;
+
+               pipe_widget = swidget->pipe_widget;
+               pipeline = pipe_widget->private;
+               ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
+               gtw_attr = ipc4_copier->gtw_attr;
+               copier_data = &ipc4_copier->data;
+               available_fmt = &ipc4_copier->available_fmt;
+
+               /*
+                * base_config->audio_fmt and out_audio_fmt represent the input and output audio
+                * formats. Use the input format as the reference to match pcm params for playback
+                * and the output format as reference for capture.
+                */
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
+                       ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
+               } else {
+                       available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
+                       ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
+               }
+               copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+               copier_data->gtw_cfg.node_id |=
+                       SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
+
+               /* set gateway attributes */
+               gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
+               ref_params = fe_params;
+               break;
+       }
+       case snd_soc_dapm_dai_in:
+       case snd_soc_dapm_dai_out:
+       {
+               dai = swidget->private;
+
+               ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+               copier_data = &ipc4_copier->data;
+               available_fmt = &ipc4_copier->available_fmt;
+               if (dir == SNDRV_PCM_STREAM_CAPTURE) {
+                       available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
+                       ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
+
+                       /*
+                        * modify the input params for the dai copier as it only supports
+                        * 32-bit always
+                        */
+                       fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
+                       snd_mask_none(fmt);
+                       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+               } else {
+                       available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
+                       ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
+               }
+
+               ref_params = pipeline_params;
+
+               ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
+                                                    ipc4_copier->dai_type, dir,
+                                                    &ipc4_copier->copier_config,
+                                                    &copier_data->gtw_cfg.config_length);
+               if (ret < 0)
+                       return ret;
+
+               break;
+       }
+       default:
+               dev_err(sdev->dev, "unsupported type %d for copier %s",
+                       swidget->id, swidget->widget->name);
+               return -EINVAL;
+       }
+
+       /* set input and output audio formats */
+       ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
+                                     &copier_data->out_format, ref_params,
+                                     available_fmt, ref_audio_fmt_size);
+       if (ret < 0)
+               return ret;
+
+       switch (swidget->id) {
+       case snd_soc_dapm_dai_in:
+       case snd_soc_dapm_dai_out:
+       {
+               /*
+                * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
+                * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
+                */
+               if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
+                       struct sof_ipc4_alh_configuration_blob *blob;
+                       struct sof_ipc4_copier_data *alh_data;
+                       struct sof_ipc4_copier *alh_copier;
+                       struct snd_sof_widget *w;
+                       u32 ch_mask = 0;
+                       u32 ch_map;
+                       int i;
+
+                       blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
+
+                       blob->gw_attr.lp_buffer_alloc = 0;
+
+                       /* Get channel_mask from ch_map */
+                       ch_map = copier_data->base_config.audio_fmt.ch_map;
+                       for (i = 0; ch_map; i++) {
+                               if ((ch_map & 0xf) != 0xf)
+                                       ch_mask |= BIT(i);
+                               ch_map >>= 4;
+                       }
+
+                       /*
+                        * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[]
+                        * for all widgets with the same stream name
+                        */
+                       i = 0;
+                       list_for_each_entry(w, &sdev->widget_list, list) {
+                               if (w->widget->sname &&
+                                   strcmp(w->widget->sname, swidget->widget->sname))
+                                       continue;
+
+                               dai = w->private;
+                               alh_copier = (struct sof_ipc4_copier *)dai->private;
+                               alh_data = &alh_copier->data;
+                               blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id;
+                               blob->alh_cfg.mapping[i].channel_mask = ch_mask;
+                               i++;
+                       }
+                       if (blob->alh_cfg.count > 1) {
+                               int group_id;
+
+                               group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT,
+                                                        GFP_KERNEL);
+
+                               if (group_id < 0)
+                                       return group_id;
+
+                               /* add multi-gateway base */
+                               group_id += ALH_MULTI_GTW_BASE;
+                               copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+                               copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id);
+                       }
+               }
+       }
+       }
+
+       /* modify the input params for the next widget */
+       fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
+       out_sample_valid_bits =
+               SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
+       snd_mask_none(fmt);
+       switch (out_sample_valid_bits) {
+       case 16:
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+               break;
+       case 24:
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+               break;
+       case 32:
+               snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+               break;
+       default:
+               dev_err(sdev->dev, "invalid sample frame format %d\n",
+                       params_format(pipeline_params));
+               return -EINVAL;
+       }
+
+       /* set the gateway dma_buffer_size using the matched ID returned above */
+       copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
+
+       data = &ipc4_copier->copier_config;
+       ipc_config_size = &ipc4_copier->ipc_config_size;
+       ipc_config_data = &ipc4_copier->ipc_config_data;
+
+       /* config_length is DWORD based */
+       ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
+
+       dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
+
+       *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
+       if (!*ipc_config_data)
+               return -ENOMEM;
+
+       *ipc_config_size = ipc_size;
+
+       /* copy IPC data */
+       memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
+       if (copier_data->gtw_cfg.config_length)
+               memcpy(*ipc_config_data + sizeof(*copier_data),
+                      *data, copier_data->gtw_cfg.config_length * 4);
+
+       /* update pipeline memory usage */
+       sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
+
+       return 0;
+}
+
+static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
+                                       struct snd_pcm_hw_params *fe_params,
+                                       struct snd_sof_platform_stream_params *platform_params,
+                                       struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_gain *gain = swidget->private;
+       int ret;
+
+       gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
+
+       /* output format is not required to be sent to the FW for gain */
+       ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
+                                     NULL, pipeline_params, &gain->available_fmt,
+                                     sizeof(gain->base_config));
+       if (ret < 0)
+               return ret;
+
+       /* update pipeline memory usage */
+       sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
+
+       return 0;
+}
+
+static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
+                                        struct snd_pcm_hw_params *fe_params,
+                                        struct snd_sof_platform_stream_params *platform_params,
+                                        struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_mixer *mixer = swidget->private;
+       int ret;
+
+       /* only 32bit is supported by mixer */
+       mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
+
+       /* output format is not required to be sent to the FW for mixer */
+       ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
+                                     NULL, pipeline_params, &mixer->available_fmt,
+                                     sizeof(mixer->base_config));
+       if (ret < 0)
+               return ret;
+
+       /* update pipeline memory usage */
+       sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
+
+       return 0;
+}
+
+static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
+                                      struct snd_pcm_hw_params *fe_params,
+                                      struct snd_sof_platform_stream_params *platform_params,
+                                      struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+       struct snd_soc_component *scomp = swidget->scomp;
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_src *src = swidget->private;
+       struct snd_interval *rate;
+       int ret;
+
+       src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt;
+
+       /* output format is not required to be sent to the FW for SRC */
+       ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config,
+                                     NULL, pipeline_params, &src->available_fmt,
+                                     sizeof(src->base_config));
+       if (ret < 0)
+               return ret;
+
+       /* update pipeline memory usage */
+       sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
+
+       /* update pipeline_params for sink widgets */
+       rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
+       rate->min = src->sink_rate;
+       rate->max = rate->min;
+
+       return 0;
+}
+
+static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+       struct sof_ipc4_control_data *control_data;
+       struct sof_ipc4_msg *msg;
+       int i;
+
+       scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
+
+       /* scontrol->ipc_control_data will be freed in sof_control_unload */
+       scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
+       if (!scontrol->ipc_control_data)
+               return -ENOMEM;
+
+       control_data = scontrol->ipc_control_data;
+       control_data->index = scontrol->index;
+
+       msg = &control_data->msg;
+       msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
+       msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+       msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
+
+       /* set default volume values to 0dB in control */
+       for (i = 0; i < scontrol->num_channels; i++) {
+               control_data->chanv[i].channel = i;
+               control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
+       }
+
+       return 0;
+}
+
+static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+       switch (scontrol->info_type) {
+       case SND_SOC_TPLG_CTL_VOLSW:
+       case SND_SOC_TPLG_CTL_VOLSW_SX:
+       case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
+               return sof_ipc4_control_load_volume(sdev, scontrol);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+       struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+       struct sof_ipc4_pipeline *pipeline;
+       struct sof_ipc4_msg *msg;
+       void *ipc_data = NULL;
+       u32 ipc_size = 0;
+       int ret;
+
+       switch (swidget->id) {
+       case snd_soc_dapm_scheduler:
+               pipeline = swidget->private;
+
+               dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
+                       pipeline->mem_usage);
+
+               msg = &pipeline->msg;
+               msg->primary |= pipeline->mem_usage;
+               break;
+       case snd_soc_dapm_aif_in:
+       case snd_soc_dapm_aif_out:
+       {
+               struct sof_ipc4_copier *ipc4_copier = swidget->private;
+
+               ipc_size = ipc4_copier->ipc_config_size;
+               ipc_data = ipc4_copier->ipc_config_data;
+
+               msg = &ipc4_copier->msg;
+               break;
+       }
+       case snd_soc_dapm_dai_in:
+       case snd_soc_dapm_dai_out:
+       {
+               struct snd_sof_dai *dai = swidget->private;
+               struct sof_ipc4_copier *ipc4_copier = dai->private;
+
+               ipc_size = ipc4_copier->ipc_config_size;
+               ipc_data = ipc4_copier->ipc_config_data;
+
+               msg = &ipc4_copier->msg;
+               break;
+       }
+       case snd_soc_dapm_pga:
+       {
+               struct sof_ipc4_gain *gain = swidget->private;
+
+               ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
+                          sizeof(struct sof_ipc4_gain_data);
+               ipc_data = gain;
+
+               msg = &gain->msg;
+               break;
+       }
+       case snd_soc_dapm_mixer:
+       {
+               struct sof_ipc4_mixer *mixer = swidget->private;
+
+               ipc_size = sizeof(mixer->base_config);
+               ipc_data = &mixer->base_config;
+
+               msg = &mixer->msg;
+               break;
+       }
+       case snd_soc_dapm_src:
+       {
+               struct sof_ipc4_src *src = swidget->private;
+
+               ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
+               ipc_data = src;
+
+               msg = &src->msg;
+               break;
+       }
+       default:
+               dev_err(sdev->dev, "widget type %d not supported", swidget->id);
+               return -EINVAL;
+       }
+
+       if (swidget->id != snd_soc_dapm_scheduler) {
+               ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
+               if (ret < 0) {
+                       dev_err(sdev->dev, "failed to assign instance id for %s\n",
+                               swidget->widget->name);
+                       return ret;
+               }
+               pipeline = pipe_widget->private;
+               msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
+               msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
+
+               msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
+               msg->extension |= ipc_size >> 2;
+       }
+       dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
+               swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
+
+       msg->data_size = ipc_size;
+       msg->data_ptr = ipc_data;
+
+       ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
+
+       return ret;
+}
+
+static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+       struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+       int ret = 0;
+
+       /* freeing a pipeline frees all the widgets associated with it */
+       if (swidget->id == snd_soc_dapm_scheduler) {
+               struct sof_ipc4_pipeline *pipeline = swidget->private;
+               struct sof_ipc4_msg msg = {{ 0 }};
+               u32 header;
+
+               header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+               header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
+               header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+               header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+               msg.primary = header;
+
+               ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+               if (ret < 0)
+                       dev_err(sdev->dev, "failed to free pipeline widget %s\n",
+                               swidget->widget->name);
+
+               pipeline->mem_usage = 0;
+               pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+       } else {
+               ida_free(&fw_module->m_ida, swidget->instance_id);
+       }
+
+       return ret;
+}
+
+static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
+{
+       struct snd_sof_widget *src_widget = sroute->src_widget;
+       struct snd_sof_widget *sink_widget = sroute->sink_widget;
+       struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
+       struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
+       struct sof_ipc4_msg msg = {{ 0 }};
+       u32 header, extension;
+       int src_queue = 0;
+       int dst_queue = 0;
+       int ret;
+
+       dev_dbg(sdev->dev, "bind %s -> %s\n",
+               src_widget->widget->name, sink_widget->widget->name);
+
+       header = src_fw_module->man4_module_entry.id;
+       header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+       header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
+       header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+       extension = sink_fw_module->man4_module_entry.id;
+       extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
+       extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
+       extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+
+       msg.primary = header;
+       msg.extension = extension;
+
+       ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+       if (ret < 0)
+               dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n",
+                       __func__, src_widget->widget->name, sink_widget->widget->name);
+
+       return ret;
+}
+
+static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
+{
+       struct snd_sof_widget *src_widget = sroute->src_widget;
+       struct snd_sof_widget *sink_widget = sroute->sink_widget;
+       struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
+       struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
+       struct sof_ipc4_msg msg = {{ 0 }};
+       u32 header, extension;
+       int src_queue = 0;
+       int dst_queue = 0;
+       int ret;
+
+       dev_dbg(sdev->dev, "unbind modules %s -> %s\n",
+               src_widget->widget->name, sink_widget->widget->name);
+
+       header = src_fw_module->man4_module_entry.id;
+       header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+       header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
+       header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+       extension = sink_fw_module->man4_module_entry.id;
+       extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
+       extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
+       extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+
+       msg.primary = header;
+       msg.extension = extension;
+
+       ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+       if (ret < 0)
+               dev_err(sdev->dev, "failed to unbind modules %s -> %s\n",
+                       src_widget->widget->name, sink_widget->widget->name);
+
+       return ret;
+}
+
+static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+                              unsigned int flags, struct snd_sof_dai_config_data *data)
+{
+       struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+       struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+       struct snd_sof_dai *dai = swidget->private;
+       struct sof_ipc4_gtw_attributes *gtw_attr;
+       struct sof_ipc4_copier_data *copier_data;
+       struct sof_ipc4_copier *ipc4_copier;
+
+       if (!dai || !dai->private) {
+               dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
+                       swidget->widget->name);
+               return -EINVAL;
+       }
+
+       ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+       copier_data = &ipc4_copier->data;
+
+       if (!data)
+               return 0;
+
+       switch (ipc4_copier->dai_type) {
+       case SOF_DAI_INTEL_HDA:
+               gtw_attr = ipc4_copier->gtw_attr;
+               gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
+               fallthrough;
+       case SOF_DAI_INTEL_ALH:
+               copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+               copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
+               break;
+       case SOF_DAI_INTEL_DMIC:
+       case SOF_DAI_INTEL_SSP:
+               /* nothing to do for SSP/DMIC */
+               break;
+       default:
+               dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
+                       ipc4_copier->dai_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
+                                  struct snd_soc_tplg_manifest *man)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+       struct sof_manifest_tlv *manifest_tlv;
+       struct sof_manifest *manifest;
+       u32 size = le32_to_cpu(man->priv.size);
+       u8 *man_ptr = man->priv.data;
+       u32 len_check;
+       int i;
+
+       if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
+               dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+                       __func__, size);
+               return -EINVAL;
+       }
+
+       manifest = (struct sof_manifest *)man_ptr;
+
+       dev_info(scomp->dev,
+                "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
+                 le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
+                 le16_to_cpu(manifest->abi_patch),
+                 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+       /* TODO: Add ABI compatibility check */
+
+       /* no more data after the ABI version */
+       if (size <= SOF_IPC4_TPLG_ABI_SIZE)
+               return 0;
+
+       manifest_tlv = manifest->items;
+       len_check = sizeof(struct sof_manifest);
+       for (i = 0; i < le16_to_cpu(manifest->count); i++) {
+               len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+               if (len_check > size)
+                       return -EINVAL;
+
+               switch (le32_to_cpu(manifest_tlv->type)) {
+               case SOF_MANIFEST_DATA_TYPE_NHLT:
+                       /* no NHLT in BIOS, so use the one from topology manifest */
+                       if (ipc4_data->nhlt)
+                               break;
+                       ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
+                                                      le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
+                       if (!ipc4_data->nhlt)
+                               return -ENOMEM;
+                       break;
+               default:
+                       dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
+                                manifest_tlv->type);
+                       break;
+               }
+               man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+               manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
+       }
+
+       return 0;
+}
+
+static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
+{
+       struct sof_ipc4_copier *ipc4_copier = dai->private;
+       struct snd_soc_tplg_hw_config *hw_config;
+       struct snd_sof_dai_link *slink;
+       bool dai_link_found = false;
+       bool hw_cfg_found = false;
+       int i;
+
+       if (!ipc4_copier)
+               return 0;
+
+       list_for_each_entry(slink, &sdev->dai_link_list, list) {
+               if (!strcmp(slink->link->name, dai->name)) {
+                       dai_link_found = true;
+                       break;
+               }
+       }
+
+       if (!dai_link_found) {
+               dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < slink->num_hw_configs; i++) {
+               hw_config = &slink->hw_configs[i];
+               if (dai->current_config == le32_to_cpu(hw_config->id)) {
+                       hw_cfg_found = true;
+                       break;
+               }
+       }
+
+       if (!hw_cfg_found) {
+               dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
+               return -EINVAL;
+       }
+
+       switch (ipc4_copier->dai_type) {
+       case SOF_DAI_INTEL_SSP:
+               switch (clk_type) {
+               case SOF_DAI_CLK_INTEL_SSP_MCLK:
+                       return le32_to_cpu(hw_config->mclk_rate);
+               case SOF_DAI_CLK_INTEL_SSP_BCLK:
+                       return le32_to_cpu(hw_config->bclk_rate);
+               default:
+                       dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
+                       break;
+               }
+               break;
+       default:
+               dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static enum sof_tokens host_token_list[] = {
+       SOF_COMP_TOKENS,
+       SOF_AUDIO_FMT_NUM_TOKENS,
+       SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+       SOF_IN_AUDIO_FORMAT_TOKENS,
+       SOF_OUT_AUDIO_FORMAT_TOKENS,
+       SOF_COPIER_GATEWAY_CFG_TOKENS,
+       SOF_COPIER_TOKENS,
+       SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens pipeline_token_list[] = {
+       SOF_SCHED_TOKENS,
+       SOF_PIPELINE_TOKENS,
+};
+
+static enum sof_tokens dai_token_list[] = {
+       SOF_COMP_TOKENS,
+       SOF_AUDIO_FMT_NUM_TOKENS,
+       SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+       SOF_IN_AUDIO_FORMAT_TOKENS,
+       SOF_OUT_AUDIO_FORMAT_TOKENS,
+       SOF_COPIER_GATEWAY_CFG_TOKENS,
+       SOF_COPIER_TOKENS,
+       SOF_DAI_TOKENS,
+       SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens pga_token_list[] = {
+       SOF_COMP_TOKENS,
+       SOF_GAIN_TOKENS,
+       SOF_AUDIO_FMT_NUM_TOKENS,
+       SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+       SOF_IN_AUDIO_FORMAT_TOKENS,
+       SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens mixer_token_list[] = {
+       SOF_COMP_TOKENS,
+       SOF_AUDIO_FMT_NUM_TOKENS,
+       SOF_IN_AUDIO_FORMAT_TOKENS,
+       SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+       SOF_COMP_EXT_TOKENS,
+};
+
+static enum sof_tokens src_token_list[] = {
+       SOF_COMP_TOKENS,
+       SOF_SRC_TOKENS,
+       SOF_AUDIO_FMT_NUM_TOKENS,
+       SOF_IN_AUDIO_FORMAT_TOKENS,
+       SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+       SOF_COMP_EXT_TOKENS,
+};
+
+static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
+       [snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
+                                 host_token_list, ARRAY_SIZE(host_token_list), NULL,
+                                 sof_ipc4_prepare_copier_module,
+                                 sof_ipc4_unprepare_copier_module},
+       [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
+                                 host_token_list, ARRAY_SIZE(host_token_list), NULL,
+                                 sof_ipc4_prepare_copier_module,
+                                 sof_ipc4_unprepare_copier_module},
+       [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
+                                dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+                                sof_ipc4_prepare_copier_module,
+                                sof_ipc4_unprepare_copier_module},
+       [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
+                                 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+                                 sof_ipc4_prepare_copier_module,
+                                 sof_ipc4_unprepare_copier_module},
+       [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
+                                   pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
+                                   NULL, NULL},
+       [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
+                             pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
+                             sof_ipc4_prepare_gain_module,
+                             NULL},
+       [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
+                               mixer_token_list, ARRAY_SIZE(mixer_token_list),
+                               NULL, sof_ipc4_prepare_mixer_module,
+                               NULL},
+       [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
+                               src_token_list, ARRAY_SIZE(src_token_list),
+                               NULL, sof_ipc4_prepare_src_module,
+                               NULL},
+};
+
+const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
+       .widget = tplg_ipc4_widget_ops,
+       .token_list = ipc4_token_list,
+       .control_setup = sof_ipc4_control_setup,
+       .control = &tplg_ipc4_control_ops,
+       .widget_setup = sof_ipc4_widget_setup,
+       .widget_free = sof_ipc4_widget_free,
+       .route_setup = sof_ipc4_route_setup,
+       .route_free = sof_ipc4_route_free,
+       .dai_config = sof_ipc4_dai_config,
+       .parse_manifest = sof_ipc4_parse_manifest,
+       .dai_get_clk = sof_ipc4_dai_get_clk,
+};
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
new file mode 100644 (file)
index 0000000..0aa87a8
--- /dev/null
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2022 Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__
+#define __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__
+
+#include <sound/sof/ipc4/header.h>
+
+#define SOF_IPC4_FW_PAGE_SIZE BIT(12)
+#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12)
+#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1)))
+
+#define SOF_IPC4_MODULE_LOAD_TYPE              GENMASK(3, 0)
+#define SOF_IPC4_MODULE_AUTO_START             BIT(4)
+/*
+ * Two module schedule domains in fw :
+ * LL domain - Low latency domain
+ * DP domain - Data processing domain
+ * The LL setting should be equal to !DP setting
+ */
+#define SOF_IPC4_MODULE_LL             BIT(5)
+#define SOF_IPC4_MODULE_DP             BIT(6)
+#define SOF_IPC4_MODULE_LIB_CODE               BIT(7)
+
+#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12
+#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
+#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128
+#define SOF_IPC4_LL_TASK_OBJECT_SIZE 72
+#define SOF_IPC4_DP_TASK_OBJECT_SIZE 104
+#define SOF_IPC4_DP_TASK_LIST_SIZE (12 + 8)
+#define SOF_IPC4_LL_TASK_LIST_ITEM_SIZE 12
+#define SOF_IPC4_FW_MAX_PAGE_COUNT 20
+#define SOF_IPC4_FW_MAX_QUEUE_COUNT 8
+
+/* Node index and mask applicable for host copier and ALH/HDA type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_MASK       0xFF
+#define SOF_IPC4_NODE_INDEX(x) ((x) & SOF_IPC4_NODE_INDEX_MASK)
+#define SOF_IPC4_NODE_TYPE(x)  ((x) << 8)
+
+/* Node ID for SSP type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4)
+
+/* Node ID for DMIC type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_INTEL_DMIC(x) (((x) & 0x7) << 5)
+
+#define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
+#define SOF_IPC4_VOL_ZERO_DB   0x7fffffff
+
+#define ALH_MAX_NUMBER_OF_GTW   16
+
+/*
+ * The base of multi-gateways. Multi-gateways addressing starts from
+ * ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources
+ * and ALH_MULTI_GTW_COUNT multi-sinks available.
+ * Addressing is continuous from ALH_MULTI_GTW_BASE to
+ * ALH_MULTI_GTW_BASE + ALH_MULTI_GTW_COUNT - 1.
+ */
+#define ALH_MULTI_GTW_BASE     0x50
+/* A magic number from FW */
+#define ALH_MULTI_GTW_COUNT    8
+
+/**
+ * struct sof_ipc4_pipeline - pipeline config data
+ * @priority: Priority of this pipeline
+ * @lp_mode: Low power mode
+ * @mem_usage: Memory usage
+ * @state: Pipeline state
+ * @msg: message structure for pipeline
+ */
+struct sof_ipc4_pipeline {
+       uint32_t priority;
+       uint32_t lp_mode;
+       uint32_t mem_usage;
+       int state;
+       struct sof_ipc4_msg msg;
+};
+
+/**
+ * struct sof_ipc4_available_audio_format - Available audio formats
+ * @base_config: Available base config
+ * @out_audio_fmt: Available output audio format
+ * @ref_audio_fmt: Reference audio format to match runtime audio format
+ * @dma_buffer_size: Available Gateway DMA buffer size (in bytes)
+ * @audio_fmt_num: Number of available audio formats
+ */
+struct sof_ipc4_available_audio_format {
+       struct sof_ipc4_base_module_cfg *base_config;
+       struct sof_ipc4_audio_format *out_audio_fmt;
+       struct sof_ipc4_audio_format *ref_audio_fmt;
+       u32 *dma_buffer_size;
+       int audio_fmt_num;
+};
+
+/**
+ * struct sof_copier_gateway_cfg - IPC gateway configuration
+ * @node_id: ID of Gateway Node
+ * @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes)
+ * @config_length: Length of gateway node configuration blob specified in #config_data
+ * config_data: Gateway node configuration blob
+ */
+struct sof_copier_gateway_cfg {
+       uint32_t node_id;
+       uint32_t dma_buffer_size;
+       uint32_t config_length;
+       uint32_t config_data[];
+};
+
+/**
+ * struct sof_ipc4_copier_data - IPC data for copier
+ * @base_config: Base configuration including input audio format
+ * @out_format: Output audio format
+ * @copier_feature_mask: Copier feature mask
+ * @gtw_cfg: Gateway configuration
+ */
+struct sof_ipc4_copier_data {
+       struct sof_ipc4_base_module_cfg base_config;
+       struct sof_ipc4_audio_format out_format;
+       uint32_t copier_feature_mask;
+       struct sof_copier_gateway_cfg gtw_cfg;
+};
+
+/**
+ * struct sof_ipc4_gtw_attributes: Gateway attributes
+ * @lp_buffer_alloc: Gateway data requested in low power memory
+ * @alloc_from_reg_file: Gateway data requested in register file memory
+ * @rsvd: reserved for future use
+ */
+struct sof_ipc4_gtw_attributes {
+       uint32_t lp_buffer_alloc : 1;
+       uint32_t alloc_from_reg_file : 1;
+       uint32_t rsvd : 30;
+};
+
+/** struct sof_ipc4_alh_multi_gtw_cfg: ALH gateway cfg data
+ * @count: Number of streams (valid items in mapping array)
+ * @alh_id: ALH stream id of a single ALH stream aggregated
+ * @channel_mask: Channel mask
+ * @mapping: ALH streams
+ */
+struct sof_ipc4_alh_multi_gtw_cfg {
+       uint32_t count;
+       struct {
+               uint32_t alh_id;
+               uint32_t channel_mask;
+       } mapping[ALH_MAX_NUMBER_OF_GTW];
+} __packed;
+
+/** struct sof_ipc4_alh_configuration_blob: ALH blob
+ * @gw_attr: Gateway attributes
+ * @alh_cfg: ALH configuration data
+ */
+struct sof_ipc4_alh_configuration_blob {
+       struct sof_ipc4_gtw_attributes gw_attr;
+       struct sof_ipc4_alh_multi_gtw_cfg alh_cfg;
+};
+
+/**
+ * struct sof_ipc4_copier - copier config data
+ * @data: IPC copier data
+ * @copier_config: Copier + blob
+ * @ipc_config_size: Size of copier_config
+ * @available_fmt: Available audio format
+ * @frame_fmt: frame format
+ * @msg: message structure for copier
+ * @gtw_attr: Gateway attributes for copier blob
+ * @dai_type: DAI type
+ * @dai_index: DAI index
+ */
+struct sof_ipc4_copier {
+       struct sof_ipc4_copier_data data;
+       u32 *copier_config;
+       uint32_t ipc_config_size;
+       void *ipc_config_data;
+       struct sof_ipc4_available_audio_format available_fmt;
+       u32 frame_fmt;
+       struct sof_ipc4_msg msg;
+       struct sof_ipc4_gtw_attributes *gtw_attr;
+       u32 dai_type;
+       int dai_index;
+};
+
+/**
+ * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data
+ * @channel: Channel ID
+ * @value: gain value
+ */
+struct sof_ipc4_ctrl_value_chan {
+       u32 channel;
+       u32 value;
+};
+
+/**
+ * struct sof_ipc4_control_data - IPC data for kcontrol IO
+ * @msg: message structure for kcontrol IO
+ * @index: pipeline ID
+ * @chanv: channel ID and value array used by volume type controls
+ * @data: data for binary kcontrols
+ */
+struct sof_ipc4_control_data {
+       struct sof_ipc4_msg msg;
+       int index;
+
+       union {
+               struct sof_ipc4_ctrl_value_chan chanv[0];
+               struct sof_abi_hdr data[0];
+       };
+};
+
+/**
+ * struct sof_ipc4_gain_data - IPC gain blob
+ * @channels: Channels
+ * @init_val: Initial value
+ * @curve_type: Curve type
+ * @reserved: reserved for future use
+ * @curve_duration: Curve duration
+ */
+struct sof_ipc4_gain_data {
+       uint32_t channels;
+       uint32_t init_val;
+       uint32_t curve_type;
+       uint32_t reserved;
+       uint32_t curve_duration;
+} __aligned(8);
+
+/**
+ * struct sof_ipc4_gain - gain config data
+ * @base_config: IPC base config data
+ * @data: IPC gain blob
+ * @available_fmt: Available audio format
+ * @msg: message structure for gain
+ */
+struct sof_ipc4_gain {
+       struct sof_ipc4_base_module_cfg base_config;
+       struct sof_ipc4_gain_data data;
+       struct sof_ipc4_available_audio_format available_fmt;
+       struct sof_ipc4_msg msg;
+};
+
+/**
+ * struct sof_ipc4_mixer - mixer config data
+ * @base_config: IPC base config data
+ * @available_fmt: Available audio format
+ * @msg: IPC4 message struct containing header and data info
+ */
+struct sof_ipc4_mixer {
+       struct sof_ipc4_base_module_cfg base_config;
+       struct sof_ipc4_available_audio_format available_fmt;
+       struct sof_ipc4_msg msg;
+};
+
+/**
+ * struct sof_ipc4_src SRC config data
+ * @base_config: IPC base config data
+ * @sink_rate: Output rate for sink module
+ * @available_fmt: Available audio format
+ * @msg: IPC4 message struct containing header and data info
+ */
+struct sof_ipc4_src {
+       struct sof_ipc4_base_module_cfg base_config;
+       uint32_t sink_rate;
+       struct sof_ipc4_available_audio_format available_fmt;
+       struct sof_ipc4_msg msg;
+};
+
+#endif
index 658802c86685a5c5c32de45b80ffb093b6b7c550..432b812bdf9c68810188a2ae775584d087956397 100644 (file)
@@ -574,7 +574,7 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
                data_size = sizeof(struct sof_ipc4_notify_resource_data);
                break;
        default:
-               dev_dbg(sdev->dev, "%s: Unhandled DSP message: %#x|%#x\n", __func__,
+               dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n",
                        ipc4_msg->primary, ipc4_msg->extension);
                break;
        }
@@ -597,10 +597,53 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
        }
 }
 
+static int sof_ipc4_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
+{
+       struct sof_ipc4_dx_state_info dx_state;
+       struct sof_ipc4_msg msg;
+
+       dx_state.core_mask = BIT(core_idx);
+       if (on)
+               dx_state.dx_mask = BIT(core_idx);
+       else
+               dx_state.dx_mask = 0;
+
+       msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX);
+       msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+       msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+       msg.extension = 0;
+       msg.data_ptr = &dx_state;
+       msg.data_size = sizeof(dx_state);
+
+       return sof_ipc4_tx_msg(sdev, &msg, msg.data_size, NULL, 0, false);
+}
+
+/*
+ * The context save callback is used to send a message to the firmware notifying
+ * it that the primary core is going to be turned off, which is used as an
+ * indication to prepare for a full power down, thus preparing for IMR boot
+ * (when supported)
+ *
+ * Note: in IPC4 there is no message used to restore context, thus no context
+ * restore callback is implemented
+ */
+static int sof_ipc4_ctx_save(struct snd_sof_dev *sdev)
+{
+       return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false);
+}
+
+static const struct sof_ipc_pm_ops ipc4_pm_ops = {
+       .ctx_save = sof_ipc4_ctx_save,
+       .set_core_state = sof_ipc4_set_core_state,
+};
+
 const struct sof_ipc_ops ipc4_ops = {
        .tx_msg = sof_ipc4_tx_msg,
        .rx_msg = sof_ipc4_rx_msg,
        .set_get_data = sof_ipc4_set_get_data,
        .get_reply = sof_ipc4_get_reply,
+       .pm = &ipc4_pm_ops,
        .fw_loader = &ipc4_loader_ops,
+       .tplg = &ipc4_tplg_ops,
+       .pcm = &ipc4_pcm_ops,
 };
index a149dd1b3f44c558af27066945bba56619846238..4a2eddf6009a5593651f09dc17af77214760f232 100644 (file)
@@ -15,6 +15,7 @@ config SND_SOC_SOF_MTK_COMMON
        tristate
        select SND_SOC_SOF_OF_DEV
        select SND_SOC_SOF
+       select SND_SOC_SOF_IPC3
        select SND_SOC_SOF_XTENSA
        select SND_SOC_SOF_COMPRESS
        help
index 4ab998756bbc053050f25e291d5c358dee6093d8..d41e904e6614e2c214309d587d4c65c931d1e202 100644 (file)
@@ -20,6 +20,7 @@ struct mtk_adsp_chip_info {
        u32 sramsize;
        u32 dramsize;
        u32 cfgregsize;
+       u32 shared_size;
        void __iomem *va_sram; /* corresponding to pa_sram */
        void __iomem *va_dram; /* corresponding to pa_dram */
        void __iomem *va_cfgreg;
index 22220fd50b626a090eb797fa566f407160f40896..2df3b7ae1c6f510feae21f0f052dcd1bf28f3583 100644 (file)
@@ -18,8 +18,8 @@
 #include "mt8186-clk.h"
 
 static const char *adsp_clks[ADSP_CLK_MAX] = {
-       [CLK_TOP_AUDIODSP] = "audiodsp_sel",
-       [CLK_TOP_ADSP_BUS] = "adsp_bus_sel",
+       [CLK_TOP_AUDIODSP] = "audiodsp",
+       [CLK_TOP_ADSP_BUS] = "adsp_bus",
 };
 
 int mt8186_adsp_init_clock(struct snd_sof_dev *sdev)
index 6bcb4b9b00fb9ea0779dac23d61bbc3e3b3d2108..9ef08e43aa38b2db830931e4ee7bbf56def4dc03 100644 (file)
@@ -132,6 +132,13 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable)
                        return ret;
                }
 
+               ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_H],
+                                    priv->clk[CLK_TOP_CLK26M]);
+               if (ret) {
+                       dev_err(dev, "set audio_h_sel failed %d\n", ret);
+                       return ret;
+               }
+
                ret = adsp_enable_all_clock(sdev);
                if (ret) {
                        dev_err(dev, "failed to adsp_enable_clock: %d\n", ret);
index ed18d6379e922c2a1f747f593b97daac89ec6111..4be99ff4ebd33ec4a9a7b7166045c3e551e8b522 100644 (file)
@@ -21,7 +21,7 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
 
        /* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */
        snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
-                               DSP_RESET_SW, DSP_RESET_SW);
+                               STATVECTOR_SEL, STATVECTOR_SEL);
 
        /* toggle  DReset & BReset */
        /* pull high DReset & BReset */
@@ -29,6 +29,9 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
                                ADSP_BRESET_SW | ADSP_DRESET_SW,
                                ADSP_BRESET_SW | ADSP_DRESET_SW);
 
+       /* delay 10 DSP cycles at 26M about 1us by IP vendor's suggestion */
+       udelay(1);
+
        /* pull low DReset & BReset */
        snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
                                ADSP_BRESET_SW | ADSP_DRESET_SW,
@@ -46,11 +49,13 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
 
 void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev)
 {
-       /* Clear to 0 firstly */
-       snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_RESET_SW, 0x0);
-
        /* RUN_STALL pull high again to reset */
        snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
                                ADSP_RUNSTALL, ADSP_RUNSTALL);
+
+       /* pull high DReset & BReset */
+       snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
+                               ADSP_BRESET_SW | ADSP_DRESET_SW,
+                               ADSP_BRESET_SW | ADSP_DRESET_SW);
 }
 
index 30111ab23bf5e3b9b8846c6746f2b4a6b5a4f638..9c146015cd1b7bd728d3b5e04e7aeb4edc3a5771 100644 (file)
@@ -145,6 +145,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
 
        dev_dbg(dev, "DMA %pR\n", &res);
 
+       adsp->pa_shared_dram = (phys_addr_t)res.start;
+       adsp->shared_size = resource_size(&res);
+       if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
+               dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
+                       (u32)adsp->pa_shared_dram);
+               return -EINVAL;
+       }
+
        ret = of_reserved_mem_device_init(dev);
        if (ret) {
                dev_err(dev, "of_reserved_mem_device_init failed\n");
@@ -273,23 +281,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
 {
        struct device *dev = &pdev->dev;
        struct mtk_adsp_chip_info *adsp = data;
-       u32 shared_size;
 
        /* remap shared-dram base to be non-cachable */
-       shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL;
-       adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size;
-       if (adsp->va_dram) {
-               adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size;
-       } else {
-               adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
-                                                shared_size);
-               if (!adsp->shared_dram) {
-                       dev_err(dev, "ioremap failed for shared DRAM\n");
-                       return -ENOMEM;
-               }
+       adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
+                                        adsp->shared_size);
+       if (!adsp->shared_dram) {
+               dev_err(dev, "failed to ioremap base %pa size %#x\n",
+                       adsp->shared_dram, adsp->shared_size);
+               return -ENOMEM;
        }
+
        dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa,  size=%#x\n",
-               adsp->shared_dram, &adsp->pa_shared_dram, shared_size);
+               adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
 
        return 0;
 }
@@ -361,9 +364,11 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
                goto err_adsp_sram_power_off;
        }
 
-       sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev,
-                                                         priv->adsp->pa_dram,
-                                                         priv->adsp->dramsize);
+       priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM];
+
+       sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev,
+                                                      priv->adsp->pa_dram,
+                                                      priv->adsp->dramsize);
        if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
                dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
                        &priv->adsp->pa_dram, priv->adsp->dramsize);
@@ -438,6 +443,19 @@ static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
 {
        struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
        int ret;
+       u32 reset_sw, dbg_pc;
+
+       /* wait dsp enter idle, timeout is 1 second */
+       ret = snd_sof_dsp_read_poll_timeout(sdev, DSP_REG_BAR,
+                                           DSP_RESET_SW, reset_sw,
+                                           ((reset_sw & ADSP_PWAIT) == ADSP_PWAIT),
+                                           SUSPEND_DSP_IDLE_POLL_INTERVAL_US,
+                                           SUSPEND_DSP_IDLE_TIMEOUT_US);
+       if (ret < 0) {
+               dbg_pc = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGPC);
+               dev_warn(sdev->dev, "dsp not idle, powering off anyway : swrest %#x, pc %#x, ret %d\n",
+                        reset_sw, dbg_pc, ret);
+       }
 
        /* stall and reset dsp */
        sof_hifixdsp_shutdown(sdev);
index 92942418235724a79b8e87a8e9e0d305c02d5cb0..7ffd523f936c8283065ec81c3b75c397699b27e7 100644 (file)
@@ -34,6 +34,7 @@ struct snd_sof_dev;
 #define ADSP_DRESET_SW                 BIT(1)
 #define ADSP_RUNSTALL                  BIT(3)
 #define STATVECTOR_SEL                 BIT(4)
+#define ADSP_PWAIT                     BIT(16)
 #define DSP_PFAULTBUS                  0x0028
 #define DSP_PFAULTINFO                 0x002c
 #define DSP_GPR00                      0x0030
@@ -153,6 +154,10 @@ struct snd_sof_dev;
 #define DRAM_REMAP_SHIFT       12
 #define DRAM_REMAP_MASK                (BIT(DRAM_REMAP_SHIFT) - 1)
 
+/* suspend dsp idle check interval and timeout */
+#define SUSPEND_DSP_IDLE_TIMEOUT_US            1000000 /* timeout to wait dsp idle, 1 sec */
+#define SUSPEND_DSP_IDLE_POLL_INTERVAL_US      500     /* 0.5 msec */
+
 void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr);
 void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev);
 #endif
index b79ae4f66ebaa6c23f021774f7c7972046663e1e..55d43adb6a2951739165d78b0479e40558580840 100644 (file)
@@ -29,6 +29,12 @@ static inline int sof_ops_init(struct snd_sof_dev *sdev)
        return 0;
 }
 
+static inline void sof_ops_free(struct snd_sof_dev *sdev)
+{
+       if (sdev->pdata->desc->ops_free)
+               sdev->pdata->desc->ops_free(sdev);
+}
+
 /* Mandatory operations are verified during probing */
 
 /* init */
index a76d0b5b2ad950a4e411e0e12872346325bc21f0..6cb6a432be5e99ffca60825daceefb0e000e9be4 100644 (file)
@@ -604,6 +604,14 @@ static int sof_pcm_probe(struct snd_soc_component *component)
        const char *tplg_filename;
        int ret;
 
+       /*
+        * make sure the device is pm_runtime_active before loading the
+        * topology and initiating IPC or bus transactions
+        */
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
        /* load the default topology */
        sdev->component = component;
 
@@ -621,6 +629,9 @@ static int sof_pcm_probe(struct snd_soc_component *component)
                return ret;
        }
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return ret;
 }
 
@@ -671,4 +682,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
 
         /* increment module refcount when a pcm is opened */
        pd->module_get_upon_open = 1;
+
+       pd->legacy_dai_naming = 1;
 }
index 27cc5fb642e57c6391808acce02040c1d3f9a754..4284ea2f3a1ff2275a7a939e6cdd94f50f7f6824 100644 (file)
@@ -168,6 +168,7 @@ struct sof_ipc_tplg_widget_ops {
  * @dai_get_clk: Function pointer for getting the DAI clock setting
  * @set_up_all_pipelines: Function pointer for setting up all topology pipelines
  * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines
+ * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest
  */
 struct sof_ipc_tplg_ops {
        const struct sof_ipc_tplg_widget_ops *widget;
@@ -185,6 +186,8 @@ struct sof_ipc_tplg_ops {
        int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type);
        int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
        int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
+       int (*parse_manifest)(struct snd_soc_component *scomp, int index,
+                             struct snd_soc_tplg_manifest *man);
 };
 
 /** struct snd_sof_tuple - Tuple info
@@ -225,6 +228,15 @@ enum sof_tokens {
        SOF_AFE_TOKENS,
        SOF_CORE_TOKENS,
        SOF_COMP_EXT_TOKENS,
+       SOF_IN_AUDIO_FORMAT_TOKENS,
+       SOF_OUT_AUDIO_FORMAT_TOKENS,
+       SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+       SOF_COPIER_GATEWAY_CFG_TOKENS,
+       SOF_COPIER_TOKENS,
+       SOF_AUDIO_FMT_NUM_TOKENS,
+       SOF_COPIER_FORMAT_TOKENS,
+       SOF_GAIN_TOKENS,
+       SOF_ACPDMIC_TOKENS,
 
        /* this should be the last */
        SOF_TOKEN_COUNT,
index 6bdfa527b7f76b39c4fd04d3d0fdabe9f521c48e..752d5320680f14449847543faecf42dd3daff69c 100644 (file)
@@ -181,7 +181,7 @@ static ssize_t sof_msg_inject_ipc4_dfs_write(struct file *file,
        struct sof_client_dev *cdev = file->private_data;
        struct sof_msg_inject_priv *priv = cdev->data;
        struct sof_ipc4_msg *ipc4_msg = priv->tx_buffer;
-       ssize_t size;
+       size_t data_size;
        int ret;
 
        if (*ppos)
@@ -191,25 +191,20 @@ static ssize_t sof_msg_inject_ipc4_dfs_write(struct file *file,
                return -EINVAL;
 
        /* copy the header first */
-       size = simple_write_to_buffer(&ipc4_msg->header_u64,
-                                     sizeof(ipc4_msg->header_u64),
-                                     ppos, buffer, count);
-       if (size < 0)
-               return size;
-       if (size != sizeof(ipc4_msg->header_u64))
+       if (copy_from_user(&ipc4_msg->header_u64, buffer,
+                          sizeof(ipc4_msg->header_u64)))
                return -EFAULT;
 
-       count -= size;
+       data_size = count - sizeof(ipc4_msg->header_u64);
+       if (data_size > priv->max_msg_size)
+               return -EINVAL;
+
        /* Copy the payload */
-       size = simple_write_to_buffer(ipc4_msg->data_ptr,
-                                     priv->max_msg_size, ppos, buffer,
-                                     count);
-       if (size < 0)
-               return size;
-       if (size != count)
+       if (copy_from_user(ipc4_msg->data_ptr,
+                          buffer + sizeof(ipc4_msg->header_u64), data_size))
                return -EFAULT;
 
-       ipc4_msg->data_size = count;
+       ipc4_msg->data_size = data_size;
 
        /* Initialize the reply storage */
        ipc4_msg = priv->rx_buffer;
@@ -221,9 +216,9 @@ static ssize_t sof_msg_inject_ipc4_dfs_write(struct file *file,
 
        /* return the error code if test failed */
        if (ret < 0)
-               size = ret;
+               return ret;
 
-       return size;
+       return count;
 };
 
 static int sof_msg_inject_dfs_release(struct inode *inode, struct file *file)
index 34e6bd356e7179592de9be16c110ebd96a1b9dcb..eb246b8234614cde8f18b6ab8f6a3cbba5f64ebc 100644 (file)
@@ -270,9 +270,9 @@ static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
        if (ret)
                return ret;
 
-       ret = ops->assign(cdev, cstream, dai, &priv->extractor_stream_tag);
+       ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag);
        if (ret) {
-               dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret);
+               dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret);
                priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
                sof_client_core_module_put(cdev);
        }
@@ -310,7 +310,7 @@ exit:
        priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
        snd_compr_free_pages(cstream);
 
-       ret = ops->free(cdev, cstream, dai);
+       ret = ops->shutdown(cdev, cstream, dai);
 
        sof_client_core_module_put(cdev);
 
@@ -667,6 +667,7 @@ static const struct snd_soc_component_driver sof_probes_component = {
        .name = "sof-probes-component",
        .compress_ops = &sof_probes_compressed_ops,
        .module_get_upon_open = 1,
+       .legacy_dai_naming = 1,
 };
 
 SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
@@ -693,6 +694,10 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
        if (!sof_probes_enabled)
                return -ENXIO;
 
+       /* only ipc3 is supported */
+       if (sof_client_get_ipc_type(cdev) != SOF_IPC)
+               return -ENXIO;
+
        if (!dev->platform_data) {
                dev_err(dev, "missing platform data\n");
                return -ENODEV;
@@ -704,7 +709,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
 
        ops = dev->platform_data;
 
-       if (!ops->assign || !ops->free || !ops->set_params || !ops->trigger ||
+       if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
            !ops->pointer) {
                dev_err(dev, "missing platform callback(s)\n");
                return -ENODEV;
index 0f9ed4569fd3bbe2ee058848a8141f1fb6b7854d..9e43f3c444f8fb919f447cdf02ce69bffb5e956d 100644 (file)
@@ -14,10 +14,10 @@ struct snd_soc_dai;
  * DSP and host, like HDA.
  */
 struct sof_probes_host_ops {
-       int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
-                     struct snd_soc_dai *dai, u32 *stream_id);
-       int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
-                   struct snd_soc_dai *dai);
+       int (*startup)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
+                      struct snd_soc_dai *dai, u32 *stream_id);
+       int (*shutdown)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
+                       struct snd_soc_dai *dai);
        int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
                          struct snd_compr_params *params,
                          struct snd_soc_dai *dai);
index 16cca666bb852be9ddf623c5cef89bbe9ab2d778..125aa21371954d88ca17e8cf057cd9750495a211 100644 (file)
@@ -383,8 +383,8 @@ void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf)
 
                msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary);
        } else {
-               dev_dbg_once(sdev->dev, "%s: Not supported IPC version: %d\n",
-                            __func__, sdev->pdata->ipc_type);
+               dev_dbg_once(sdev->dev, "Not supported IPC version: %d\n",
+                            sdev->pdata->ipc_type);
                return;
        }
 
index f0f3d72c0da73bec5e4f2378fea42ad769e51619..823583086279b3bd092bd392d79c946d4d99f76a 100644 (file)
 #define SOF_DBG_IGNORE_D3_PERSISTENT           BIT(7) /* ignore the DSP D3 persistent capability
                                                        * and always download firmware upon D3 exit
                                                        */
+#define SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS BIT(8) /* print DMA position updates
+                                                       * in dmesg logs
+                                                       */
+#define SOF_DBG_PRINT_IPC_SUCCESS_LOGS         BIT(9) /* print IPC success
+                                                       * in dmesg logs
+                                                       */
 
 /* Flag definitions used for controlling the DSP dump behavior */
 #define SOF_DBG_DUMP_REGS              BIT(0)
@@ -120,6 +126,7 @@ struct snd_sof_platform_stream_params {
        bool use_phy_address;
        u32 phy_addr;
        bool no_ipc_position;
+       bool cont_update_posn;
 };
 
 /*
@@ -378,12 +385,14 @@ struct sof_ipc_fw_tracing_ops {
 
 /**
  * struct sof_ipc_pm_ops - IPC-specific PM ops
- * @ctx_save:          Function pointer for context save
- * @ctx_restore:       Function pointer for context restore
+ * @ctx_save:          Optional function pointer for context save
+ * @ctx_restore:       Optional function pointer for context restore
+ * @set_core_state:    Optional function pointer for turning on/off a DSP core
  */
 struct sof_ipc_pm_ops {
        int (*ctx_save)(struct snd_sof_dev *sdev);
        int (*ctx_restore)(struct snd_sof_dev *sdev);
+       int (*set_core_state)(struct snd_sof_dev *sdev, int core_idx, bool on);
 };
 
 /**
@@ -657,7 +666,7 @@ void sof_print_oops_and_stack(struct snd_sof_dev *sdev, const char *level,
                              u32 panic_code, u32 tracep_code, void *oops,
                              struct sof_ipc_panic_info *panic_info,
                              void *stack, size_t stack_words);
-void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
+void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg);
 int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev);
 int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev,
                enum snd_sof_fw_blk_type blk_type, u32 offset, size_t size,
index b1fcab7ce48e8476a9c4f09578f1aa72488f7e1f..9273a70fec25c5bf439b8fd43b67ed92c92fc6e9 100644 (file)
@@ -36,9 +36,6 @@
 #define TLV_STEP       1
 #define TLV_MUTE       2
 
-/* size of tplg abi in byte */
-#define SOF_TPLG_ABI_SIZE 3
-
 /**
  * sof_update_ipc_object - Parse multiple sets of tokens within the token array associated with the
  *                         token ID.
@@ -1141,6 +1138,21 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
        return 0;
 }
 
+static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
+{
+       int i;
+
+       if (!tuples)
+               return -EINVAL;
+
+       for (i = 0; i < num_tuples; i++) {
+               if (tuples[i].token == token_id)
+                       return tuples[i].value.v;
+       }
+
+       return -EINVAL;
+}
+
 static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_sof_widget *swidget,
                                   struct snd_soc_tplg_dapm_widget *tw,
                                   enum sof_tokens *object_token_list, int count)
@@ -1168,6 +1180,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
 
        /* parse token list for widget */
        for (i = 0; i < count; i++) {
+               int num_sets = 1;
+
                if (object_token_list[i] >= SOF_TOKEN_COUNT) {
                        dev_err(scomp->dev, "Invalid token id %d for widget %s\n",
                                object_token_list[i], swidget->widget->name);
@@ -1175,8 +1189,9 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
                        goto err;
                }
 
-               /* parse and save UUID in swidget */
-               if (object_token_list[i] == SOF_COMP_EXT_TOKENS) {
+               switch (object_token_list[i]) {
+               case SOF_COMP_EXT_TOKENS:
+                       /* parse and save UUID in swidget */
                        ret = sof_parse_tokens(scomp, swidget,
                                               token_list[object_token_list[i]].tokens,
                                               token_list[object_token_list[i]].count,
@@ -1189,11 +1204,41 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
                        }
 
                        continue;
+               case SOF_IN_AUDIO_FORMAT_TOKENS:
+               case SOF_OUT_AUDIO_FORMAT_TOKENS:
+               case SOF_COPIER_GATEWAY_CFG_TOKENS:
+               case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS:
+                       num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS,
+                                                      swidget->tuples, swidget->num_tuples);
+
+                       if (num_sets < 0) {
+                               dev_err(sdev->dev, "Invalid audio format count for %s\n",
+                                       swidget->widget->name);
+                               ret = num_sets;
+                               goto err;
+                       }
+
+                       if (num_sets > 1) {
+                               struct snd_sof_tuple *new_tuples;
+
+                               num_tuples += token_list[object_token_list[i]].count * num_sets;
+                               new_tuples = krealloc(swidget->tuples,
+                                                     sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
+                               if (!new_tuples) {
+                                       ret = -ENOMEM;
+                                       goto err;
+                               }
+
+                               swidget->tuples = new_tuples;
+                       }
+                       break;
+               default:
+                       break;
                }
 
                /* copy one set of tuples per token ID into swidget->tuples */
                ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size),
-                                     object_token_list[i], 1, swidget->tuples,
+                                     object_token_list[i], num_sets, swidget->tuples,
                                      num_tuples, &swidget->num_tuples);
                if (ret < 0) {
                        dev_err(scomp->dev, "Failed parsing %s for widget %s err: %d\n",
@@ -1208,21 +1253,6 @@ err:
        return ret;
 }
 
-static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
-{
-       int i;
-
-       if (!tuples)
-               return -EINVAL;
-
-       for (i = 0; i < num_tuples; i++) {
-               if (tuples[i].token == token_id)
-                       return tuples[i].value.v;
-       }
-
-       return -EINVAL;
-}
-
 /* external widget init - used for any driver specific init */
 static int sof_widget_ready(struct snd_soc_component *scomp, int index,
                            struct snd_soc_dapm_widget *w,
@@ -1389,7 +1419,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
        struct soc_bytes_ext *sbe;
        struct snd_sof_dai *dai;
        struct soc_enum *se;
-       int ret = 0;
        int i;
 
        swidget = dobj->private;
@@ -1450,7 +1479,7 @@ out:
        list_del(&swidget->list);
        kfree(swidget);
 
-       return ret;
+       return 0;
 }
 
 /*
@@ -1709,6 +1738,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
                token_id = SOF_AFE_TOKENS;
                num_tuples += token_list[SOF_AFE_TOKENS].count;
                break;
+       case SOF_DAI_AMD_DMIC:
+               token_id = SOF_ACPDMIC_TOKENS;
+               num_tuples += token_list[SOF_ACPDMIC_TOKENS].count;
+               break;
        default:
                break;
        }
@@ -1987,45 +2020,11 @@ static int sof_complete(struct snd_soc_component *scomp)
 static int sof_manifest(struct snd_soc_component *scomp, int index,
                        struct snd_soc_tplg_manifest *man)
 {
-       u32 size;
-       u32 abi_version;
-
-       size = le32_to_cpu(man->priv.size);
-
-       /* backward compatible with tplg without ABI info */
-       if (!size) {
-               dev_dbg(scomp->dev, "No topology ABI info\n");
-               return 0;
-       }
-
-       if (size != SOF_TPLG_ABI_SIZE) {
-               dev_err(scomp->dev, "error: invalid topology ABI size\n");
-               return -EINVAL;
-       }
-
-       dev_info(scomp->dev,
-                "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
-                man->priv.data[0], man->priv.data[1],
-                man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
-                SOF_ABI_PATCH);
-
-       abi_version = SOF_ABI_VER(man->priv.data[0],
-                                 man->priv.data[1],
-                                 man->priv.data[2]);
-
-       if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
-               dev_err(scomp->dev, "error: incompatible topology ABI version\n");
-               return -EINVAL;
-       }
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
 
-       if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
-               if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
-                       dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
-               } else {
-                       dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
-                       return -EINVAL;
-               }
-       }
+       if (ipc_tplg_ops->parse_manifest)
+               return ipc_tplg_ops->parse_manifest(scomp, index, man);
 
        return 0;
 }
index 4b68d6ee75da4a5a00aaeeffd99efc81656baf54..4ad8b1fc713a77f9969e38160140494612fccf66 100644 (file)
@@ -172,7 +172,8 @@ static struct snd_soc_dai_driver spdif_in_dai = {
 };
 
 static const struct snd_soc_component_driver spdif_in_component = {
-       .name           = "spdif-in",
+       .name                   = "spdif-in",
+       .legacy_dai_naming      = 1,
 };
 
 static irqreturn_t spdif_in_irq(int irq, void *arg)
index 549295a6ed501e936d3f7e168b919c9aa2aeedcb..fb107c5790addc7fbc26e8e18290a2acbe473b86 100644 (file)
@@ -273,7 +273,8 @@ static struct snd_soc_dai_driver spdif_out_dai = {
 };
 
 static const struct snd_soc_component_driver spdif_out_component = {
-       .name           = "spdif-out",
+       .name                   = "spdif-out",
+       .legacy_dai_naming      = 1,
 };
 
 static int spdif_out_probe(struct platform_device *pdev)
index 34668fe3909d1617ea726aca3458c817f75ef7d9..a4d74d1e3c2403321c9fb18fea4dd8550319629f 100644 (file)
@@ -376,7 +376,8 @@ static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
 static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
        .name = "sti_cpu_dai",
        .suspend = sti_uniperiph_suspend,
-       .resume = sti_uniperiph_resume
+       .resume = sti_uniperiph_resume,
+       .legacy_dai_naming = 1,
 };
 
 static int sti_uniperiph_cpu_dai_of(struct device_node *node,
index 6ee714542b84a1a9643cfa476db5583927fe337e..04f2912e14181519c67f20c15e8d23a4c29b7f4d 100644 (file)
@@ -149,6 +149,7 @@ static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
 
 static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
        .name = "stm32_dfsdm_audio",
+       .legacy_dai_naming = 1,
 };
 
 static void stm32_memcpy_32to16(void *dest, const void *src, size_t n)
@@ -296,7 +297,7 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_component *component,
 static int stm32_adfsdm_dummy_cb(const void *data, void *private)
 {
        /*
-        * This dummmy callback is requested by iio_channel_get_all_cb() API,
+        * This dummy callback is requested by iio_channel_get_all_cb() API,
         * but the stm32_dfsdm_get_buff_cb() API is used instead, to optimize
         * DMA transfers.
         */
index ac5dff4d1677a98519ba8623018551798dc464cc..6aafe793eec441d2198322700529d950cca47260 100644 (file)
@@ -593,16 +593,16 @@ static int stm32_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        }
 
        /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                i2s->ms_flg = I2S_MS_SLAVE;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                i2s->ms_flg = I2S_MS_MASTER;
                break;
        default:
                dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
-                       fmt & SND_SOC_DAIFMT_MASTER_MASK);
+                       fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
                return -EINVAL;
        }
 
@@ -978,6 +978,7 @@ static const struct snd_dmaengine_pcm_config stm32_i2s_pcm_config = {
 
 static const struct snd_soc_component_driver stm32_i2s_component = {
        .name = "stm32-i2s",
+       .legacy_dai_naming = 1,
 };
 
 static void stm32_i2s_dai_init(struct snd_soc_pcm_stream *stream,
index dd636af81c9bd74fc1c83f5c7c5f3b374cdacc71..eb31b49e659785bd0087e940dbfd1a6e2363de8e 100644 (file)
@@ -45,8 +45,6 @@
 #define STM_SAI_B_ID           0x1
 
 #define STM_SAI_IS_SUB_A(x)    ((x)->id == STM_SAI_A_ID)
-#define STM_SAI_IS_SUB_B(x)    ((x)->id == STM_SAI_B_ID)
-#define STM_SAI_BLOCK_NAME(x)  (((x)->id == STM_SAI_A_ID) ? "A" : "B")
 
 #define SAI_SYNC_NONE          0x0
 #define SAI_SYNC_INTERNAL      0x1
@@ -719,18 +717,18 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
        stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
 
        /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                /* codec is master */
                cr1 |= SAI_XCR1_SLAVE;
                sai->master = false;
                break;
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                sai->master = true;
                break;
        default:
                dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
-                       fmt & SND_SOC_DAIFMT_MASTER_MASK);
+                       fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
                return -EINVAL;
        }
 
@@ -1338,6 +1336,7 @@ static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = {
 
 static const struct snd_soc_component_driver stm32_component = {
        .name = "stm32-sai",
+       .legacy_dai_naming = 1,
 };
 
 static const struct of_device_id stm32_sai_sub_ids[] = {
index 6f7882c4fe6ad101c841807bc0a3762e5b51e5c8..0f7146756717670cb5c6f8b240a5b0e9549a6933 100644 (file)
@@ -888,6 +888,7 @@ static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = {
 
 static const struct snd_soc_component_driver stm32_spdifrx_component = {
        .name = "stm32-spdifrx",
+       .legacy_dai_naming = 1,
 };
 
 static const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config = {
index 60712f24ade59ee715a08d37fb100cfb2474bda2..830beb38bf1563cbd5fd23125f2bf5b555c1932f 100644 (file)
@@ -250,37 +250,33 @@ struct sun4i_codec {
 static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
 {
        /* Flush TX FIFO */
-       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
-                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
+       regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                       BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
 
        /* Enable DAC DRQ */
-       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                          BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
-                          BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
+       regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                       BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
 }
 
 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
 {
        /* Disable DAC DRQ */
-       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                          BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
-                          0);
+       regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                         BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
 }
 
 static void sun4i_codec_start_capture(struct sun4i_codec *scodec)
 {
        /* Enable ADC DRQ */
-       regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN),
-                                BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
+       regmap_field_set_bits(scodec->reg_adc_fifoc,
+                             BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
 }
 
 static void sun4i_codec_stop_capture(struct sun4i_codec *scodec)
 {
        /* Disable ADC DRQ */
-       regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0);
+       regmap_field_clear_bits(scodec->reg_adc_fifoc,
+                                BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN));
 }
 
 static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -323,8 +319,7 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream,
 
 
        /* Flush RX FIFO */
-       regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH),
+       regmap_field_set_bits(scodec->reg_adc_fifoc,
                                 BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH));
 
 
@@ -365,8 +360,7 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
        u32 val;
 
        /* Flush the TX FIFO */
-       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                          BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
+       regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
                           BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
 
        /* Set TX FIFO Empty Trigger Level */
@@ -386,9 +380,8 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream,
                           val);
 
        /* Send zeros when we have an underrun */
-       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                          BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
-                          0);
+       regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                          BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT));
 
        return 0;
 };
@@ -485,33 +478,27 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec,
 
        /* Set the number of channels we want to use */
        if (params_channels(params) == 1)
-               regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                        BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
+               regmap_field_set_bits(scodec->reg_adc_fifoc,
                                         BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
        else
-               regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                        BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN),
-                                        0);
+               regmap_field_clear_bits(scodec->reg_adc_fifoc,
+                                        BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN));
 
        /* Set the number of sample bits to either 16 or 24 bits */
        if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
-               regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                  BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
+               regmap_field_set_bits(scodec->reg_adc_fifoc,
                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
 
-               regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                  BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
-                                  0);
+               regmap_field_clear_bits(scodec->reg_adc_fifoc,
+                                  BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
 
                scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        } else {
-               regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                  BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS),
-                                  0);
+               regmap_field_clear_bits(scodec->reg_adc_fifoc,
+                                  BIT(SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS));
 
                /* Fill most significant bits with valid data MSB */
-               regmap_field_update_bits(scodec->reg_adc_fifoc,
-                                  BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE),
+               regmap_field_set_bits(scodec->reg_adc_fifoc,
                                   BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE));
 
                scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -543,24 +530,20 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec,
 
        /* Set the number of sample bits to either 16 or 24 bits */
        if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
-               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
+               regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
 
                /* Set TX FIFO mode to padding the LSBs with 0 */
-               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
-                                  0);
+               regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
 
                scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        } else {
-               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
-                                  0);
+               regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
+                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
 
                /* Set TX FIFO mode to repeat the MSB */
-               regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                                  BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
+               regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
                                   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
 
                scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -624,8 +607,7 @@ static int sun4i_codec_startup(struct snd_pcm_substream *substream,
         * Stop issuing DRQ when we have room for less than 16 samples
         * in our TX FIFO
         */
-       regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
-                          3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
+       regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
                           3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
 
        return clk_prepare_enable(scodec->clk_module);
@@ -899,7 +881,6 @@ static const struct snd_soc_component_driver sun4i_codec_codec = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver sun7i_codec_codec = {
@@ -912,7 +893,6 @@ static const struct snd_soc_component_driver sun7i_codec_codec = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /*** sun6i Codec ***/
@@ -1220,7 +1200,6 @@ static const struct snd_soc_component_driver sun6i_codec_codec = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 /* sun8i A23 codec */
@@ -1248,11 +1227,11 @@ static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct snd_soc_component_driver sun4i_codec_component = {
-       .name = "sun4i-codec",
+       .name                   = "sun4i-codec",
+       .legacy_dai_naming      = 1,
 };
 
 #define SUN4I_CODEC_RATES      SNDRV_PCM_RATE_CONTINUOUS
index 7047f71629ab37bbc7f79255a96be5036aefca00..6028871825baea607ce95523417fb377b964fac9 100644 (file)
@@ -161,6 +161,8 @@ struct sun4i_i2s;
  * @field_clkdiv_mclk_en: regmap field to enable mclk output.
  * @field_fmt_wss: regmap field to set word select size.
  * @field_fmt_sr: regmap field to set sample resolution.
+ * @num_din_pins: input pins
+ * @num_dout_pins: output pins (currently set but unused)
  * @bclk_dividers: bit clock dividers array
  * @num_bclk_dividers: number of bit clock dividers
  * @mclk_dividers: mclk dividers array
@@ -702,13 +704,13 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
                           SUN4I_I2S_FMT0_FMT_MASK, val);
 
        /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* BCLK and LRCLK master */
                val = SUN4I_I2S_CTRL_MODE_MASTER;
                break;
 
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* BCLK and LRCLK slave */
                val = SUN4I_I2S_CTRL_MODE_SLAVE;
                break;
@@ -802,13 +804,13 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
                           SUN8I_I2S_TX_CHAN_OFFSET(offset));
 
        /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* BCLK and LRCLK master */
                val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
                break;
 
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* BCLK and LRCLK slave */
                val = 0;
                break;
@@ -909,13 +911,13 @@ static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
                           SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
 
        /* DAI clock master masks */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* BCLK and LRCLK master */
                val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
                break;
 
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* BCLK and LRCLK slave */
                val = 0;
                break;
@@ -1123,7 +1125,8 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver sun4i_i2s_component = {
-       .name   = "sun4i-dai",
+       .name                   = "sun4i-dai",
+       .legacy_dai_naming      = 1,
 };
 
 static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)
index 17090f43150e0a72aedf8f3d35e893780eb2a114..bcceebca915ac80663e3ccbbc8077503f3c6b574 100644 (file)
@@ -583,7 +583,8 @@ static const struct of_device_id sun4i_spdif_of_match[] = {
 MODULE_DEVICE_TABLE(of, sun4i_spdif_of_match);
 
 static const struct snd_soc_component_driver sun4i_spdif_component = {
-       .name           = "sun4i-spdif",
+       .name                   = "sun4i-spdif",
+       .legacy_dai_naming      = 1,
 };
 
 static int sun4i_spdif_runtime_suspend(struct device *dev)
index a41e25ad0aaf012d96ac5bbae7cd008c6f3bc4a2..e1e5e8de01301f3bf18a197552f5df081dd2930a 100644 (file)
 #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN   7
 
 #define SUN50I_ADDA_JACK_MIC_CTRL      0x1d
+#define SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN   6
 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN   5
 
 /* mixer controls */
@@ -507,6 +508,7 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev)
 {
        struct regmap *regmap;
        void __iomem *base;
+       bool enable;
 
        base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base)) {
@@ -520,6 +522,12 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
        }
 
+       enable = device_property_read_bool(&pdev->dev,
+                                          "allwinner,internal-bias-resistor");
+       regmap_update_bits(regmap, SUN50I_ADDA_JACK_MIC_CTRL,
+                          BIT(SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN),
+                          enable << SUN50I_ADDA_JACK_MIC_CTRL_INNERRESEN);
+
        return devm_snd_soc_register_component(&pdev->dev,
                                               &sun50i_codec_analog_cmpnt_drv,
                                               NULL, 0);
index 0bea2162f68d98464ab650118270b6fb6bfa7de9..9844978d91e6e0182318ecd176ca4b0effa7e3d7 100644 (file)
@@ -286,11 +286,11 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        u32 dsp_format, format, invert, value;
 
        /* clock masters */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */
                value = 0x1;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
+       case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */
                value = 0x0;
                break;
        default:
@@ -1278,7 +1278,6 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
        .probe                  = sun8i_codec_component_probe,
        .idle_bias_on           = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static const struct regmap_config sun8i_codec_regmap_config = {
index 2482d98673577cebb00e2787622d0fc87abb91f5..b6712a3d1fa115c8bbcb7512767d8227023eb673 100644 (file)
@@ -85,6 +85,15 @@ config SND_SOC_TEGRA210_I2S
          compatible devices.
          Say Y or M if you want to add support for Tegra210 I2S module.
 
+config SND_SOC_TEGRA210_OPE
+       tristate "Tegra210 OPE module"
+       help
+         Config to enable the Output Processing Engine (OPE) which includes
+         Parametric Equalizer (PEQ) and Multi Band Dynamic Range Compressor
+         (MBDRC) sub blocks for data processing. It can support up to 8
+         channels.
+         Say Y or M if you want to add support for Tegra210 OPE module.
+
 config SND_SOC_TEGRA186_ASRC
        tristate "Tegra186 ASRC module"
        help
index 70a498ddb2fabce0863c4c243a1190c0f0148f79..b723c78e665dac48db337c0b30436f778fc42d18 100644 (file)
@@ -19,6 +19,7 @@ snd-soc-tegra210-sfc-objs := tegra210_sfc.o
 snd-soc-tegra210-amx-objs := tegra210_amx.o
 snd-soc-tegra210-adx-objs := tegra210_adx.o
 snd-soc-tegra210-mixer-objs := tegra210_mixer.o
+snd-soc-tegra210-ope-objs := tegra210_ope.o tegra210_mbdrc.o tegra210_peq.o
 
 obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
 obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_TEGRA210_SFC) += snd-soc-tegra210-sfc.o
 obj-$(CONFIG_SND_SOC_TEGRA210_AMX) += snd-soc-tegra210-amx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_ADX) += snd-soc-tegra210-adx.o
 obj-$(CONFIG_SND_SOC_TEGRA210_MIXER) += snd-soc-tegra210-mixer.o
+obj-$(CONFIG_SND_SOC_TEGRA210_OPE) += snd-soc-tegra210-ope.o
 
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
index c454a34c15c4c46f3808f423abedf5f9057d655f..87facfbcdd110d6371f7f29ebfa5603f0f21ff5e 100644 (file)
@@ -239,7 +239,8 @@ static struct snd_soc_dai_driver tegra20_ac97_dai = {
 };
 
 static const struct snd_soc_component_driver tegra20_ac97_component = {
-       .name           = DRV_NAME,
+       .name                   = DRV_NAME,
+       .legacy_dai_naming      = 1,
 };
 
 static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
@@ -353,6 +354,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
                }
        } else {
                dev_err(&pdev->dev, "no codec-reset GPIO supplied\n");
+               ret = -EINVAL;
                goto err_clk_put;
        }
 
@@ -360,6 +362,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
                                            "nvidia,codec-sync-gpio", 0);
        if (!gpio_is_valid(ac97->sync_gpio)) {
                dev_err(&pdev->dev, "no codec-sync GPIO supplied\n");
+               ret = -EINVAL;
                goto err_clk_put;
        }
 
index 69c651274c12fe0431f129609cd9d0df1367cdbf..c620ab0c601fae50d3fbc4ed7f5c2c04030e3596 100644 (file)
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include "tegra20_das.h"
 
 #define DRV_NAME "tegra20-das"
 
-static struct tegra20_das *das;
+/* Register TEGRA20_DAS_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_CTRL_SEL                       0x00
+#define TEGRA20_DAS_DAP_CTRL_SEL_COUNT                 5
+#define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE                        4
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P          31
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S          1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P    30
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S    1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P    29
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S    1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P                0
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S                5
+
+/* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_SEL_DAC1       0
+#define TEGRA20_DAS_DAP_SEL_DAC2       1
+#define TEGRA20_DAS_DAP_SEL_DAC3       2
+#define TEGRA20_DAS_DAP_SEL_DAP1       16
+#define TEGRA20_DAS_DAP_SEL_DAP2       17
+#define TEGRA20_DAS_DAP_SEL_DAP3       18
+#define TEGRA20_DAS_DAP_SEL_DAP4       19
+#define TEGRA20_DAS_DAP_SEL_DAP5       20
+
+/* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL                     0x40
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT               3
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE              4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P    28
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S    4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P    24
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S    4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P       0
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S       4
 
-static inline void tegra20_das_write(u32 reg, u32 val)
-{
-       regmap_write(das->regmap, reg, val);
-}
-
-static inline u32 tegra20_das_read(u32 reg)
-{
-       u32 val;
+/*
+ * Values for:
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
+ */
+#define TEGRA20_DAS_DAC_SEL_DAP1       0
+#define TEGRA20_DAS_DAC_SEL_DAP2       1
+#define TEGRA20_DAS_DAC_SEL_DAP3       2
+#define TEGRA20_DAS_DAC_SEL_DAP4       3
+#define TEGRA20_DAS_DAC_SEL_DAP5       4
 
-       regmap_read(das->regmap, reg, &val);
-       return val;
-}
+/*
+ * Names/IDs of the DACs/DAPs.
+ */
 
-int tegra20_das_connect_dap_to_dac(int dap, int dac)
-{
-       u32 addr;
-       u32 reg;
+#define TEGRA20_DAS_DAP_ID_1 0
+#define TEGRA20_DAS_DAP_ID_2 1
+#define TEGRA20_DAS_DAP_ID_3 2
+#define TEGRA20_DAS_DAP_ID_4 3
+#define TEGRA20_DAS_DAP_ID_5 4
 
-       if (!das)
-               return -ENODEV;
+#define TEGRA20_DAS_DAC_ID_1 0
+#define TEGRA20_DAS_DAC_ID_2 1
+#define TEGRA20_DAS_DAC_ID_3 2
 
-       addr = TEGRA20_DAS_DAP_CTRL_SEL +
-               (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
-       reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
+struct tegra20_das {
+       struct regmap *regmap;
+};
 
-       tegra20_das_write(addr, reg);
+/*
+ * Terminology:
+ * DAS: Digital audio switch (HW module controlled by this driver)
+ * DAP: Digital audio port (port/pins on Tegra device)
+ * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
+ *
+ * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
+ * DAC, or another DAP. When DAPs are connected, one must be the master and
+ * one the slave. Each DAC allows selection of a specific DAP for input, to
+ * cater for the case where N DAPs are connected to 1 DAC for broadcast
+ * output.
+ *
+ * This driver is dumb; no attempt is made to ensure that a valid routing
+ * configuration is programmed.
+ */
 
-       return 0;
+static inline void tegra20_das_write(struct tegra20_das *das, u32 reg, u32 val)
+{
+       regmap_write(das->regmap, reg, val);
 }
-EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac);
 
-int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master,
-                                  int sdata1rx, int sdata2rx)
+static void tegra20_das_connect_dap_to_dac(struct tegra20_das *das, int dap, int dac)
 {
        u32 addr;
        u32 reg;
 
-       if (!das)
-               return -ENODEV;
-
        addr = TEGRA20_DAS_DAP_CTRL_SEL +
                (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
-       reg = (otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P) |
-               (!!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P) |
-               (!!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P) |
-               (!!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P);
-
-       tegra20_das_write(addr, reg);
+       reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
 
-       return 0;
+       tegra20_das_write(das, addr, reg);
 }
-EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap);
 
-int tegra20_das_connect_dac_to_dap(int dac, int dap)
+static void tegra20_das_connect_dac_to_dap(struct tegra20_das *das, int dac, int dap)
 {
        u32 addr;
        u32 reg;
 
-       if (!das)
-               return -ENODEV;
-
        addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
                (dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
        reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
                dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
                dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
 
-       tegra20_das_write(addr, reg);
-
-       return 0;
+       tegra20_das_write(das, addr, reg);
 }
-EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap);
 
 #define LAST_REG(name) \
        (TEGRA20_DAS_##name + \
@@ -120,73 +155,31 @@ static const struct regmap_config tegra20_das_regmap_config = {
 static int tegra20_das_probe(struct platform_device *pdev)
 {
        void __iomem *regs;
-       int ret = 0;
-
-       if (das)
-               return -ENODEV;
+       struct tegra20_das *das;
 
        das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
-       if (!das) {
-               ret = -ENOMEM;
-               goto err;
-       }
-       das->dev = &pdev->dev;
+       if (!das)
+               return -ENOMEM;
 
        regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(regs)) {
-               ret = PTR_ERR(regs);
-               goto err;
-       }
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
 
        das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
                                            &tegra20_das_regmap_config);
        if (IS_ERR(das->regmap)) {
                dev_err(&pdev->dev, "regmap init failed\n");
-               ret = PTR_ERR(das->regmap);
-               goto err;
-       }
-
-       ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
-                                            TEGRA20_DAS_DAP_SEL_DAC1);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
-               goto err;
-       }
-       ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1,
-                                            TEGRA20_DAS_DAC_SEL_DAP1);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
-               goto err;
-       }
-
-       ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3,
-                                            TEGRA20_DAS_DAP_SEL_DAC3);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
-               goto err;
+               return PTR_ERR(das->regmap);
        }
-       ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_3,
-                                            TEGRA20_DAS_DAC_SEL_DAP3);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
-               goto err;
-       }
-
-       platform_set_drvdata(pdev, das);
-
-       return 0;
-
-err:
-       das = NULL;
-       return ret;
-}
-
-static int tegra20_das_remove(struct platform_device *pdev)
-{
-       if (!das)
-               return -ENODEV;
 
-       das = NULL;
+       tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_1,
+                                      TEGRA20_DAS_DAP_SEL_DAC1);
+       tegra20_das_connect_dac_to_dap(das, TEGRA20_DAS_DAC_ID_1,
+                                      TEGRA20_DAS_DAC_SEL_DAP1);
+       tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_3,
+                                      TEGRA20_DAS_DAP_SEL_DAC3);
+       tegra20_das_connect_dac_to_dap(das, TEGRA20_DAS_DAC_ID_3,
+                                      TEGRA20_DAS_DAC_SEL_DAP3);
 
        return 0;
 }
@@ -198,7 +191,6 @@ static const struct of_device_id tegra20_das_of_match[] = {
 
 static struct platform_driver tegra20_das_driver = {
        .probe = tegra20_das_probe,
-       .remove = tegra20_das_remove,
        .driver = {
                .name = DRV_NAME,
                .of_match_table = tegra20_das_of_match,
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h
deleted file mode 100644 (file)
index 18e832d..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * tegra20_das.h - Definitions for Tegra20 DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010,2012 - NVIDIA, Inc.
- */
-
-#ifndef __TEGRA20_DAS_H__
-#define __TEGRA20_DAS_H__
-
-/* Register TEGRA20_DAS_DAP_CTRL_SEL */
-#define TEGRA20_DAS_DAP_CTRL_SEL                       0x00
-#define TEGRA20_DAS_DAP_CTRL_SEL_COUNT                 5
-#define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE                        4
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P          31
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S          1
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P    30
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S    1
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P    29
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S    1
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P                0
-#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S                5
-
-/* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
-#define TEGRA20_DAS_DAP_SEL_DAC1       0
-#define TEGRA20_DAS_DAP_SEL_DAC2       1
-#define TEGRA20_DAS_DAP_SEL_DAC3       2
-#define TEGRA20_DAS_DAP_SEL_DAP1       16
-#define TEGRA20_DAS_DAP_SEL_DAP2       17
-#define TEGRA20_DAS_DAP_SEL_DAP3       18
-#define TEGRA20_DAS_DAP_SEL_DAP4       19
-#define TEGRA20_DAS_DAP_SEL_DAP5       20
-
-/* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL                     0x40
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT               3
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE              4
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P    28
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S    4
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P    24
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S    4
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P       0
-#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S       4
-
-/*
- * Values for:
- * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
- * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
- * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
- */
-#define TEGRA20_DAS_DAC_SEL_DAP1       0
-#define TEGRA20_DAS_DAC_SEL_DAP2       1
-#define TEGRA20_DAS_DAC_SEL_DAP3       2
-#define TEGRA20_DAS_DAC_SEL_DAP4       3
-#define TEGRA20_DAS_DAC_SEL_DAP5       4
-
-/*
- * Names/IDs of the DACs/DAPs.
- */
-
-#define TEGRA20_DAS_DAP_ID_1 0
-#define TEGRA20_DAS_DAP_ID_2 1
-#define TEGRA20_DAS_DAP_ID_3 2
-#define TEGRA20_DAS_DAP_ID_4 3
-#define TEGRA20_DAS_DAP_ID_5 4
-
-#define TEGRA20_DAS_DAC_ID_1 0
-#define TEGRA20_DAS_DAC_ID_2 1
-#define TEGRA20_DAS_DAC_ID_3 2
-
-struct tegra20_das {
-       struct device *dev;
-       struct regmap *regmap;
-};
-
-/*
- * Terminology:
- * DAS: Digital audio switch (HW module controlled by this driver)
- * DAP: Digital audio port (port/pins on Tegra device)
- * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
- *
- * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
- * DAC, or another DAP. When DAPs are connected, one must be the master and
- * one the slave. Each DAC allows selection of a specific DAP for input, to
- * cater for the case where N DAPs are connected to 1 DAC for broadcast
- * output.
- *
- * This driver is dumb; no attempt is made to ensure that a valid routing
- * configuration is programmed.
- */
-
-/*
- * Connect a DAP to a DAC
- * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
- * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC*
- */
-extern int tegra20_das_connect_dap_to_dac(int dap, int dac);
-
-/*
- * Connect a DAP to another DAP
- * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
- * other_dap_sel: DAP to connect to: TEGRA20_DAS_DAP_SEL_DAP*
- * master: Is this DAP the master (1) or slave (0)
- * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
- * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
- */
-extern int tegra20_das_connect_dap_to_dap(int dap, int otherdap,
-                                         int master, int sdata1rx,
-                                         int sdata2rx);
-
-/*
- * Connect a DAC's input to a DAP
- * (DAC outputs are selected by the DAP)
- * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_*
- * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP*
- */
-extern int tegra20_das_connect_dac_to_dap(int dac, int dap);
-
-#endif
index 27365a877e4717f8d2f2c98b5ba6f69aeedf42e8..fff0cd6588f56722c425b92fe1aeef2d2bc2a50d 100644 (file)
@@ -95,11 +95,11 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
        }
 
        mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                break;
        default:
                return -EINVAL;
@@ -338,7 +338,8 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
 };
 
 static const struct snd_soc_component_driver tegra20_i2s_component = {
-       .name           = DRV_NAME,
+       .name                   = DRV_NAME,
+       .legacy_dai_naming      = 1,
 };
 
 static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
index 64c2f304f2542986f9536cd24a6a2ffa8370f162..ca7b222e07d05e4d1e459eddd0e01b41818f3731 100644 (file)
@@ -264,6 +264,7 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = {
 
 static const struct snd_soc_component_driver tegra20_spdif_component = {
        .name = "tegra20-spdif",
+       .legacy_dai_naming = 1,
 };
 
 static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
index 3785cade2d9a94b21a6e31cfdddd2019f616d351..49691d2cce509fcd56848ff7853e3d46a3ef284d 100644 (file)
@@ -191,7 +191,7 @@ static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol,
        unsigned char *bytes_map = (unsigned char *)&adx->map;
        int value = ucontrol->value.integer.value[0];
        struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;;
+               (struct soc_mixer_control *)kcontrol->private_value;
 
        if (value == bytes_map[mc->reg])
                return 0;
index e1f90daea7a1de3603deed0f29ea90c48ab26572..b38d205b69cc281351d920093bae60c0e6076c1d 100644 (file)
@@ -170,6 +170,11 @@ static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
        DAI(MIXER1 TX3),
        DAI(MIXER1 TX4),
        DAI(MIXER1 TX5),
+       /* XBAR -> OPE -> XBAR */
+       DAI(OPE1 RX),
+       DAI(OPE1 TX),
+       DAI(OPE2 RX),
+       DAI(OPE2 TX),
 };
 
 static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
@@ -294,6 +299,9 @@ static struct snd_soc_dai_driver tegra186_ahub_dais[] = {
        DAI(ASRC1 RX6),
        DAI(ASRC1 TX6),
        DAI(ASRC1 RX7),
+       /* XBAR -> OPE -> XBAR */
+       DAI(OPE1 RX),
+       DAI(OPE1 TX),
 };
 
 static const char * const tegra210_ahub_mux_texts[] = {
@@ -337,6 +345,8 @@ static const char * const tegra210_ahub_mux_texts[] = {
        "MIXER1 TX3",
        "MIXER1 TX4",
        "MIXER1 TX5",
+       "OPE1",
+       "OPE2",
 };
 
 static const char * const tegra186_ahub_mux_texts[] = {
@@ -408,6 +418,7 @@ static const char * const tegra186_ahub_mux_texts[] = {
        "ASRC1 TX4",
        "ASRC1 TX5",
        "ASRC1 TX6",
+       "OPE1",
 };
 
 static const unsigned int tegra210_ahub_mux_values[] = {
@@ -459,6 +470,9 @@ static const unsigned int tegra210_ahub_mux_values[] = {
        MUX_VALUE(1, 2),
        MUX_VALUE(1, 3),
        MUX_VALUE(1, 4),
+       /* OPE */
+       MUX_VALUE(2, 0),
+       MUX_VALUE(2, 1),
 };
 
 static const unsigned int tegra186_ahub_mux_values[] = {
@@ -540,6 +554,8 @@ static const unsigned int tegra186_ahub_mux_values[] = {
        MUX_VALUE(3, 27),
        MUX_VALUE(3, 28),
        MUX_VALUE(3, 29),
+       /* OPE */
+       MUX_VALUE(2, 0),
 };
 
 /* Controls for t210 */
@@ -584,6 +600,8 @@ MUX_ENUM_CTRL_DECL(t210_mixer17_tx, 0x26);
 MUX_ENUM_CTRL_DECL(t210_mixer18_tx, 0x27);
 MUX_ENUM_CTRL_DECL(t210_mixer19_tx, 0x28);
 MUX_ENUM_CTRL_DECL(t210_mixer110_tx, 0x29);
+MUX_ENUM_CTRL_DECL(t210_ope1_tx, 0x40);
+MUX_ENUM_CTRL_DECL(t210_ope2_tx, 0x41);
 
 /* Controls for t186 */
 MUX_ENUM_CTRL_DECL_186(t186_admaif1_tx, 0x00);
@@ -657,6 +675,7 @@ MUX_ENUM_CTRL_DECL_186(t186_asrc14_tx, 0x6f);
 MUX_ENUM_CTRL_DECL_186(t186_asrc15_tx, 0x70);
 MUX_ENUM_CTRL_DECL_186(t186_asrc16_tx, 0x71);
 MUX_ENUM_CTRL_DECL_186(t186_asrc17_tx, 0x72);
+MUX_ENUM_CTRL_DECL_186(t186_ope1_tx, 0x40);
 
 /* Controls for t234 */
 MUX_ENUM_CTRL_DECL_234(t234_mvc1_tx, 0x44);
@@ -758,6 +777,8 @@ static const struct snd_soc_dapm_widget tegra210_ahub_widgets[] = {
        TX_WIDGETS("MIXER1 TX3"),
        TX_WIDGETS("MIXER1 TX4"),
        TX_WIDGETS("MIXER1 TX5"),
+       WIDGETS("OPE1", t210_ope1_tx),
+       WIDGETS("OPE2", t210_ope2_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
@@ -867,6 +888,7 @@ static const struct snd_soc_dapm_widget tegra186_ahub_widgets[] = {
        TX_WIDGETS("ASRC1 TX4"),
        TX_WIDGETS("ASRC1 TX5"),
        TX_WIDGETS("ASRC1 TX6"),
+       WIDGETS("OPE1", t186_ope1_tx),
 };
 
 static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
@@ -976,6 +998,7 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
        TX_WIDGETS("ASRC1 TX4"),
        TX_WIDGETS("ASRC1 TX5"),
        TX_WIDGETS("ASRC1 TX6"),
+       WIDGETS("OPE1", t186_ope1_tx),
 };
 
 #define TEGRA_COMMON_MUX_ROUTES(name)                                  \
@@ -1018,7 +1041,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
        { name " Mux",          "MIXER1 TX2",   "MIXER1 TX2 XBAR-RX" }, \
        { name " Mux",          "MIXER1 TX3",   "MIXER1 TX3 XBAR-RX" }, \
        { name " Mux",          "MIXER1 TX4",   "MIXER1 TX4 XBAR-RX" }, \
-       { name " Mux",          "MIXER1 TX5",   "MIXER1 TX5 XBAR-RX" },
+       { name " Mux",          "MIXER1 TX5",   "MIXER1 TX5 XBAR-RX" }, \
+       { name " Mux",          "OPE1",         "OPE1 XBAR-RX" },
+
+#define TEGRA210_ONLY_MUX_ROUTES(name)                                 \
+       { name " Mux",          "OPE2",         "OPE2 XBAR-RX" },
 
 #define TEGRA186_ONLY_MUX_ROUTES(name)                                 \
        { name " Mux",          "ADMAIF11",     "ADMAIF11 XBAR-RX" },   \
@@ -1050,10 +1077,11 @@ static const struct snd_soc_dapm_widget tegra234_ahub_widgets[] = {
        { name " Mux",          "ASRC1 TX5",    "ASRC1 TX5 XBAR-RX" },  \
        { name " Mux",          "ASRC1 TX6",    "ASRC1 TX6 XBAR-RX" },
 
-#define TEGRA210_MUX_ROUTES(name)                                              \
-       TEGRA_COMMON_MUX_ROUTES(name)
+#define TEGRA210_MUX_ROUTES(name)                                      \
+       TEGRA_COMMON_MUX_ROUTES(name)                                   \
+       TEGRA210_ONLY_MUX_ROUTES(name)
 
-#define TEGRA186_MUX_ROUTES(name)                                              \
+#define TEGRA186_MUX_ROUTES(name)                                      \
        TEGRA_COMMON_MUX_ROUTES(name)                                   \
        TEGRA186_ONLY_MUX_ROUTES(name)
 
@@ -1121,6 +1149,8 @@ static const struct snd_soc_dapm_route tegra210_ahub_routes[] = {
        TEGRA210_MUX_ROUTES("MIXER1 RX8")
        TEGRA210_MUX_ROUTES("MIXER1 RX9")
        TEGRA210_MUX_ROUTES("MIXER1 RX10")
+       TEGRA210_MUX_ROUTES("OPE1")
+       TEGRA210_MUX_ROUTES("OPE2")
 };
 
 static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
@@ -1215,6 +1245,7 @@ static const struct snd_soc_dapm_route tegra186_ahub_routes[] = {
        TEGRA186_MUX_ROUTES("ASRC1 RX5")
        TEGRA186_MUX_ROUTES("ASRC1 RX6")
        TEGRA186_MUX_ROUTES("ASRC1 RX7")
+       TEGRA186_MUX_ROUTES("OPE1")
 };
 
 static const struct snd_soc_component_driver tegra210_ahub_component = {
index 9552bbb939dd1e9343ad989a5bafb036a75db0e0..39ffa4d76b593748be6f9b98114d63ad71be0c49 100644 (file)
@@ -214,11 +214,11 @@ static int tegra210_i2s_set_fmt(struct snd_soc_dai *dai,
        unsigned int mask, val;
 
        mask = I2S_CTRL_MASTER_EN_MASK;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                val = 0;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BP_FP:
                val = I2S_CTRL_MASTER_EN;
                break;
        default:
@@ -803,7 +803,6 @@ static const struct snd_soc_component_driver tegra210_i2s_cmpnt = {
        .num_dapm_routes        = ARRAY_SIZE(tegra210_i2s_routes),
        .controls               = tegra210_i2s_controls,
        .num_controls           = ARRAY_SIZE(tegra210_i2s_controls),
-       .non_legacy_dai_naming  = 1,
 };
 
 static bool tegra210_i2s_wr_reg(struct device *dev, unsigned int reg)
diff --git a/sound/soc/tegra/tegra210_mbdrc.c b/sound/soc/tegra/tegra210_mbdrc.c
new file mode 100644 (file)
index 0000000..d786daa
--- /dev/null
@@ -0,0 +1,1014 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_mbdrc.c - Tegra210 MBDRC driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+
+#define MBDRC_FILTER_REG(reg, id)                                          \
+       ((reg) + ((id) * TEGRA210_MBDRC_FILTER_PARAM_STRIDE))
+
+#define MBDRC_FILTER_REG_DEFAULTS(id)                                      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_IIR_CFG, id), 0x00000005},        \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_ATTACK, id), 0x3e48590c},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_RELEASE, id), 0x08414e9f},     \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_ATTACK, id), 0x7fffffff},    \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_IN_THRESHOLD, id), 0x06145082},   \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_OUT_THRESHOLD, id), 0x060d379b},  \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_1ST, id), 0x0000a000},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_2ND, id), 0x00002000},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_3RD, id), 0x00000b33},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_4TH, id), 0x00000800},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_RATIO_5TH, id), 0x0000019a},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_MAKEUP_GAIN, id), 0x00000002},    \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_INIT_GAIN, id), 0x00066666},      \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_ATTACK, id), 0x00d9ba0e},    \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_GAIN_RELEASE, id), 0x3e48590c},   \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_FAST_RELEASE, id), 0x7ffff26a},   \
+       { MBDRC_FILTER_REG(TEGRA210_MBDRC_CFG_RAM_CTRL, id), 0x4000}
+
+static const struct reg_default tegra210_mbdrc_reg_defaults[] = {
+       { TEGRA210_MBDRC_CFG, 0x0030de51},
+       { TEGRA210_MBDRC_CHANNEL_MASK, 0x00000003},
+       { TEGRA210_MBDRC_FAST_FACTOR, 0x30000800},
+
+       MBDRC_FILTER_REG_DEFAULTS(0),
+       MBDRC_FILTER_REG_DEFAULTS(1),
+       MBDRC_FILTER_REG_DEFAULTS(2),
+};
+
+/* Default MBDRC parameters */
+static const struct tegra210_mbdrc_config mbdrc_init_config = {
+       .mode                   = 0, /* Bypass */
+       .rms_off                = 48,
+       .peak_rms_mode          = 1, /* PEAK */
+       .fliter_structure       = 0, /* All-pass tree */
+       .shift_ctrl             = 30,
+       .frame_size             = 32,
+       .channel_mask           = 0x3,
+       .fa_factor              = 2048,
+       .fr_factor              = 14747,
+
+       .band_params[MBDRC_LOW_BAND] = {
+               .band                   = MBDRC_LOW_BAND,
+               .iir_stages             = 5,
+               .in_attack_tc           = 1044928780,
+               .in_release_tc          = 138497695,
+               .fast_attack_tc         = 2147483647,
+               .in_threshold           = {130, 80, 20, 6},
+               .out_threshold          = {155, 55, 13, 6},
+               .ratio                  = {40960, 8192, 2867, 2048, 410},
+               .makeup_gain            = 4,
+               .gain_init              = 419430,
+               .gain_attack_tc         = 14268942,
+               .gain_release_tc        = 1440547090,
+               .fast_release_tc        = 2147480170,
+
+               .biquad_params  = {
+                       /*
+                        * Gains:
+                        *
+                        * b0, b1, a0,
+                        * a1, a2,
+                        */
+
+                       /* Band-0 */
+                       961046798, -2030431983, 1073741824,
+                       2030431983, -961046798,
+                       /* Band-1 */
+                       1030244425, -2099481453, 1073741824,
+                       2099481453, -1030244425,
+                       /* Band-2 */
+                       1067169294, -2136327263, 1073741824,
+                       2136327263, -1067169294,
+                       /* Band-3 */
+                       434951949, -1306567134, 1073741824,
+                       1306567134, -434951949,
+                       /* Band-4 */
+                       780656019, -1605955641, 1073741824,
+                       1605955641, -780656019,
+                       /* Band-5 */
+                       1024497031, -1817128152, 1073741824,
+                       1817128152, -1024497031,
+                       /* Band-6 */
+                       1073741824, 0, 0,
+                       0, 0,
+                       /* Band-7 */
+                       1073741824, 0, 0,
+                       0, 0,
+               }
+       },
+
+       .band_params[MBDRC_MID_BAND] = {
+               .band                   = MBDRC_MID_BAND,
+               .iir_stages             = 5,
+               .in_attack_tc           = 1581413104,
+               .in_release_tc          = 35494783,
+               .fast_attack_tc         = 2147483647,
+               .in_threshold           = {130, 50, 30, 6},
+               .out_threshold          = {106, 50, 30, 13},
+               .ratio                  = {40960, 2867, 4096, 2867, 410},
+               .makeup_gain            = 6,
+               .gain_init              = 419430,
+               .gain_attack_tc         = 4766887,
+               .gain_release_tc        = 1044928780,
+               .fast_release_tc        = 2147480170,
+
+               .biquad_params = {
+                       /*
+                        * Gains:
+                        *
+                        * b0, b1, a0,
+                        * a1, a2,
+                        */
+
+                       /* Band-0 */
+                       -1005668963, 1073741824, 0,
+                       1005668963, 0,
+                       /* Band-1 */
+                       998437058, -2067742187, 1073741824,
+                       2067742187, -998437058,
+                       /* Band-2 */
+                       1051963422, -2121153948, 1073741824,
+                       2121153948, -1051963422,
+                       /* Band-3 */
+                       434951949, -1306567134, 1073741824,
+                       1306567134, -434951949,
+                       /* Band-4 */
+                       780656019, -1605955641, 1073741824,
+                       1605955641, -780656019,
+                       /* Band-5 */
+                       1024497031, -1817128152, 1073741824,
+                       1817128152, -1024497031,
+                       /* Band-6 */
+                       1073741824, 0, 0,
+                       0, 0,
+                       /* Band-7 */
+                       1073741824, 0, 0,
+                       0, 0,
+               }
+       },
+
+       .band_params[MBDRC_HIGH_BAND] = {
+               .band                   = MBDRC_HIGH_BAND,
+               .iir_stages             = 5,
+               .in_attack_tc           = 2144750688,
+               .in_release_tc          = 70402888,
+               .fast_attack_tc         = 2147483647,
+               .in_threshold           = {130, 50, 30, 6},
+               .out_threshold          = {106, 50, 30, 13},
+               .ratio                  = {40960, 2867, 4096, 2867, 410},
+               .makeup_gain            = 6,
+               .gain_init              = 419430,
+               .gain_attack_tc         = 4766887,
+               .gain_release_tc        = 1044928780,
+               .fast_release_tc        = 2147480170,
+
+               .biquad_params = {
+                       /*
+                        * Gains:
+                        *
+                        * b0, b1, a0,
+                        * a1, a2,
+                        */
+
+                       /* Band-0 */
+                       1073741824, 0, 0,
+                       0, 0,
+                       /* Band-1 */
+                       1073741824, 0, 0,
+                       0, 0,
+                       /* Band-2 */
+                       1073741824, 0, 0,
+                       0, 0,
+                       /* Band-3 */
+                       -619925131, 1073741824, 0,
+                       619925131, 0,
+                       /* Band-4 */
+                       606839335, -1455425976, 1073741824,
+                       1455425976, -606839335,
+                       /* Band-5 */
+                       917759617, -1724690840, 1073741824,
+                       1724690840, -917759617,
+                       /* Band-6 */
+                       1073741824, 0, 0,
+                       0, 0,
+                       /* Band-7 */
+                       1073741824, 0, 0,
+                       0, 0,
+               }
+       }
+};
+
+static void tegra210_mbdrc_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+                                    unsigned int reg_data, unsigned int ram_offset,
+                                    unsigned int *data, size_t size)
+{
+       unsigned int val;
+       unsigned int i;
+
+       val = ram_offset & TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK;
+       val |= TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN;
+       val |= TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN;
+       val |= TEGRA210_MBDRC_RAM_CTRL_RW_WRITE;
+
+       regmap_write(regmap, reg_ctrl, val);
+
+       for (i = 0; i < size; i++)
+               regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_mbdrc_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int val;
+
+       regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+       ucontrol->value.integer.value[0] = (val >> mc->shift) & mc->max;
+
+       return 0;
+}
+
+static int tegra210_mbdrc_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int val = ucontrol->value.integer.value[0];
+       bool change = false;
+
+       val = val << mc->shift;
+
+       regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+                                (mc->max << mc->shift), val, &change);
+
+       return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_get_enum(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned int val;
+
+       regmap_read(ope->mbdrc_regmap, e->reg, &val);
+
+       ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
+
+       return 0;
+}
+
+static int tegra210_mbdrc_put_enum(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       bool change = false;
+       unsigned int val;
+       unsigned int mask;
+
+       if (ucontrol->value.enumerated.item[0] > e->items - 1)
+               return -EINVAL;
+
+       val = ucontrol->value.enumerated.item[0] << e->shift_l;
+       mask = e->mask << e->shift_l;
+
+       regmap_update_bits_check(ope->mbdrc_regmap, e->reg, mask, val,
+                                &change);
+
+       return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_band_params_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 *data = (u32 *)ucontrol->value.bytes.data;
+       u32 regs = params->soc.base;
+       u32 mask = params->soc.mask;
+       u32 shift = params->shift;
+       unsigned int i;
+
+       for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+               regmap_read(ope->mbdrc_regmap, regs, &data[i]);
+
+               data[i] = ((data[i] & mask) >> shift);
+       }
+
+       return 0;
+}
+
+static int tegra210_mbdrc_band_params_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 *data = (u32 *)ucontrol->value.bytes.data;
+       u32 regs = params->soc.base;
+       u32 mask = params->soc.mask;
+       u32 shift = params->shift;
+       bool change = false;
+       unsigned int i;
+
+       for (i = 0; i < params->soc.num_regs; i++, regs += cmpnt->val_bytes) {
+               bool update = false;
+
+               regmap_update_bits_check(ope->mbdrc_regmap, regs, mask,
+                                        data[i] << shift, &update);
+
+               change |= update;
+       }
+
+       return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_threshold_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 *data = (u32 *)ucontrol->value.bytes.data;
+       u32 regs = params->soc.base;
+       u32 num_regs = params->soc.num_regs;
+       u32 val;
+       unsigned int i;
+
+       for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+               regmap_read(ope->mbdrc_regmap, regs, &val);
+
+               data[i] = (val & TEGRA210_MBDRC_THRESH_1ST_MASK) >>
+                         TEGRA210_MBDRC_THRESH_1ST_SHIFT;
+               data[i + 1] = (val & TEGRA210_MBDRC_THRESH_2ND_MASK) >>
+                             TEGRA210_MBDRC_THRESH_2ND_SHIFT;
+               data[i + 2] = (val & TEGRA210_MBDRC_THRESH_3RD_MASK) >>
+                             TEGRA210_MBDRC_THRESH_3RD_SHIFT;
+               data[i + 3] = (val & TEGRA210_MBDRC_THRESH_4TH_MASK) >>
+                             TEGRA210_MBDRC_THRESH_4TH_SHIFT;
+       }
+
+       return 0;
+}
+
+static int tegra210_mbdrc_threshold_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 *data = (u32 *)ucontrol->value.bytes.data;
+       u32 regs = params->soc.base;
+       u32 num_regs = params->soc.num_regs;
+       bool change = false;
+       unsigned int i;
+
+       for (i = 0; i < num_regs; i += 4, regs += cmpnt->val_bytes) {
+               bool update = false;
+
+               data[i] = (((data[i] >> TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+                           TEGRA210_MBDRC_THRESH_1ST_MASK) |
+                          ((data[i + 1] >> TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+                           TEGRA210_MBDRC_THRESH_2ND_MASK) |
+                          ((data[i + 2] >> TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+                           TEGRA210_MBDRC_THRESH_3RD_MASK) |
+                          ((data[i + 3] >> TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+                           TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+               regmap_update_bits_check(ope->mbdrc_regmap, regs, 0xffffffff,
+                                        data[i], &update);
+
+               change |= update;
+       }
+
+       return change ? 1 : 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+       memset(data, 0, params->soc.num_regs * cmpnt->val_bytes);
+
+       return 0;
+}
+
+static int tegra210_mbdrc_biquad_coeffs_put(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 reg_ctrl = params->soc.base;
+       u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+       u32 *data = (u32 *)ucontrol->value.bytes.data;
+
+       tegra210_mbdrc_write_ram(ope->mbdrc_regmap, reg_ctrl, reg_data,
+                                params->shift, data, params->soc.num_regs);
+
+       return 1;
+}
+
+static int tegra210_mbdrc_param_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_bytes *params = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = params->num_regs * sizeof(u32);
+
+       return 0;
+}
+
+static int tegra210_mbdrc_vol_get(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       int val;
+
+       regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+       ucontrol->value.integer.value[0] =
+               ((val >> mc->shift) - TEGRA210_MBDRC_MASTER_VOL_MIN);
+
+       return 0;
+}
+
+static int tegra210_mbdrc_vol_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       int val = ucontrol->value.integer.value[0];
+       bool change = false;
+
+       val += TEGRA210_MBDRC_MASTER_VOL_MIN;
+
+       regmap_update_bits_check(ope->mbdrc_regmap, mc->reg,
+                                mc->max << mc->shift, val << mc->shift,
+                                &change);
+
+       regmap_read(ope->mbdrc_regmap, mc->reg, &val);
+
+       return change ? 1 : 0;
+}
+
+static const char * const tegra210_mbdrc_mode_text[] = {
+       "Bypass", "Fullband", "Dualband", "Multiband"
+};
+
+static const struct soc_enum tegra210_mbdrc_mode_enum =
+       SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT,
+                       4, tegra210_mbdrc_mode_text);
+
+static const char * const tegra210_mbdrc_peak_rms_text[] = {
+       "Peak", "RMS"
+};
+
+static const struct soc_enum tegra210_mbdrc_peak_rms_enum =
+       SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT,
+                       2, tegra210_mbdrc_peak_rms_text);
+
+static const char * const tegra210_mbdrc_filter_structure_text[] = {
+       "All-pass-tree", "Flexible"
+};
+
+static const struct soc_enum tegra210_mbdrc_filter_structure_enum =
+       SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG,
+                       TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT, 2,
+                       tegra210_mbdrc_filter_structure_text);
+
+static const char * const tegra210_mbdrc_frame_size_text[] = {
+       "N1", "N2", "N4", "N8", "N16", "N32", "N64"
+};
+
+static const struct soc_enum tegra210_mbdrc_frame_size_enum =
+       SOC_ENUM_SINGLE(TEGRA210_MBDRC_CFG, TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT,
+                       7, tegra210_mbdrc_frame_size_text);
+
+#define TEGRA_MBDRC_BYTES_EXT(xname, xbase, xregs, xshift, xmask, xinfo)    \
+       TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,             \
+                           tegra210_mbdrc_band_params_get,                 \
+                           tegra210_mbdrc_band_params_put,                 \
+                           tegra210_mbdrc_param_info)
+
+#define TEGRA_MBDRC_BAND_BYTES_EXT(xname, xbase, xshift, xmask, xinfo)     \
+       TEGRA_MBDRC_BYTES_EXT(xname, xbase, TEGRA210_MBDRC_FILTER_COUNT,    \
+                             xshift, xmask, xinfo)
+
+static const DECLARE_TLV_DB_MINMAX(mdbrc_vol_tlv, -25600, 25500);
+
+static const struct snd_kcontrol_new tegra210_mbdrc_controls[] = {
+       SOC_ENUM_EXT("MBDRC Peak RMS Mode", tegra210_mbdrc_peak_rms_enum,
+                    tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+       SOC_ENUM_EXT("MBDRC Filter Structure",
+                    tegra210_mbdrc_filter_structure_enum,
+                    tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+       SOC_ENUM_EXT("MBDRC Frame Size", tegra210_mbdrc_frame_size_enum,
+                    tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+       SOC_ENUM_EXT("MBDRC Mode", tegra210_mbdrc_mode_enum,
+                    tegra210_mbdrc_get_enum, tegra210_mbdrc_put_enum),
+
+       SOC_SINGLE_EXT("MBDRC RMS Offset", TEGRA210_MBDRC_CFG,
+                      TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT, 0x1ff, 0,
+                      tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+       SOC_SINGLE_EXT("MBDRC Shift Control", TEGRA210_MBDRC_CFG,
+                      TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT, 0x1f, 0,
+                      tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+       SOC_SINGLE_EXT("MBDRC Fast Attack Factor", TEGRA210_MBDRC_FAST_FACTOR,
+                      TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT, 0xffff, 0,
+                      tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+       SOC_SINGLE_EXT("MBDRC Fast Release Factor", TEGRA210_MBDRC_FAST_FACTOR,
+                      TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT, 0xffff, 0,
+                      tegra210_mbdrc_get, tegra210_mbdrc_put),
+
+       SOC_SINGLE_RANGE_EXT_TLV("MBDRC Master Volume",
+                                TEGRA210_MBDRC_MASTER_VOL,
+                                TEGRA210_MBDRC_MASTER_VOL_SHIFT,
+                                0, 0x1ff, 0,
+                                tegra210_mbdrc_vol_get, tegra210_mbdrc_vol_put,
+                                mdbrc_vol_tlv),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC IIR Stages", TEGRA210_MBDRC_IIR_CFG,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT,
+                           TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC In Attack Time Const", TEGRA210_MBDRC_IN_ATTACK,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT,
+                           TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC In Release Time Const", TEGRA210_MBDRC_IN_RELEASE,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT,
+                           TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Fast Attack Time Const", TEGRA210_MBDRC_FAST_ATTACK,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT,
+                           TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC In Threshold", TEGRA210_MBDRC_IN_THRESHOLD,
+                           TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+                           tegra210_mbdrc_threshold_get,
+                           tegra210_mbdrc_threshold_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Out Threshold", TEGRA210_MBDRC_OUT_THRESHOLD,
+                           TEGRA210_MBDRC_FILTER_COUNT * 4, 0, 0xffffffff,
+                           tegra210_mbdrc_threshold_get,
+                           tegra210_mbdrc_threshold_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Ratio", TEGRA210_MBDRC_RATIO_1ST,
+                           TEGRA210_MBDRC_FILTER_COUNT * 5,
+                           TEGRA210_MBDRC_RATIO_1ST_SHIFT, TEGRA210_MBDRC_RATIO_1ST_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Makeup Gain", TEGRA210_MBDRC_MAKEUP_GAIN,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT,
+                           TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Init Gain", TEGRA210_MBDRC_INIT_GAIN,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_INIT_GAIN_SHIFT,
+                           TEGRA210_MBDRC_INIT_GAIN_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Attack Gain", TEGRA210_MBDRC_GAIN_ATTACK,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_GAIN_ATTACK_SHIFT,
+                           TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Release Gain", TEGRA210_MBDRC_GAIN_RELEASE,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_GAIN_RELEASE_SHIFT,
+                           TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Fast Release Gain",
+                           TEGRA210_MBDRC_FAST_RELEASE,
+                           TEGRA210_MBDRC_FILTER_COUNT,
+                           TEGRA210_MBDRC_FAST_RELEASE_SHIFT,
+                           TEGRA210_MBDRC_FAST_RELEASE_MASK,
+                           tegra210_mbdrc_band_params_get,
+                           tegra210_mbdrc_band_params_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Low Band Biquad Coeffs",
+                           TEGRA210_MBDRC_CFG_RAM_CTRL,
+                           TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+                           tegra210_mbdrc_biquad_coeffs_get,
+                           tegra210_mbdrc_biquad_coeffs_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC Mid Band Biquad Coeffs",
+                           TEGRA210_MBDRC_CFG_RAM_CTRL +
+                               TEGRA210_MBDRC_FILTER_PARAM_STRIDE,
+                           TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+                           tegra210_mbdrc_biquad_coeffs_get,
+                           tegra210_mbdrc_biquad_coeffs_put,
+                           tegra210_mbdrc_param_info),
+
+       TEGRA_SOC_BYTES_EXT("MBDRC High Band Biquad Coeffs",
+                           TEGRA210_MBDRC_CFG_RAM_CTRL +
+                               (TEGRA210_MBDRC_FILTER_PARAM_STRIDE * 2),
+                           TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5, 0, 0xffffffff,
+                           tegra210_mbdrc_biquad_coeffs_get,
+                           tegra210_mbdrc_biquad_coeffs_put,
+                           tegra210_mbdrc_param_info),
+};
+
+static bool tegra210_mbdrc_wr_reg(struct device *dev, unsigned int reg)
+{
+       if (reg >= TEGRA210_MBDRC_IIR_CFG)
+               reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+                       (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+                        TEGRA210_MBDRC_FILTER_COUNT));
+
+       switch (reg) {
+       case TEGRA210_MBDRC_SOFT_RESET:
+       case TEGRA210_MBDRC_CG:
+       case TEGRA210_MBDRC_CFG ... TEGRA210_MBDRC_CFG_RAM_DATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_mbdrc_rd_reg(struct device *dev, unsigned int reg)
+{
+       if (tegra210_mbdrc_wr_reg(dev, reg))
+               return true;
+
+       if (reg >= TEGRA210_MBDRC_IIR_CFG)
+               reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+                       (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+                        TEGRA210_MBDRC_FILTER_COUNT));
+
+       switch (reg) {
+       case TEGRA210_MBDRC_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_mbdrc_volatile_reg(struct device *dev, unsigned int reg)
+{
+       if (reg >= TEGRA210_MBDRC_IIR_CFG)
+               reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+                       (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+                        TEGRA210_MBDRC_FILTER_COUNT));
+
+       switch (reg) {
+       case TEGRA210_MBDRC_SOFT_RESET:
+       case TEGRA210_MBDRC_STATUS:
+       case TEGRA210_MBDRC_CFG_RAM_CTRL:
+       case TEGRA210_MBDRC_CFG_RAM_DATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_mbdrc_precious_reg(struct device *dev, unsigned int reg)
+{
+       if (reg >= TEGRA210_MBDRC_IIR_CFG)
+               reg -= ((reg - TEGRA210_MBDRC_IIR_CFG) %
+                       (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *
+                        TEGRA210_MBDRC_FILTER_COUNT));
+
+       switch (reg) {
+       case TEGRA210_MBDRC_CFG_RAM_DATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config tegra210_mbdrc_regmap_cfg = {
+       .name                   = "mbdrc",
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = TEGRA210_MBDRC_MAX_REG,
+       .writeable_reg          = tegra210_mbdrc_wr_reg,
+       .readable_reg           = tegra210_mbdrc_rd_reg,
+       .volatile_reg           = tegra210_mbdrc_volatile_reg,
+       .precious_reg           = tegra210_mbdrc_precious_reg,
+       .reg_defaults           = tegra210_mbdrc_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(tegra210_mbdrc_reg_defaults),
+       .cache_type             = REGCACHE_FLAT,
+};
+
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt)
+{
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+       u32 val = 0;
+       unsigned int i;
+
+       regmap_read(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG, &val);
+
+       val &= TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK;
+
+       if (val == TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS)
+               return 0;
+
+       for (i = 0; i < MBDRC_NUM_BAND; i++) {
+               const struct tegra210_mbdrc_band_params *params =
+                       &conf->band_params[i];
+
+               u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+               tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+                                        reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+                                        reg_off + TEGRA210_MBDRC_CFG_RAM_DATA,
+                                        0, (u32 *)&params->biquad_params[0],
+                                        TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+       }
+       return 0;
+}
+
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt)
+{
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       const struct tegra210_mbdrc_config *conf = &mbdrc_init_config;
+       unsigned int i;
+       u32 val;
+
+       pm_runtime_get_sync(cmpnt->dev);
+
+       /* Initialize MBDRC registers and AHUB RAM with default params */
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+               TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK,
+               conf->mode << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+               TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK,
+               conf->rms_off << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+               TEGRA210_MBDRC_CFG_PEAK_RMS_MASK,
+               conf->peak_rms_mode << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+               TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK,
+               conf->fliter_structure <<
+               TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+               TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK,
+               conf->shift_ctrl << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CFG,
+               TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK,
+               __ffs(conf->frame_size) <<
+               TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_CHANNEL_MASK,
+               TEGRA210_MBDRC_CHANNEL_MASK_MASK,
+               conf->channel_mask << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+               TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+               conf->fa_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+       regmap_update_bits(ope->mbdrc_regmap, TEGRA210_MBDRC_FAST_FACTOR,
+               TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK,
+               conf->fr_factor << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT);
+
+       for (i = 0; i < MBDRC_NUM_BAND; i++) {
+               const struct tegra210_mbdrc_band_params *params =
+                                               &conf->band_params[i];
+               u32 reg_off = i * TEGRA210_MBDRC_FILTER_PARAM_STRIDE;
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_IIR_CFG,
+                       TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK,
+                       params->iir_stages <<
+                               TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_IN_ATTACK,
+                       TEGRA210_MBDRC_IN_ATTACK_TC_MASK,
+                       params->in_attack_tc <<
+                               TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_IN_RELEASE,
+                       TEGRA210_MBDRC_IN_RELEASE_TC_MASK,
+                       params->in_release_tc <<
+                               TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_FAST_ATTACK,
+                       TEGRA210_MBDRC_FAST_ATTACK_TC_MASK,
+                       params->fast_attack_tc <<
+                               TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT);
+
+               val = (((params->in_threshold[0] >>
+                        TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+                       TEGRA210_MBDRC_THRESH_1ST_MASK) |
+                       ((params->in_threshold[1] >>
+                         TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+                        TEGRA210_MBDRC_THRESH_2ND_MASK) |
+                       ((params->in_threshold[2] >>
+                         TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+                        TEGRA210_MBDRC_THRESH_3RD_MASK) |
+                       ((params->in_threshold[3] >>
+                         TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+                        TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                                  reg_off + TEGRA210_MBDRC_IN_THRESHOLD,
+                                  0xffffffff, val);
+
+               val = (((params->out_threshold[0] >>
+                        TEGRA210_MBDRC_THRESH_1ST_SHIFT) &
+                       TEGRA210_MBDRC_THRESH_1ST_MASK) |
+                       ((params->out_threshold[1] >>
+                         TEGRA210_MBDRC_THRESH_2ND_SHIFT) &
+                        TEGRA210_MBDRC_THRESH_2ND_MASK) |
+                       ((params->out_threshold[2] >>
+                         TEGRA210_MBDRC_THRESH_3RD_SHIFT) &
+                        TEGRA210_MBDRC_THRESH_3RD_MASK) |
+                       ((params->out_threshold[3] >>
+                         TEGRA210_MBDRC_THRESH_4TH_SHIFT) &
+                        TEGRA210_MBDRC_THRESH_4TH_MASK));
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_OUT_THRESHOLD,
+                       0xffffffff, val);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_RATIO_1ST,
+                       TEGRA210_MBDRC_RATIO_1ST_MASK,
+                       params->ratio[0] << TEGRA210_MBDRC_RATIO_1ST_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_RATIO_2ND,
+                       TEGRA210_MBDRC_RATIO_2ND_MASK,
+                       params->ratio[1] << TEGRA210_MBDRC_RATIO_2ND_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_RATIO_3RD,
+                       TEGRA210_MBDRC_RATIO_3RD_MASK,
+                       params->ratio[2] << TEGRA210_MBDRC_RATIO_3RD_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_RATIO_4TH,
+                       TEGRA210_MBDRC_RATIO_4TH_MASK,
+                       params->ratio[3] << TEGRA210_MBDRC_RATIO_4TH_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_RATIO_5TH,
+                       TEGRA210_MBDRC_RATIO_5TH_MASK,
+                       params->ratio[4] << TEGRA210_MBDRC_RATIO_5TH_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_MAKEUP_GAIN,
+                       TEGRA210_MBDRC_MAKEUP_GAIN_MASK,
+                       params->makeup_gain <<
+                               TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_INIT_GAIN,
+                       TEGRA210_MBDRC_INIT_GAIN_MASK,
+                       params->gain_init <<
+                               TEGRA210_MBDRC_INIT_GAIN_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_GAIN_ATTACK,
+                       TEGRA210_MBDRC_GAIN_ATTACK_MASK,
+                       params->gain_attack_tc <<
+                               TEGRA210_MBDRC_GAIN_ATTACK_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_GAIN_RELEASE,
+                       TEGRA210_MBDRC_GAIN_RELEASE_MASK,
+                       params->gain_release_tc <<
+                               TEGRA210_MBDRC_GAIN_RELEASE_SHIFT);
+
+               regmap_update_bits(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_FAST_RELEASE,
+                       TEGRA210_MBDRC_FAST_RELEASE_MASK,
+                       params->fast_release_tc <<
+                               TEGRA210_MBDRC_FAST_RELEASE_SHIFT);
+
+               tegra210_mbdrc_write_ram(ope->mbdrc_regmap,
+                       reg_off + TEGRA210_MBDRC_CFG_RAM_CTRL,
+                       reg_off + TEGRA210_MBDRC_CFG_RAM_DATA, 0,
+                       (u32 *)&params->biquad_params[0],
+                       TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5);
+       }
+
+       pm_runtime_put_sync(cmpnt->dev);
+
+       snd_soc_add_component_controls(cmpnt, tegra210_mbdrc_controls,
+                                      ARRAY_SIZE(tegra210_mbdrc_controls));
+
+       return 0;
+}
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra210_ope *ope = dev_get_drvdata(dev);
+       struct device_node *child;
+       struct resource mem;
+       void __iomem *regs;
+       int err;
+
+       child = of_get_child_by_name(dev->of_node, "dynamic-range-compressor");
+       if (!child)
+               return -ENODEV;
+
+       err = of_address_to_resource(child, 0, &mem);
+       of_node_put(child);
+       if (err < 0) {
+               dev_err(dev, "fail to get MBDRC resource\n");
+               return err;
+       }
+
+       mem.flags = IORESOURCE_MEM;
+       regs = devm_ioremap_resource(dev, &mem);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       ope->mbdrc_regmap = devm_regmap_init_mmio(dev, regs,
+                                                 &tegra210_mbdrc_regmap_cfg);
+       if (IS_ERR(ope->mbdrc_regmap)) {
+               dev_err(dev, "regmap init failed\n");
+               return PTR_ERR(ope->mbdrc_regmap);
+       }
+
+       regcache_cache_only(ope->mbdrc_regmap, true);
+
+       return 0;
+}
diff --git a/sound/soc/tegra/tegra210_mbdrc.h b/sound/soc/tegra/tegra210_mbdrc.h
new file mode 100644 (file)
index 0000000..4c48da0
--- /dev/null
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_mbdrc.h - Definitions for Tegra210 MBDRC driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_MBDRC_H__
+#define __TEGRA210_MBDRC_H__
+
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+
+/* Register offsets from TEGRA210_MBDRC*_BASE */
+#define TEGRA210_MBDRC_SOFT_RESET                      0x4
+#define TEGRA210_MBDRC_CG                              0x8
+#define TEGRA210_MBDRC_STATUS                          0xc
+#define TEGRA210_MBDRC_CFG                             0x28
+#define TEGRA210_MBDRC_CHANNEL_MASK                    0x2c
+#define TEGRA210_MBDRC_MASTER_VOL                      0x30
+#define TEGRA210_MBDRC_FAST_FACTOR                     0x34
+
+#define TEGRA210_MBDRC_FILTER_COUNT                    3
+#define TEGRA210_MBDRC_FILTER_PARAM_STRIDE             0x4
+
+#define TEGRA210_MBDRC_IIR_CFG                         0x38
+#define TEGRA210_MBDRC_IN_ATTACK                       0x44
+#define TEGRA210_MBDRC_IN_RELEASE                      0x50
+#define TEGRA210_MBDRC_FAST_ATTACK                     0x5c
+#define TEGRA210_MBDRC_IN_THRESHOLD                    0x68
+#define TEGRA210_MBDRC_OUT_THRESHOLD                   0x74
+#define TEGRA210_MBDRC_RATIO_1ST                       0x80
+#define TEGRA210_MBDRC_RATIO_2ND                       0x8c
+#define TEGRA210_MBDRC_RATIO_3RD                       0x98
+#define TEGRA210_MBDRC_RATIO_4TH                       0xa4
+#define TEGRA210_MBDRC_RATIO_5TH                       0xb0
+#define TEGRA210_MBDRC_MAKEUP_GAIN                     0xbc
+#define TEGRA210_MBDRC_INIT_GAIN                       0xc8
+#define TEGRA210_MBDRC_GAIN_ATTACK                     0xd4
+#define TEGRA210_MBDRC_GAIN_RELEASE                    0xe0
+#define TEGRA210_MBDRC_FAST_RELEASE                    0xec
+#define TEGRA210_MBDRC_CFG_RAM_CTRL                    0xf8
+#define TEGRA210_MBDRC_CFG_RAM_DATA                    0x104
+
+#define TEGRA210_MBDRC_MAX_REG                         (TEGRA210_MBDRC_CFG_RAM_DATA +          \
+                                                        (TEGRA210_MBDRC_FILTER_PARAM_STRIDE *  \
+                                                         (TEGRA210_MBDRC_FILTER_COUNT - 1)))
+
+/* Fields for TEGRA210_MBDRC_CFG */
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT            16
+#define TEGRA210_MBDRC_CFG_RMS_OFFSET_MASK             (0x1ff << TEGRA210_MBDRC_CFG_RMS_OFFSET_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT              14
+#define TEGRA210_MBDRC_CFG_PEAK_RMS_MASK               (0x1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+#define TEGRA210_MBDRC_CFG_PEAK                                (1 << TEGRA210_MBDRC_CFG_PEAK_RMS_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT      13
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_MASK       (0x1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+#define TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_FLEX       (1 << TEGRA210_MBDRC_CFG_FILTER_STRUCTURE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT            8
+#define TEGRA210_MBDRC_CFG_SHIFT_CTRL_MASK             (0x1f << TEGRA210_MBDRC_CFG_SHIFT_CTRL_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT            4
+#define TEGRA210_MBDRC_CFG_FRAME_SIZE_MASK             (0xf << TEGRA210_MBDRC_CFG_FRAME_SIZE_SHIFT)
+
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT            0
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_MASK             (0x3 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+#define TEGRA210_MBDRC_CFG_MBDRC_MODE_BYPASS           (0 << TEGRA210_MBDRC_CFG_MBDRC_MODE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_CHANNEL_MASK */
+#define TEGRA210_MBDRC_CHANNEL_MASK_SHIFT              0
+#define TEGRA210_MBDRC_CHANNEL_MASK_MASK               (0xff << TEGRA210_MBDRC_CHANNEL_MASK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MASTER_VOL */
+#define TEGRA210_MBDRC_MASTER_VOL_SHIFT                        23
+#define TEGRA210_MBDRC_MASTER_VOL_MIN                  -256
+#define TEGRA210_MBDRC_MASTER_VOL_MAX                  256
+
+/* Fields for TEGRA210_MBDRC_FAST_FACTOR */
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT       16
+#define TEGRA210_MBDRC_FAST_FACTOR_RELEASE_MASK                (0xffff << TEGRA210_MBDRC_FAST_FACTOR_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT                0
+#define TEGRA210_MBDRC_FAST_FACTOR_ATTACK_MASK         (0xffff << TEGRA210_MBDRC_FAST_FACTOR_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IIR_CFG */
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT                0
+#define TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_MASK         (0xf << TEGRA210_MBDRC_IIR_CFG_NUM_STAGES_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_ATTACK */
+#define TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT              0
+#define TEGRA210_MBDRC_IN_ATTACK_TC_MASK               (0xffffffff << TEGRA210_MBDRC_IN_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_RELEASE */
+#define TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT             0
+#define TEGRA210_MBDRC_IN_RELEASE_TC_MASK              (0xffffffff << TEGRA210_MBDRC_IN_RELEASE_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_ATTACK */
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT            0
+#define TEGRA210_MBDRC_FAST_ATTACK_TC_MASK             (0xffffffff << TEGRA210_MBDRC_FAST_ATTACK_TC_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_IN_THRESHOLD / TEGRA210_MBDRC_OUT_THRESHOLD */
+#define TEGRA210_MBDRC_THRESH_4TH_SHIFT                        24
+#define TEGRA210_MBDRC_THRESH_4TH_MASK                 (0xff << TEGRA210_MBDRC_THRESH_4TH_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_3RD_SHIFT                        16
+#define TEGRA210_MBDRC_THRESH_3RD_MASK                 (0xff << TEGRA210_MBDRC_THRESH_3RD_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_2ND_SHIFT                        8
+#define TEGRA210_MBDRC_THRESH_2ND_MASK                 (0xff << TEGRA210_MBDRC_THRESH_2ND_SHIFT)
+
+#define TEGRA210_MBDRC_THRESH_1ST_SHIFT                        0
+#define TEGRA210_MBDRC_THRESH_1ST_MASK                 (0xff << TEGRA210_MBDRC_THRESH_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_1ST */
+#define TEGRA210_MBDRC_RATIO_1ST_SHIFT                 0
+#define TEGRA210_MBDRC_RATIO_1ST_MASK                  (0xffff << TEGRA210_MBDRC_RATIO_1ST_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_2ND */
+#define TEGRA210_MBDRC_RATIO_2ND_SHIFT                 0
+#define TEGRA210_MBDRC_RATIO_2ND_MASK                  (0xffff << TEGRA210_MBDRC_RATIO_2ND_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_3RD */
+#define TEGRA210_MBDRC_RATIO_3RD_SHIFT                 0
+#define TEGRA210_MBDRC_RATIO_3RD_MASK                  (0xffff << TEGRA210_MBDRC_RATIO_3RD_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_4TH */
+#define TEGRA210_MBDRC_RATIO_4TH_SHIFT                 0
+#define TEGRA210_MBDRC_RATIO_4TH_MASK                  (0xffff << TEGRA210_MBDRC_RATIO_4TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_RATIO_5TH */
+#define TEGRA210_MBDRC_RATIO_5TH_SHIFT                 0
+#define TEGRA210_MBDRC_RATIO_5TH_MASK                  (0xffff << TEGRA210_MBDRC_RATIO_5TH_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_MAKEUP_GAIN */
+#define TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT               0
+#define TEGRA210_MBDRC_MAKEUP_GAIN_MASK                        (0x3f << TEGRA210_MBDRC_MAKEUP_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_INIT_GAIN */
+#define TEGRA210_MBDRC_INIT_GAIN_SHIFT                 0
+#define TEGRA210_MBDRC_INIT_GAIN_MASK                  (0xffffffff << TEGRA210_MBDRC_INIT_GAIN_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_ATTACK */
+#define TEGRA210_MBDRC_GAIN_ATTACK_SHIFT               0
+#define TEGRA210_MBDRC_GAIN_ATTACK_MASK                        (0xffffffff << TEGRA210_MBDRC_GAIN_ATTACK_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_GAIN_RELEASE */
+#define TEGRA210_MBDRC_GAIN_RELEASE_SHIFT              0
+#define TEGRA210_MBDRC_GAIN_RELEASE_MASK               (0xffffffff << TEGRA210_MBDRC_GAIN_RELEASE_SHIFT)
+
+/* Fields for TEGRA210_MBDRC_FAST_RELEASE */
+#define TEGRA210_MBDRC_FAST_RELEASE_SHIFT              0
+#define TEGRA210_MBDRC_FAST_RELEASE_MASK               (0xffffffff << TEGRA210_MBDRC_FAST_RELEASE_SHIFT)
+
+#define TEGRA210_MBDRC_RAM_CTRL_RW_READ                        0
+#define TEGRA210_MBDRC_RAM_CTRL_RW_WRITE               (1 << 14)
+#define TEGRA210_MBDRC_RAM_CTRL_ADDR_INIT_EN           (1 << 13)
+#define TEGRA210_MBDRC_RAM_CTRL_SEQ_ACCESS_EN          (1 << 12)
+#define TEGRA210_MBDRC_RAM_CTRL_RAM_ADDR_MASK          0x1ff
+
+/*
+ * Order and size of each structure element for following structures should not
+ * be altered size order of elements and their size are based on PEQ co-eff ram
+ * and shift ram layout.
+ */
+#define TEGRA210_MBDRC_THRESHOLD_NUM                           4
+#define TEGRA210_MBDRC_RATIO_NUM                               (TEGRA210_MBDRC_THRESHOLD_NUM + 1)
+#define TEGRA210_MBDRC_MAX_BIQUAD_STAGES                       8
+
+/* Order of these enums are same as the order of band specific hw registers */
+enum {
+       MBDRC_LOW_BAND,
+       MBDRC_MID_BAND,
+       MBDRC_HIGH_BAND,
+       MBDRC_NUM_BAND,
+};
+
+struct tegra210_mbdrc_band_params {
+       u32 band;
+       u32 iir_stages;
+       u32 in_attack_tc;
+       u32 in_release_tc;
+       u32 fast_attack_tc;
+       u32 in_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+       u32 out_threshold[TEGRA210_MBDRC_THRESHOLD_NUM];
+       u32 ratio[TEGRA210_MBDRC_RATIO_NUM];
+       u32 makeup_gain;
+       u32 gain_init;
+       u32 gain_attack_tc;
+       u32 gain_release_tc;
+       u32 fast_release_tc;
+       /* For biquad_params[][5] order of coeff is b0, b1, a0, a1, a2 */
+       u32 biquad_params[TEGRA210_MBDRC_MAX_BIQUAD_STAGES * 5];
+};
+
+struct tegra210_mbdrc_config {
+       unsigned int mode;
+       unsigned int rms_off;
+       unsigned int peak_rms_mode;
+       unsigned int fliter_structure;
+       unsigned int shift_ctrl;
+       unsigned int frame_size;
+       unsigned int channel_mask;
+       unsigned int fa_factor; /* Fast attack factor */
+       unsigned int fr_factor; /* Fast release factor */
+       struct tegra210_mbdrc_band_params band_params[MBDRC_NUM_BAND];
+};
+
+int tegra210_mbdrc_regmap_init(struct platform_device *pdev);
+int tegra210_mbdrc_component_init(struct snd_soc_component *cmpnt);
+int tegra210_mbdrc_hw_params(struct snd_soc_component *cmpnt);
+
+#endif
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
new file mode 100644 (file)
index 0000000..3dd2bde
--- /dev/null
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_ope.c - Tegra210 OPE driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_mbdrc.h"
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+#include "tegra_cif.h"
+
+static const struct reg_default tegra210_ope_reg_defaults[] = {
+       { TEGRA210_OPE_RX_INT_MASK, 0x00000001},
+       { TEGRA210_OPE_RX_CIF_CTRL, 0x00007700},
+       { TEGRA210_OPE_TX_INT_MASK, 0x00000001},
+       { TEGRA210_OPE_TX_CIF_CTRL, 0x00007700},
+       { TEGRA210_OPE_CG, 0x1},
+};
+
+static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope,
+                                     struct snd_pcm_hw_params *params,
+                                     unsigned int reg)
+{
+       int channels, audio_bits;
+       struct tegra_cif_conf cif_conf;
+
+       memset(&cif_conf, 0, sizeof(struct tegra_cif_conf));
+
+       channels = params_channels(params);
+       if (channels < 2)
+               return -EINVAL;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               audio_bits = TEGRA_ACIF_BITS_16;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               audio_bits = TEGRA_ACIF_BITS_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       cif_conf.audio_ch = channels;
+       cif_conf.client_ch = channels;
+       cif_conf.audio_bits = audio_bits;
+       cif_conf.client_bits = audio_bits;
+
+       tegra_set_cif(ope->regmap, reg, &cif_conf);
+
+       return 0;
+}
+
+static int tegra210_ope_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct device *dev = dai->dev;
+       struct tegra210_ope *ope = snd_soc_dai_get_drvdata(dai);
+       int err;
+
+       /* Set RX and TX CIF */
+       err = tegra210_ope_set_audio_cif(ope, params,
+                                        TEGRA210_OPE_RX_CIF_CTRL);
+       if (err) {
+               dev_err(dev, "Can't set OPE RX CIF: %d\n", err);
+               return err;
+       }
+
+       err = tegra210_ope_set_audio_cif(ope, params,
+                                        TEGRA210_OPE_TX_CIF_CTRL);
+       if (err) {
+               dev_err(dev, "Can't set OPE TX CIF: %d\n", err);
+               return err;
+       }
+
+       tegra210_mbdrc_hw_params(dai->component);
+
+       return err;
+}
+
+static int tegra210_ope_component_probe(struct snd_soc_component *cmpnt)
+{
+       struct tegra210_ope *ope = dev_get_drvdata(cmpnt->dev);
+
+       tegra210_peq_component_init(cmpnt);
+       tegra210_mbdrc_component_init(cmpnt);
+
+       /*
+        * The OPE, PEQ and MBDRC functionalities are combined under one
+        * device registered by OPE driver. In fact OPE HW block includes
+        * sub blocks PEQ and MBDRC. However driver registers separate
+        * regmap interfaces for each of these. ASoC core depends on
+        * dev_get_regmap() to populate the regmap field for a given ASoC
+        * component. A component can have one regmap reference and since
+        * the DAPM routes depend on OPE regmap only, below explicit
+        * assignment is done to highlight this. This is needed for ASoC
+        * core to access correct regmap during DAPM path setup.
+        */
+       snd_soc_component_init_regmap(cmpnt, ope->regmap);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops tegra210_ope_dai_ops = {
+       .hw_params      = tegra210_ope_hw_params,
+};
+
+static struct snd_soc_dai_driver tegra210_ope_dais[] = {
+       {
+               .name = "OPE-RX-CIF",
+               .playback = {
+                       .stream_name = "RX-CIF-Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
+               },
+               .capture = {
+                       .stream_name = "RX-CIF-Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
+               },
+       },
+       {
+               .name = "OPE-TX-CIF",
+               .playback = {
+                       .stream_name = "TX-CIF-Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
+               },
+               .capture = {
+                       .stream_name = "TX-CIF-Capture",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = SNDRV_PCM_RATE_8000_192000,
+                       .formats = SNDRV_PCM_FMTBIT_S8 |
+                               SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S32_LE,
+               },
+               .ops = &tegra210_ope_dai_ops,
+       }
+};
+
+static const struct snd_soc_dapm_widget tegra210_ope_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("TX", NULL, 0, TEGRA210_OPE_ENABLE,
+                            TEGRA210_OPE_EN_SHIFT, 0),
+};
+
+#define OPE_ROUTES(sname)                                      \
+       { "RX XBAR-" sname,     NULL,   "XBAR-TX" },            \
+       { "RX-CIF-" sname,      NULL,   "RX XBAR-" sname },     \
+       { "RX",                 NULL,   "RX-CIF-" sname },      \
+       { "TX-CIF-" sname,      NULL,   "TX" },                 \
+       { "TX XBAR-" sname,     NULL,   "TX-CIF-" sname },      \
+       { "XBAR-RX",            NULL,   "TX XBAR-" sname }
+
+static const struct snd_soc_dapm_route tegra210_ope_routes[] = {
+       { "TX", NULL, "RX" },
+       OPE_ROUTES("Playback"),
+       OPE_ROUTES("Capture"),
+};
+
+static const char * const tegra210_ope_data_dir_text[] = {
+       "MBDRC to PEQ",
+       "PEQ to MBDRC"
+};
+
+static const struct soc_enum tegra210_ope_data_dir_enum =
+       SOC_ENUM_SINGLE(TEGRA210_OPE_DIR, TEGRA210_OPE_DIR_SHIFT,
+                       2, tegra210_ope_data_dir_text);
+
+static int tegra210_ope_get_data_dir(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+
+       ucontrol->value.enumerated.item[0] = ope->data_dir;
+
+       return 0;
+}
+
+static int tegra210_ope_put_data_dir(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == ope->data_dir)
+               return 0;
+
+       ope->data_dir = value;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new tegra210_ope_controls[] = {
+       SOC_ENUM_EXT("Data Flow Direction", tegra210_ope_data_dir_enum,
+                    tegra210_ope_get_data_dir, tegra210_ope_put_data_dir),
+};
+
+static const struct snd_soc_component_driver tegra210_ope_cmpnt = {
+       .probe                  = tegra210_ope_component_probe,
+       .dapm_widgets           = tegra210_ope_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(tegra210_ope_widgets),
+       .dapm_routes            = tegra210_ope_routes,
+       .num_dapm_routes        = ARRAY_SIZE(tegra210_ope_routes),
+       .controls               = tegra210_ope_controls,
+       .num_controls           = ARRAY_SIZE(tegra210_ope_controls),
+};
+
+static bool tegra210_ope_wr_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA210_OPE_RX_INT_MASK ... TEGRA210_OPE_RX_CIF_CTRL:
+       case TEGRA210_OPE_TX_INT_MASK ... TEGRA210_OPE_TX_CIF_CTRL:
+       case TEGRA210_OPE_ENABLE ... TEGRA210_OPE_CG:
+       case TEGRA210_OPE_DIR:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_ope_rd_reg(struct device *dev, unsigned int reg)
+{
+       if (tegra210_ope_wr_reg(dev, reg))
+               return true;
+
+       switch (reg) {
+       case TEGRA210_OPE_RX_STATUS:
+       case TEGRA210_OPE_RX_INT_STATUS:
+       case TEGRA210_OPE_TX_STATUS:
+       case TEGRA210_OPE_TX_INT_STATUS:
+       case TEGRA210_OPE_STATUS:
+       case TEGRA210_OPE_INT_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_ope_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA210_OPE_RX_STATUS:
+       case TEGRA210_OPE_RX_INT_STATUS:
+       case TEGRA210_OPE_TX_STATUS:
+       case TEGRA210_OPE_TX_INT_STATUS:
+       case TEGRA210_OPE_SOFT_RESET:
+       case TEGRA210_OPE_STATUS:
+       case TEGRA210_OPE_INT_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config tegra210_ope_regmap_config = {
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = TEGRA210_OPE_DIR,
+       .writeable_reg          = tegra210_ope_wr_reg,
+       .readable_reg           = tegra210_ope_rd_reg,
+       .volatile_reg           = tegra210_ope_volatile_reg,
+       .reg_defaults           = tegra210_ope_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(tegra210_ope_reg_defaults),
+       .cache_type             = REGCACHE_FLAT,
+};
+
+static int tegra210_ope_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra210_ope *ope;
+       void __iomem *regs;
+       int err;
+
+       ope = devm_kzalloc(dev, sizeof(*ope), GFP_KERNEL);
+       if (!ope)
+               return -ENOMEM;
+
+       regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       ope->regmap = devm_regmap_init_mmio(dev, regs,
+                                           &tegra210_ope_regmap_config);
+       if (IS_ERR(ope->regmap)) {
+               dev_err(dev, "regmap init failed\n");
+               return PTR_ERR(ope->regmap);
+       }
+
+       regcache_cache_only(ope->regmap, true);
+
+       dev_set_drvdata(dev, ope);
+
+       err = tegra210_peq_regmap_init(pdev);
+       if (err < 0) {
+               dev_err(dev, "PEQ init failed\n");
+               return err;
+       }
+
+       err = tegra210_mbdrc_regmap_init(pdev);
+       if (err < 0) {
+               dev_err(dev, "MBDRC init failed\n");
+               return err;
+       }
+
+       err = devm_snd_soc_register_component(dev, &tegra210_ope_cmpnt,
+                                             tegra210_ope_dais,
+                                             ARRAY_SIZE(tegra210_ope_dais));
+       if (err) {
+               dev_err(dev, "can't register OPE component, err: %d\n", err);
+               return err;
+       }
+
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+
+static int tegra210_ope_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
+{
+       struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+       tegra210_peq_save(ope->peq_regmap, ope->peq_biquad_gains,
+                         ope->peq_biquad_shifts);
+
+       regcache_cache_only(ope->mbdrc_regmap, true);
+       regcache_cache_only(ope->peq_regmap, true);
+       regcache_cache_only(ope->regmap, true);
+
+       regcache_mark_dirty(ope->regmap);
+       regcache_mark_dirty(ope->peq_regmap);
+       regcache_mark_dirty(ope->mbdrc_regmap);
+
+       return 0;
+}
+
+static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
+{
+       struct tegra210_ope *ope = dev_get_drvdata(dev);
+
+       regcache_cache_only(ope->regmap, false);
+       regcache_cache_only(ope->peq_regmap, false);
+       regcache_cache_only(ope->mbdrc_regmap, false);
+
+       regcache_sync(ope->regmap);
+       regcache_sync(ope->peq_regmap);
+       regcache_sync(ope->mbdrc_regmap);
+
+       tegra210_peq_restore(ope->peq_regmap, ope->peq_biquad_gains,
+                            ope->peq_biquad_shifts);
+
+       return 0;
+}
+
+static const struct dev_pm_ops tegra210_ope_pm_ops = {
+       SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
+                          tegra210_ope_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+};
+
+static const struct of_device_id tegra210_ope_of_match[] = {
+       { .compatible = "nvidia,tegra210-ope" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tegra210_ope_of_match);
+
+static struct platform_driver tegra210_ope_driver = {
+       .driver = {
+               .name = "tegra210-ope",
+               .of_match_table = tegra210_ope_of_match,
+               .pm = &tegra210_ope_pm_ops,
+       },
+       .probe = tegra210_ope_probe,
+       .remove = tegra210_ope_remove,
+};
+module_platform_driver(tegra210_ope_driver)
+
+MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>");
+MODULE_DESCRIPTION("Tegra210 OPE ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra210_ope.h b/sound/soc/tegra/tegra210_ope.h
new file mode 100644 (file)
index 0000000..2835af6
--- /dev/null
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_ope.h - Definitions for Tegra210 OPE driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_OPE_H__
+#define __TEGRA210_OPE_H__
+
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "tegra210_peq.h"
+
+/*
+ * OPE_RX registers are with respect to XBAR.
+ * The data comes from XBAR to OPE
+ */
+#define TEGRA210_OPE_RX_STATUS                 0xc
+#define TEGRA210_OPE_RX_INT_STATUS             0x10
+#define TEGRA210_OPE_RX_INT_MASK               0x14
+#define TEGRA210_OPE_RX_INT_SET                        0x18
+#define TEGRA210_OPE_RX_INT_CLEAR              0x1c
+#define TEGRA210_OPE_RX_CIF_CTRL               0x20
+
+/*
+ * OPE_TX registers are with respect to XBAR.
+ * The data goes out from OPE to XBAR
+ */
+#define TEGRA210_OPE_TX_STATUS                 0x4c
+#define TEGRA210_OPE_TX_INT_STATUS             0x50
+#define TEGRA210_OPE_TX_INT_MASK               0x54
+#define TEGRA210_OPE_TX_INT_SET                        0x58
+#define TEGRA210_OPE_TX_INT_CLEAR              0x5c
+#define TEGRA210_OPE_TX_CIF_CTRL               0x60
+
+/* OPE Gloabal registers */
+#define TEGRA210_OPE_ENABLE                    0x80
+#define TEGRA210_OPE_SOFT_RESET                        0x84
+#define TEGRA210_OPE_CG                                0x88
+#define TEGRA210_OPE_STATUS                    0x8c
+#define TEGRA210_OPE_INT_STATUS                        0x90
+#define TEGRA210_OPE_DIR                       0x94
+
+/* Fields for TEGRA210_OPE_ENABLE */
+#define TEGRA210_OPE_EN_SHIFT                  0
+#define TEGRA210_OPE_EN                                (1 << TEGRA210_OPE_EN_SHIFT)
+
+/* Fields for TEGRA210_OPE_SOFT_RESET */
+#define TEGRA210_OPE_SOFT_RESET_SHIFT          0
+#define TEGRA210_OPE_SOFT_RESET_EN             (1 << TEGRA210_OPE_SOFT_RESET_SHIFT)
+
+#define TEGRA210_OPE_DIR_SHIFT                 0
+
+struct tegra210_ope {
+       struct regmap *regmap;
+       struct regmap *peq_regmap;
+       struct regmap *mbdrc_regmap;
+       u32 peq_biquad_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+       u32 peq_biquad_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH];
+       unsigned int data_dir;
+};
+
+/* Extension of soc_bytes structure defined in sound/soc.h */
+struct tegra_soc_bytes {
+       struct soc_bytes soc;
+       u32 shift; /* Used as offset for AHUB RAM related programing */
+};
+
+/* Utility structures for using mixer control of type snd_soc_bytes */
+#define TEGRA_SOC_BYTES_EXT(xname, xbase, xregs, xshift, xmask,                \
+                           xhandler_get, xhandler_put, xinfo)          \
+{                                                                      \
+       .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,                           \
+       .name   = xname,                                                \
+       .info   = xinfo,                                                \
+       .get    = xhandler_get,                                         \
+       .put    = xhandler_put,                                         \
+       .private_value = ((unsigned long)&(struct tegra_soc_bytes)      \
+       {                                                               \
+               .soc.base       = xbase,                                \
+               .soc.num_regs   = xregs,                                \
+               .soc.mask       = xmask,                                \
+               .shift          = xshift                                \
+       })                                                              \
+}
+
+#endif
diff --git a/sound/soc/tegra/tegra210_peq.c b/sound/soc/tegra/tegra210_peq.c
new file mode 100644 (file)
index 0000000..205d956
--- /dev/null
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// tegra210_peq.c - Tegra210 PEQ driver
+//
+// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra210_ope.h"
+#include "tegra210_peq.h"
+
+static const struct reg_default tegra210_peq_reg_defaults[] = {
+       { TEGRA210_PEQ_CFG, 0x00000013},
+       { TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000},
+       { TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000},
+};
+
+static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = {
+       1495012349, /* Pre-gain */
+
+       /* Gains : b0, b1, a0, a1, a2 */
+       536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */
+       134217728, -265414508, 131766272, 2140402222, -1071252997,  /* Band-1 */
+       268435456, -233515765, -33935948, 1839817267, -773826124,   /* Band-2 */
+       536870912, -672537913, 139851540, 1886437554, -824433167,   /* Band-3 */
+       268435456, -114439279, 173723964, 205743566, 278809729,     /* Band-4 */
+       1, 0, 0, 0, 0, /* Band-5 */
+       1, 0, 0, 0, 0, /* Band-6 */
+       1, 0, 0, 0, 0, /* Band-7 */
+       1, 0, 0, 0, 0, /* Band-8 */
+       1, 0, 0, 0, 0, /* Band-9 */
+       1, 0, 0, 0, 0, /* Band-10 */
+       1, 0, 0, 0, 0, /* Band-11 */
+
+       963423114, /* Post-gain */
+};
+
+static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = {
+       23, /* Pre-shift */
+       30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */
+       28, /* Post-shift */
+};
+
+static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];
+
+static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl,
+                                 unsigned int reg_data, unsigned int ram_offset,
+                                 unsigned int *data, size_t size)
+{
+       unsigned int val;
+       unsigned int i;
+
+       val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+       val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+       val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+       val |= TEGRA210_PEQ_RAM_CTRL_RW_READ;
+
+       regmap_write(regmap, reg_ctrl, val);
+
+       /*
+        * Since all ahub non-io modules work under same ahub clock it is not
+        * necessary to check ahub read busy bit after every read.
+        */
+       for (i = 0; i < size; i++)
+               regmap_read(regmap, reg_data, &data[i]);
+}
+
+static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl,
+                                  unsigned int reg_data, unsigned int ram_offset,
+                                  unsigned int *data, size_t size)
+{
+       unsigned int val;
+       unsigned int i;
+
+       val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;
+       val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;
+       val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;
+       val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE;
+
+       regmap_write(regmap, reg_ctrl, val);
+
+       for (i = 0; i < size; i++)
+               regmap_write(regmap, reg_data, data[i]);
+}
+
+static int tegra210_peq_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int mask = (1 << fls(mc->max)) - 1;
+       unsigned int val;
+
+       regmap_read(ope->peq_regmap, mc->reg, &val);
+
+       ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;
+
+       if (!mc->invert)
+               return 0;
+
+       ucontrol->value.integer.value[0] =
+               mc->max - ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static int tegra210_peq_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int mask = (1 << fls(mc->max)) - 1;
+       bool change = false;
+       unsigned int val;
+
+       val = (ucontrol->value.integer.value[0] & mask);
+
+       if (mc->invert)
+               val = mc->max - val;
+
+       val = val << mc->shift;
+
+       regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift),
+                                val, &change);
+
+       return change ? 1 : 0;
+}
+
+static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 i, reg_ctrl = params->soc.base;
+       u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+       s32 *data = (s32 *)biquad_coeff_buffer;
+
+       pm_runtime_get_sync(cmpnt->dev);
+
+       tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data,
+                             params->shift, data, params->soc.num_regs);
+
+       pm_runtime_put_sync(cmpnt->dev);
+
+       for (i = 0; i < params->soc.num_regs; i++)
+               ucontrol->value.integer.value[i] = (long)data[i];
+
+       return 0;
+}
+
+static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct tegra_soc_bytes *params = (void *)kcontrol->private_value;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       u32 i, reg_ctrl = params->soc.base;
+       u32 reg_data = reg_ctrl + cmpnt->val_bytes;
+       s32 *data = (s32 *)biquad_coeff_buffer;
+
+       for (i = 0; i < params->soc.num_regs; i++)
+               data[i] = (s32)ucontrol->value.integer.value[i];
+
+       pm_runtime_get_sync(cmpnt->dev);
+
+       tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data,
+                              params->shift, data, params->soc.num_regs);
+
+       pm_runtime_put_sync(cmpnt->dev);
+
+       return 1;
+}
+
+static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       struct soc_bytes *params = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.min = INT_MIN;
+       uinfo->value.integer.max = INT_MAX;
+       uinfo->count = params->num_regs;
+
+       return 0;
+}
+
+#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan)                              \
+       TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params",   \
+               TEGRA210_PEQ_CFG_RAM_CTRL,                                \
+               TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH,                      \
+               (TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \
+               tegra210_peq_ram_get, tegra210_peq_ram_put,               \
+               tegra210_peq_param_info)
+
+#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan)                             \
+       TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params",  \
+               TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,                          \
+               TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH,                     \
+               (TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f,      \
+               tegra210_peq_ram_get, tegra210_peq_ram_put,               \
+               tegra210_peq_param_info)
+
+static const struct snd_kcontrol_new tegra210_peq_controls[] = {
+       SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG,
+                      TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0,
+                      tegra210_peq_get, tegra210_peq_put),
+
+       SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG,
+                      TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT,
+                      TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0,
+                      tegra210_peq_get, tegra210_peq_put),
+
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(0),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(1),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(2),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(3),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(4),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(5),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(6),
+       TEGRA210_PEQ_GAIN_PARAMS_CTRL(7),
+
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6),
+       TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7),
+};
+
+static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA210_PEQ_SOFT_RESET:
+       case TEGRA210_PEQ_CG:
+       case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg)
+{
+       if (tegra210_peq_wr_reg(dev, reg))
+               return true;
+
+       switch (reg) {
+       case TEGRA210_PEQ_STATUS:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA210_PEQ_SOFT_RESET:
+       case TEGRA210_PEQ_STATUS:
+       case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TEGRA210_PEQ_CFG_RAM_DATA:
+       case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config tegra210_peq_regmap_config = {
+       .name                   = "peq",
+       .reg_bits               = 32,
+       .reg_stride             = 4,
+       .val_bits               = 32,
+       .max_register           = TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+       .writeable_reg          = tegra210_peq_wr_reg,
+       .readable_reg           = tegra210_peq_rd_reg,
+       .volatile_reg           = tegra210_peq_volatile_reg,
+       .precious_reg           = tegra210_peq_precious_reg,
+       .reg_defaults           = tegra210_peq_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(tegra210_peq_reg_defaults),
+       .cache_type             = REGCACHE_FLAT,
+};
+
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+                         u32 *biquad_shifts)
+{
+       unsigned int i;
+
+       for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+               tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL,
+                       TEGRA210_PEQ_CFG_RAM_DATA,
+                       (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+                       biquad_gains,
+                       TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+               tegra210_peq_write_ram(regmap,
+                       TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+                       TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+                       (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+                       biquad_shifts,
+                       TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+       }
+}
+
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+                      u32 *biquad_shifts)
+{
+       unsigned int i;
+
+       for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+               tegra210_peq_read_ram(regmap,
+                       TEGRA210_PEQ_CFG_RAM_CTRL,
+                       TEGRA210_PEQ_CFG_RAM_DATA,
+                       (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+                       biquad_gains,
+                       TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+               tegra210_peq_read_ram(regmap,
+                       TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+                       TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+                       (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+                       biquad_shifts,
+                       TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+       }
+}
+
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt)
+{
+       struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int i;
+
+       pm_runtime_get_sync(cmpnt->dev);
+       regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+               TEGRA210_PEQ_CFG_MODE_MASK,
+               0 << TEGRA210_PEQ_CFG_MODE_SHIFT);
+       regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,
+               TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK,
+               (TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) <<
+               TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT);
+
+       /* Initialize PEQ AHUB RAM with default params */
+       for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {
+
+               /* Set default gain params */
+               tegra210_peq_write_ram(ope->peq_regmap,
+                       TEGRA210_PEQ_CFG_RAM_CTRL,
+                       TEGRA210_PEQ_CFG_RAM_DATA,
+                       (i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),
+                       (u32 *)&biquad_init_gains,
+                       TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);
+
+               /* Set default shift params */
+               tegra210_peq_write_ram(ope->peq_regmap,
+                       TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,
+                       TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,
+                       (i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),
+                       (u32 *)&biquad_init_shifts,
+                       TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);
+
+       }
+
+       pm_runtime_put_sync(cmpnt->dev);
+
+       snd_soc_add_component_controls(cmpnt, tegra210_peq_controls,
+                                      ARRAY_SIZE(tegra210_peq_controls));
+
+       return 0;
+}
+
+int tegra210_peq_regmap_init(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct tegra210_ope *ope = dev_get_drvdata(dev);
+       struct device_node *child;
+       struct resource mem;
+       void __iomem *regs;
+       int err;
+
+       child = of_get_child_by_name(dev->of_node, "equalizer");
+       if (!child)
+               return -ENODEV;
+
+       err = of_address_to_resource(child, 0, &mem);
+       of_node_put(child);
+       if (err < 0) {
+               dev_err(dev, "fail to get PEQ resource\n");
+               return err;
+       }
+
+       mem.flags = IORESOURCE_MEM;
+       regs = devm_ioremap_resource(dev, &mem);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+       ope->peq_regmap = devm_regmap_init_mmio(dev, regs,
+                                               &tegra210_peq_regmap_config);
+       if (IS_ERR(ope->peq_regmap)) {
+               dev_err(dev, "regmap init failed\n");
+               return PTR_ERR(ope->peq_regmap);
+       }
+
+       regcache_cache_only(ope->peq_regmap, true);
+
+       return 0;
+}
diff --git a/sound/soc/tegra/tegra210_peq.h b/sound/soc/tegra/tegra210_peq.h
new file mode 100644 (file)
index 0000000..6d3de4f
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tegra210_peq.h - Definitions for Tegra210 PEQ driver
+ *
+ * Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
+ *
+ */
+
+#ifndef __TEGRA210_PEQ_H__
+#define __TEGRA210_PEQ_H__
+
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+/* Register offsets from PEQ base */
+#define TEGRA210_PEQ_SOFT_RESET                                0x0
+#define TEGRA210_PEQ_CG                                        0x4
+#define TEGRA210_PEQ_STATUS                            0x8
+#define TEGRA210_PEQ_CFG                               0xc
+#define TEGRA210_PEQ_CFG_RAM_CTRL                      0x10
+#define TEGRA210_PEQ_CFG_RAM_DATA                      0x14
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL                        0x18
+#define TEGRA210_PEQ_CFG_RAM_SHIFT_DATA                        0x1c
+
+/* Fields in TEGRA210_PEQ_CFG */
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT           2
+#define TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK            (0xf << TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT)
+
+#define TEGRA210_PEQ_CFG_MODE_SHIFT                    0
+#define TEGRA210_PEQ_CFG_MODE_MASK                     (0x1 << TEGRA210_PEQ_CFG_MODE_SHIFT)
+
+#define TEGRA210_PEQ_RAM_CTRL_RW_READ                  0
+#define TEGRA210_PEQ_RAM_CTRL_RW_WRITE                 (1 << 14)
+#define TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN             (1 << 13)
+#define TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN            (1 << 12)
+#define TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK            0x1ff
+
+/* PEQ register definition ends here */
+#define TEGRA210_PEQ_MAX_BIQUAD_STAGES                 12
+
+#define TEGRA210_PEQ_MAX_CHANNELS                      8
+
+#define TEGRA210_PEQ_BIQUAD_INIT_STAGE                 5
+
+#define TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES * 5)
+#define TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH (2 + TEGRA210_PEQ_MAX_BIQUAD_STAGES)
+
+int tegra210_peq_regmap_init(struct platform_device *pdev);
+int tegra210_peq_component_init(struct snd_soc_component *cmpnt);
+void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,
+                         u32 *biquad_shifts);
+void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,
+                      u32 *biquad_shifts);
+
+#endif
index 084a533bf4f2cc4223a20d25d98949b8889c1239..10cd37096fb33471d172f59f2246bfb6a3515a9b 100644 (file)
@@ -87,11 +87,11 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
        }
 
        mask |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                val |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                break;
        default:
                return -EINVAL;
@@ -331,7 +331,8 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
 };
 
 static const struct snd_soc_component_driver tegra30_i2s_component = {
-       .name           = DRV_NAME,
+       .name                   = DRV_NAME,
+       .legacy_dai_naming      = 1,
 };
 
 static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
index 0363a088d2e00058d9f96bb62e4aad7b57742f5f..e6e77a5f3c1e7d3177cd4bd0a6375d0f2d84ca9c 100644 (file)
@@ -230,15 +230,15 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
        dev->fmt = fmt;
        /* set master/slave audio interface */
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* cpu is master */
                pcr = DAVINCI_MCBSP_PCR_FSXM |
                        DAVINCI_MCBSP_PCR_FSRM |
                        DAVINCI_MCBSP_PCR_CLKXM |
                        DAVINCI_MCBSP_PCR_CLKRM;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
                /*
                 * Selection of the clock input pin that is the
@@ -260,7 +260,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                }
 
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* codec is master */
                pcr = 0;
                break;
@@ -395,12 +395,12 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
        }
 
-       master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+       master = dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
        fmt = params_format(params);
        mcbsp_word_length = asp_word_length[fmt];
 
        switch (master) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                freq = clk_get_rate(dev->clk);
                srgr = DAVINCI_MCBSP_SRGR_FSGM |
                       DAVINCI_MCBSP_SRGR_CLKSM;
@@ -426,7 +426,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                clk_div &= 0xFF;
                srgr |= clk_div;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                srgr = DAVINCI_MCBSP_SRGR_FSGM;
                clk_div = dev->clk_div - 1;
                srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
@@ -434,7 +434,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                clk_div &= 0xFF;
                srgr |= clk_div;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* Clock and frame sync given from external sources */
                i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
                srgr = DAVINCI_MCBSP_SRGR_FSGM;
@@ -473,15 +473,15 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                        fmt = double_fmt[fmt];
                }
                switch (master) {
-               case SND_SOC_DAIFMT_CBS_CFS:
-               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_BP_FP:
+               case SND_SOC_DAIFMT_BP_FC:
                        rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
                        xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
                        rcr |= DAVINCI_MCBSP_RCR_RPHASE;
                        xcr |= DAVINCI_MCBSP_XCR_XPHASE;
                        break;
-               case SND_SOC_DAIFMT_CBM_CFM:
-               case SND_SOC_DAIFMT_CBM_CFS:
+               case SND_SOC_DAIFMT_BC_FC:
+               case SND_SOC_DAIFMT_BC_FP:
                        rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
                        xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
                        break;
@@ -492,13 +492,13 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
        mcbsp_word_length = asp_word_length[fmt];
 
        switch (master) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_BP_FC:
                rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
                xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_BC_FP:
                rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
                xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
                break;
@@ -640,7 +640,8 @@ static struct snd_soc_dai_driver davinci_i2s_dai = {
 };
 
 static const struct snd_soc_component_driver davinci_i2s_component = {
-       .name           = DRV_NAME,
+       .name                   = DRV_NAME,
+       .legacy_dai_naming      = 1,
 };
 
 static int davinci_i2s_probe(struct platform_device *pdev)
index 377be2e2b6ee7d10b9bf7f3f67c3644b80c14d37..ca5d1bb6ac59e1768bc458a7ce5952b9bbb22d3b 100644 (file)
@@ -492,8 +492,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(data_delay),
                       FSRDLY(3));
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* codec is clock and frame slave */
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -510,7 +510,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp->bclk_master = 1;
                break;
-       case SND_SOC_DAIFMT_CBS_CFM:
+       case SND_SOC_DAIFMT_BP_FC:
                /* codec is clock slave and frame master */
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -527,7 +527,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp->bclk_master = 1;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                /* codec is clock master and frame slave */
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -544,7 +544,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
                mcasp->bclk_master = 0;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* codec is clock and frame master */
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
@@ -1765,7 +1765,8 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 };
 
 static const struct snd_soc_component_driver davinci_mcasp_component = {
-       .name           = "davinci-mcasp",
+       .name                   = "davinci-mcasp",
+       .legacy_dai_naming      = 1,
 };
 
 /* Some HW specific values and defaults. The rest is filled in from DT. */
@@ -2111,8 +2112,7 @@ static int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset)
        }
 
        /* Do not change the PIN yet */
-
-       return pm_runtime_get_sync(mcasp->dev);
+       return pm_runtime_resume_and_get(mcasp->dev);
 }
 
 static void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset)
index f810123cc40703d09afa439911976ff32727f30d..36fa97e2b9e225d2b3b0dcf9016f4872f96dc46c 100644 (file)
@@ -185,7 +185,8 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 };
 
 static const struct snd_soc_component_driver davinci_vcif_component = {
-       .name           = "davinci-vcif",
+       .name                   = "davinci-vcif",
+       .legacy_dai_naming      = 1,
 };
 
 static int davinci_vcif_probe(struct platform_device *pdev)
index f3eed20611a3fa558f90220db089295d9782762b..825c70a443dad1c2b4ff9ff2e76282bfb68c38e8 100644 (file)
@@ -453,7 +453,8 @@ static struct snd_soc_dai_driver omap_dmic_dai = {
 };
 
 static const struct snd_soc_component_driver omap_dmic_component = {
-       .name           = "omap-dmic",
+       .name                   = "omap-dmic",
+       .legacy_dai_naming      = 1,
 };
 
 static int asoc_dmic_probe(struct platform_device *pdev)
index 3328c02f93c7443094baabd97e156b2dbdf00f04..0dc0475670ffecc9b22be3996f0dfefb2ef59792 100644 (file)
@@ -275,6 +275,7 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
 
 static const struct snd_soc_component_driver omap_hdmi_component = {
        .name = "omapdss_hdmi",
+       .legacy_dai_naming = 1,
 };
 
 static struct snd_soc_dai_driver omap5_hdmi_dai = {
index 9933b33c80caac53729f5b0e9a3caed6d8225df4..c4ac1f30b9fe45519fc38026ac5bada4cc0efc53 100644 (file)
@@ -1026,8 +1026,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 
        /* In McBSP master modes, FRAME (i.e. sample rate) is generated
         * by _counting_ BCLKs. Calculate frame size in BCLKs */
-       master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
-       if (master ==   SND_SOC_DAIFMT_CBS_CFS) {
+       master = mcbsp->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
+       if (master == SND_SOC_DAIFMT_BP_FP) {
                div = mcbsp->clk_div ? mcbsp->clk_div : 1;
                framesize = (mcbsp->in_freq / div) / params_rate(params);
 
@@ -1126,20 +1126,20 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BP_FP:
                /* McBSP master. Set FS and bit clocks as outputs */
                regs->pcr0      |= FSXM | FSRM |
                                   CLKXM | CLKRM;
                /* Sample rate generator drives the FS */
                regs->srgr2     |= FSGM;
                break;
-       case SND_SOC_DAIFMT_CBM_CFS:
+       case SND_SOC_DAIFMT_BC_FP:
                /* McBSP slave. FS clock as output */
                regs->srgr2     |= FSGM;
                regs->pcr0      |= FSXM | FSRM;
                break;
-       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_BC_FC:
                /* McBSP slave */
                break;
        default:
@@ -1307,7 +1307,8 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = {
 };
 
 static const struct snd_soc_component_driver omap_mcbsp_component = {
-       .name           = "omap-mcbsp",
+       .name                   = "omap-mcbsp",
+       .legacy_dai_naming      = 1,
 };
 
 static struct omap_mcbsp_platform_data omap2420_pdata = {
index fafb2998ad0df27f00d5fc4ac9d1ec07107e3a40..0b18a7bfd3fd73f5cd9179d7b35fc658dd76f8c1 100644 (file)
@@ -524,9 +524,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
 };
 
 static const struct snd_soc_component_driver omap_mcpdm_component = {
-       .name           = "omap-mcpdm",
-       .suspend        = omap_mcpdm_suspend,
-       .resume         = omap_mcpdm_resume,
+       .name                   = "omap-mcpdm",
+       .suspend                = omap_mcpdm_suspend,
+       .resume                 = omap_mcpdm_resume,
+       .legacy_dai_naming      = 1,
 };
 
 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
index 96343d19a1e0f1d9eab9983edc31838c9a56c67d..42403ae8e31b2a81e569a76b01d0da0e4da38dd2 100644 (file)
@@ -397,7 +397,6 @@ static struct snd_soc_component_driver soc_codec_evea = {
        .idle_bias_on           = 1,
        .use_pmdown_time        = 1,
        .endianness             = 1,
-       .non_legacy_dai_naming  = 1,
 };
 
 static struct snd_soc_dai_driver soc_dai_evea[] = {
index 4f41bb0ab2b00a76454c18c3c3841d00a5263149..fdd55d772b8e2d3828da37806e0b953cc040bbc6 100644 (file)
@@ -4,8 +4,6 @@
  *
  * Author: Ola Lilja (ola.o.lilja@stericsson.com)
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #include <asm/mach-types.h>
index 1ea1729984a9af14d350e0f75fbb836457c408de..e5e73a2bd9fe4bc78037315f18636c9acf528f5c 100644 (file)
@@ -5,8 +5,6 @@
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  *         Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #include <linux/module.h>
index 087ef246d87daf8b5526bd48930cf3daa68654f5..98de80a9cc4fefa585097ca7bd3fbe65b8dce957 100644 (file)
@@ -4,8 +4,6 @@
  *
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #ifndef MOP500_AB8500_H
index 21052378a32eb305a750dc3b99410f7b24bd310e..9d99ea6d7f30ec823fd71d93a741d1a0af32c85a 100644 (file)
@@ -5,8 +5,6 @@
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #include <linux/module.h>
@@ -191,8 +189,8 @@ static int setup_clocking(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+       case SND_SOC_DAIFMT_BC_FC:
                dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
 
                msp_config->iodelay = 0x20;
@@ -204,7 +202,7 @@ static int setup_clocking(struct snd_soc_dai *dai,
 
                break;
 
-       case SND_SOC_DAIFMT_CBS_CFS:
+       case SND_SOC_DAIFMT_BP_FP:
                dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
 
                msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
@@ -328,15 +326,15 @@ static int setup_msp_config(struct snd_pcm_substream *substream,
        dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,
                runtime->rate, runtime->channels);
        switch (fmt &
-               (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+               (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) {
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP:
                dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
 
                msp_config->default_protdesc = 1;
                msp_config->protocol = MSP_I2S_PROTOCOL;
                break;
 
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC:
                dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
 
                msp_config->data_size = MSP_DATA_BITS_16;
@@ -348,10 +346,10 @@ static int setup_msp_config(struct snd_pcm_substream *substream,
 
                break;
 
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC:
                dev_dbg(dai->dev, "%s: PCM format.\n", __func__);
 
                msp_config->data_size = MSP_DATA_BITS_16;
@@ -477,7 +475,7 @@ static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
        }
 
        /* Set OPP-level */
-       if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) &&
+       if ((drvdata->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) &&
                (drvdata->msp->f_bitclk > 19200000)) {
                /* If the bit-clock is higher than 19.2MHz, Vape should be
                 * run in 100% OPP. Only when bit-clock is used (MSP master)
@@ -544,13 +542,13 @@ static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
        dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);
 
        switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
-               SND_SOC_DAIFMT_MASTER_MASK)) {
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+               SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK)) {
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_BC_FC:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BP_FP:
+       case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_BC_FC:
                break;
 
        default:
@@ -731,7 +729,8 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv = {
 };
 
 static const struct snd_soc_component_driver ux500_msp_component = {
-       .name           = "ux500-msp",
+       .name                   = "ux500-msp",
+       .legacy_dai_naming      = 1,
 };
 
 
index fcd4b26f5d2de44793b4ffebf5afbd2d959b416e..30bf708381961548f5637f2abb7f58c729c142fe 100644 (file)
@@ -5,8 +5,6 @@
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #ifndef UX500_msp_dai_H
index fd0b88bb7921266097dc450bcfe6e44ac6bee549..d113411a19f822fb89e05a4673f211819153bf20 100644 (file)
@@ -6,8 +6,6 @@
  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
  *         Sandeep Kaushik <sandeep.kaushik@st.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #include <linux/module.h>
index 756b3973af9af64a5dc21fb62ffa9f674c941a65..d45b5e2831cc030ab995d847f28557174d7cc8d9 100644 (file)
@@ -4,8 +4,6 @@
  *
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 
index 18191084b8b8474cb4339f17968123bfec88654f..d3802e5ef196e0e66fe3bc7c15fd39a549f10369 100644 (file)
@@ -5,8 +5,6 @@
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 
 #include <asm/page.h>
index ff3ef7223db699816da403c44a674e6bf968956b..bd4348ebf9a133016dad28c571a61cc31910fe63 100644 (file)
@@ -5,8 +5,6 @@
  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
  *         for ST-Ericsson.
- *
- * License terms:
  */
 #ifndef UX500_PCM_H
 #define UX500_PCM_H
index 5c4158069a5a893ebf7cfec6d7a6249c353c68df..ff1fe62fea7028eed06a96d22855bbce311917b1 100644 (file)
@@ -575,14 +575,14 @@ static int xlnx_formatter_pcm_new(struct snd_soc_component *component,
 }
 
 static const struct snd_soc_component_driver xlnx_asoc_component = {
-       .name           = DRV_NAME,
-       .set_sysclk     = xlnx_formatter_set_sysclk,
-       .open           = xlnx_formatter_pcm_open,
-       .close          = xlnx_formatter_pcm_close,
-       .hw_params      = xlnx_formatter_pcm_hw_params,
-       .trigger        = xlnx_formatter_pcm_trigger,
-       .pointer        = xlnx_formatter_pcm_pointer,
-       .pcm_construct  = xlnx_formatter_pcm_new,
+       .name                   = DRV_NAME,
+       .set_sysclk             = xlnx_formatter_set_sysclk,
+       .open                   = xlnx_formatter_pcm_open,
+       .close                  = xlnx_formatter_pcm_close,
+       .hw_params              = xlnx_formatter_pcm_hw_params,
+       .trigger                = xlnx_formatter_pcm_trigger,
+       .pointer                = xlnx_formatter_pcm_pointer,
+       .pcm_construct          = xlnx_formatter_pcm_new,
 };
 
 static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
@@ -703,7 +703,7 @@ static int xlnx_formatter_pcm_remove(struct platform_device *pdev)
                dev_err(&pdev->dev, "audio formatter reset failed\n");
 
        clk_disable_unprepare(adata->axi_clk);
-       return ret;
+       return 0;
 }
 
 static const struct of_device_id xlnx_formatter_pcm_of_match[] = {
index 4cc6ee7c81a321dd91c9ddd3af29eef77e57046f..9de92d35e30ee352dc6f3ecd703fd24749ab7414 100644 (file)
@@ -158,6 +158,7 @@ static const struct snd_soc_dai_ops xlnx_i2s_dai_ops = {
 
 static const struct snd_soc_component_driver xlnx_i2s_component = {
        .name = DRV_NAME,
+       .legacy_dai_naming = 1,
 };
 
 static const struct of_device_id xlnx_i2s_of_match[] = {
index cba0e868a7d77e35e8c80fe47bb8dea45bc9630d..7342048e98751c174982c32d55e3ec6f2fc64268 100644 (file)
@@ -226,6 +226,7 @@ static struct snd_soc_dai_driver xlnx_spdif_rx_dai = {
 
 static const struct snd_soc_component_driver xlnx_spdif_component = {
        .name = "xlnx-spdif",
+       .legacy_dai_naming = 1,
 };
 
 static const struct of_device_id xlnx_spdif_of_match[] = {
index aeb4b2c4d1d35df4057b08058d4d6cd13ece5295..a8f156540b50078d530d457ca4ba81d8df9bad14 100644 (file)
@@ -339,7 +339,7 @@ static int xtfpga_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 {
        if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
                return -EINVAL;
-       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+       if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP)
                return -EINVAL;
        if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
                return -EINVAL;
@@ -475,19 +475,20 @@ static int xtfpga_pcm_new(struct snd_soc_component *component,
 }
 
 static const struct snd_soc_component_driver xtfpga_i2s_component = {
-       .name           = DRV_NAME,
-       .open           = xtfpga_pcm_open,
-       .close          = xtfpga_pcm_close,
-       .hw_params      = xtfpga_pcm_hw_params,
-       .trigger        = xtfpga_pcm_trigger,
-       .pointer        = xtfpga_pcm_pointer,
-       .pcm_construct  = xtfpga_pcm_new,
+       .name                   = DRV_NAME,
+       .open                   = xtfpga_pcm_open,
+       .close                  = xtfpga_pcm_close,
+       .hw_params              = xtfpga_pcm_hw_params,
+       .trigger                = xtfpga_pcm_trigger,
+       .pointer                = xtfpga_pcm_pointer,
+       .pcm_construct          = xtfpga_pcm_new,
+       .legacy_dai_naming      = 1,
 };
 
 static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = {
        .startup        = xtfpga_i2s_startup,
        .hw_params      = xtfpga_i2s_hw_params,
-       .set_fmt        = xtfpga_i2s_set_fmt,
+       .set_fmt        = xtfpga_i2s_set_fmt,
 };
 
 static struct snd_soc_dai_driver xtfpga_i2s_dai[] = {
index 7168f1c6a37aa262c774015a67f4c9cd5fbdf27b..32c39d8bd2e5532aa46a28cb02a71d97bf33b05c 100644 (file)
@@ -175,7 +175,7 @@ static int usb6fire_pcm_stream_start(struct pcm_runtime *rt)
                        }
                }
 
-               /* wait for first out urb to return (sent in in urb handler) */
+               /* wait for first out urb to return (sent in urb handler) */
                wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
                                HZ);
                if (rt->stream_wait_cond)
index cd4a0bc6d278fd4d82d6895bc622fcfeff2ae12a..7aec0a95c609a951252105e60b5aa1622e1c39ac 100644 (file)
@@ -348,7 +348,8 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k)
 static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k,
                                                struct usb_interface *interface)
 {
-       /* usb_kill_urb not necessary, urb is aborted automatically */
+       usb_kill_urb(bcd2k->midi_out_urb);
+       usb_kill_urb(bcd2k->midi_in_urb);
 
        usb_free_urb(bcd2k->midi_out_urb);
        usb_free_urb(bcd2k->midi_in_urb);
index f9c921683948d1b8e45db3a1773161960495826f..0d7b73bf7945063cda7bd50d81c65327dde5ef2a 100644 (file)
@@ -133,7 +133,7 @@ static inline bool ep_state_running(struct snd_usb_endpoint *ep)
 
 static inline bool ep_state_update(struct snd_usb_endpoint *ep, int old, int new)
 {
-       return atomic_cmpxchg(&ep->state, old, new) == old;
+       return atomic_try_cmpxchg(&ep->state, &old, new);
 }
 
 /**
index 71f17f02f34188586f7475e7c71c44af20d6ef32..cf650fab54d7e25f480923a5a0a3fbf88bf772d6 100644 (file)
@@ -225,7 +225,7 @@ static int hiface_pcm_stream_start(struct pcm_runtime *rt)
                        }
                }
 
-               /* wait for first out urb to return (sent in in urb handler) */
+               /* wait for first out urb to return (sent in urb handler) */
                wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
                                   HZ);
                if (rt->stream_wait_cond) {
index 16e644330c4d63c9a0ff40548bac7e975b82a59f..cd41aa7f038513c4d90f788b50d78bc34320e91e 100644 (file)
@@ -235,7 +235,7 @@ static ssize_t serial_number_show(struct device *dev,
        struct snd_card *card = dev_to_snd_card(dev);
        struct usb_line6_pod *pod = card->private_data;
 
-       return sprintf(buf, "%u\n", pod->serial_number);
+       return sysfs_emit(buf, "%u\n", pod->serial_number);
 }
 
 /*
@@ -247,8 +247,8 @@ static ssize_t firmware_version_show(struct device *dev,
        struct snd_card *card = dev_to_snd_card(dev);
        struct usb_line6_pod *pod = card->private_data;
 
-       return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
-                      pod->firmware_version % 100);
+       return sysfs_emit(buf, "%d.%02d\n", pod->firmware_version / 100,
+                         pod->firmware_version % 100);
 }
 
 /*
@@ -260,7 +260,7 @@ static ssize_t device_id_show(struct device *dev,
        struct snd_card *card = dev_to_snd_card(dev);
        struct usb_line6_pod *pod = card->private_data;
 
-       return sprintf(buf, "%d\n", pod->device_id);
+       return sysfs_emit(buf, "%d\n", pod->device_id);
 }
 
 /*
index b24bc82f89e37c3911353fb8ce112f59953c613b..ffd8c157a28139ed376b9b22626678f37ea4660e 100644 (file)
@@ -146,7 +146,7 @@ static ssize_t serial_number_show(struct device *dev,
        struct snd_card *card = dev_to_snd_card(dev);
        struct usb_line6_podhd *pod = card->private_data;
 
-       return sprintf(buf, "%u\n", pod->serial_number);
+       return sysfs_emit(buf, "%u\n", pod->serial_number);
 }
 
 static ssize_t firmware_version_show(struct device *dev,
@@ -155,7 +155,7 @@ static ssize_t firmware_version_show(struct device *dev,
        struct snd_card *card = dev_to_snd_card(dev);
        struct usb_line6_podhd *pod = card->private_data;
 
-       return sprintf(buf, "%06x\n", pod->firmware_version);
+       return sysfs_emit(buf, "%06x\n", pod->firmware_version);
 }
 
 static DEVICE_ATTR_RO(firmware_version);
index d35cf54cab3383fb11f179bf4531b838784dcbad..c06d6dfa81392de523962666d7af4dbaa943d941 100644 (file)
@@ -24,6 +24,7 @@
 #include <sound/asoundef.h>
 #include <sound/core.h>
 #include <sound/control.h>
+#include <sound/hda_verbs.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
 #include <sound/tlv.h>
@@ -1934,13 +1935,194 @@ static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer)
                                          NULL);
 }
 
+/*
+ * Dell WD15 dock jack detection
+ *
+ * The WD15 contains an ALC4020 USB audio controller and ALC3263 audio codec
+ * from Realtek. It is a UAC 1 device, and UAC 1 does not support jack
+ * detection. Instead, jack detection works by sending HD Audio commands over
+ * vendor-type USB messages.
+ */
+
+#define HDA_VERB_CMD(V, N, D) (((N) << 20) | ((V) << 8) | (D))
+
+#define REALTEK_HDA_VALUE 0x0038
+
+#define REALTEK_HDA_SET                62
+#define REALTEK_MANUAL_MODE    72
+#define REALTEK_HDA_GET_OUT    88
+#define REALTEK_HDA_GET_IN     89
+
+#define REALTEK_AUDIO_FUNCTION_GROUP   0x01
+#define REALTEK_LINE1                  0x1a
+#define REALTEK_VENDOR_REGISTERS       0x20
+#define REALTEK_HP_OUT                 0x21
+
+#define REALTEK_CBJ_CTRL2 0x50
+
+#define REALTEK_JACK_INTERRUPT_NODE 5
+
+#define REALTEK_MIC_FLAG 0x100
+
+static int realtek_hda_set(struct snd_usb_audio *chip, u32 cmd)
+{
+       struct usb_device *dev = chip->dev;
+       __be32 buf = cpu_to_be32(cmd);
+
+       return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_HDA_SET,
+                              USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT,
+                              REALTEK_HDA_VALUE, 0, &buf, sizeof(buf));
+}
+
+static int realtek_hda_get(struct snd_usb_audio *chip, u32 cmd, u32 *value)
+{
+       struct usb_device *dev = chip->dev;
+       int err;
+       __be32 buf = cpu_to_be32(cmd);
+
+       err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_HDA_GET_OUT,
+                             USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT,
+                             REALTEK_HDA_VALUE, 0, &buf, sizeof(buf));
+       if (err < 0)
+               return err;
+       err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), REALTEK_HDA_GET_IN,
+                             USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN,
+                             REALTEK_HDA_VALUE, 0, &buf, sizeof(buf));
+       if (err < 0)
+               return err;
+
+       *value = be32_to_cpu(buf);
+       return 0;
+}
+
+static int realtek_ctl_connector_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *cval = kcontrol->private_data;
+       struct snd_usb_audio *chip = cval->head.mixer->chip;
+       u32 pv = kcontrol->private_value;
+       u32 node_id = pv & 0xff;
+       u32 sense;
+       u32 cbj_ctrl2;
+       bool presence;
+       int err;
+
+       err = snd_usb_lock_shutdown(chip);
+       if (err < 0)
+               return err;
+       err = realtek_hda_get(chip,
+                             HDA_VERB_CMD(AC_VERB_GET_PIN_SENSE, node_id, 0),
+                             &sense);
+       if (err < 0)
+               goto err;
+       if (pv & REALTEK_MIC_FLAG) {
+               err = realtek_hda_set(chip,
+                                     HDA_VERB_CMD(AC_VERB_SET_COEF_INDEX,
+                                                  REALTEK_VENDOR_REGISTERS,
+                                                  REALTEK_CBJ_CTRL2));
+               if (err < 0)
+                       goto err;
+               err = realtek_hda_get(chip,
+                                     HDA_VERB_CMD(AC_VERB_GET_PROC_COEF,
+                                                  REALTEK_VENDOR_REGISTERS, 0),
+                                     &cbj_ctrl2);
+               if (err < 0)
+                       goto err;
+       }
+err:
+       snd_usb_unlock_shutdown(chip);
+       if (err < 0)
+               return err;
+
+       presence = sense & AC_PINSENSE_PRESENCE;
+       if (pv & REALTEK_MIC_FLAG)
+               presence = presence && (cbj_ctrl2 & 0x0070) == 0x0070;
+       ucontrol->value.integer.value[0] = presence;
+       return 0;
+}
+
+static const struct snd_kcontrol_new realtek_connector_ctl_ro = {
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .name = "", /* will be filled later manually */
+       .access = SNDRV_CTL_ELEM_ACCESS_READ,
+       .info = snd_ctl_boolean_mono_info,
+       .get = realtek_ctl_connector_get,
+};
+
+static int realtek_resume_jack(struct usb_mixer_elem_list *list)
+{
+       snd_ctl_notify(list->mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                      &list->kctl->id);
+       return 0;
+}
+
+static int realtek_add_jack(struct usb_mixer_interface *mixer,
+                           char *name, u32 val)
+{
+       struct usb_mixer_elem_info *cval;
+       struct snd_kcontrol *kctl;
+
+       cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+       if (!cval)
+               return -ENOMEM;
+       snd_usb_mixer_elem_init_std(&cval->head, mixer,
+                                   REALTEK_JACK_INTERRUPT_NODE);
+       cval->head.resume = realtek_resume_jack;
+       cval->val_type = USB_MIXER_BOOLEAN;
+       cval->channels = 1;
+       cval->min = 0;
+       cval->max = 1;
+       kctl = snd_ctl_new1(&realtek_connector_ctl_ro, cval);
+       if (!kctl) {
+               kfree(cval);
+               return -ENOMEM;
+       }
+       kctl->private_value = val;
+       strscpy(kctl->id.name, name, sizeof(kctl->id.name));
+       kctl->private_free = snd_usb_mixer_elem_free;
+       return snd_usb_mixer_add_control(&cval->head, kctl);
+}
+
+static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
+{
+       int err;
+       struct usb_device *dev = mixer->chip->dev;
+
+       /* Power down the audio codec to avoid loud pops in the next step. */
+       realtek_hda_set(mixer->chip,
+                       HDA_VERB_CMD(AC_VERB_SET_POWER_STATE,
+                                    REALTEK_AUDIO_FUNCTION_GROUP,
+                                    AC_PWRST_D3));
+
+       /*
+        * Turn off 'manual mode' in case it was enabled. This removes the need
+        * to power cycle the dock after it was attached to a Windows machine.
+        */
+       snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_MANUAL_MODE,
+                       USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT,
+                       0, 0, NULL, 0);
+
+       err = realtek_add_jack(mixer, "Line Out Jack", REALTEK_LINE1);
+       if (err < 0)
+               return err;
+       err = realtek_add_jack(mixer, "Headphone Jack", REALTEK_HP_OUT);
+       if (err < 0)
+               return err;
+       err = realtek_add_jack(mixer, "Headset Mic Jack",
+                              REALTEK_HP_OUT | REALTEK_MIC_FLAG);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
 {
        u16 buf = 0;
 
        snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
                        USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                       ch, snd_usb_ctrl_intf(chip) | (id << 8),
+                       (UAC_FU_VOLUME << 8) | ch,
+                       snd_usb_ctrl_intf(chip) | (id << 8),
                        &buf, 2);
 }
 
@@ -3245,6 +3427,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
                err = snd_soundblaster_e1_switch_create(mixer);
                break;
        case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */
+               err = dell_dock_mixer_create(mixer);
+               if (err < 0)
+                       break;
                err = dell_dock_mixer_init(mixer);
                break;
 
index 968d90caeefa09a19a10b5106514b18a3f458b16..168fd802d70bd058fe641d94bb739efe41ed963b 100644 (file)
@@ -1843,6 +1843,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x1397, 0x0508, /* Behringer UMC204HD */
                   QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */