Add cs42l43 PC focused SoundWire CODEC
authorMark Brown <broonie@kernel.org>
Tue, 22 Aug 2023 11:48:04 +0000 (12:48 +0100)
committerMark Brown <broonie@kernel.org>
Tue, 22 Aug 2023 11:48:04 +0000 (12:48 +0100)
Merge series from Charles Keepax <ckeepax@opensource.cirrus.com>:

This patch chain adds support for the Cirrus Logic cs42l43 PC focused
SoundWire CODEC. The chain is currently based of Lee's for-mfd-next
branch.

This series is mostly just a resend keeping pace with the kernel under
it, except for a minor fixup in the ASoC stuff.

Thanks,
Charles

Charles Keepax (4):
  dt-bindings: mfd: cirrus,cs42l43: Add initial DT binding
  mfd: cs42l43: Add support for cs42l43 core driver
  pinctrl: cs42l43: Add support for the cs42l43
  ASoC: cs42l43: Add support for the cs42l43

Lucas Tanure (2):
  soundwire: bus: Allow SoundWire peripherals to register IRQ handlers
  spi: cs42l43: Add SPI controller support

 .../bindings/sound/cirrus,cs42l43.yaml        |  313 +++
 MAINTAINERS                                   |    4 +
 drivers/mfd/Kconfig                           |   23 +
 drivers/mfd/Makefile                          |    3 +
 drivers/mfd/cs42l43-i2c.c                     |   98 +
 drivers/mfd/cs42l43-sdw.c                     |  239 ++
 drivers/mfd/cs42l43.c                         | 1188 +++++++++
 drivers/mfd/cs42l43.h                         |   28 +
 drivers/pinctrl/cirrus/Kconfig                |   11 +
 drivers/pinctrl/cirrus/Makefile               |    2 +
 drivers/pinctrl/cirrus/pinctrl-cs42l43.c      |  609 +++++
 drivers/soundwire/bus.c                       |   32 +
 drivers/soundwire/bus_type.c                  |   12 +
 drivers/spi/Kconfig                           |    7 +
 drivers/spi/Makefile                          |    1 +
 drivers/spi/spi-cs42l43.c                     |  284 ++
 include/linux/mfd/cs42l43-regs.h              | 1184 +++++++++
 include/linux/mfd/cs42l43.h                   |  102 +
 include/linux/soundwire/sdw.h                 |    9 +
 include/sound/cs42l43.h                       |   17 +
 sound/soc/codecs/Kconfig                      |   16 +
 sound/soc/codecs/Makefile                     |    4 +
 sound/soc/codecs/cs42l43-jack.c               |  946 +++++++
 sound/soc/codecs/cs42l43-sdw.c                |   74 +
 sound/soc/codecs/cs42l43.c                    | 2278 +++++++++++++++++
 sound/soc/codecs/cs42l43.h                    |  131 +
 26 files changed, 7615 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
 create mode 100644 drivers/mfd/cs42l43-i2c.c
 create mode 100644 drivers/mfd/cs42l43-sdw.c
 create mode 100644 drivers/mfd/cs42l43.c
 create mode 100644 drivers/mfd/cs42l43.h
 create mode 100644 drivers/pinctrl/cirrus/pinctrl-cs42l43.c
 create mode 100644 drivers/spi/spi-cs42l43.c
 create mode 100644 include/linux/mfd/cs42l43-regs.h
 create mode 100644 include/linux/mfd/cs42l43.h
 create mode 100644 include/sound/cs42l43.h
 create mode 100644 sound/soc/codecs/cs42l43-jack.c
 create mode 100644 sound/soc/codecs/cs42l43-sdw.c
 create mode 100644 sound/soc/codecs/cs42l43.c
 create mode 100644 sound/soc/codecs/cs42l43.h

--
2.30.2

526 files changed:
Documentation/core-api/kernel-api.rst
Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
Documentation/devicetree/bindings/sound/audio-iio-aux.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/awinic,aw88395.yaml
Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
Documentation/devicetree/bindings/sound/google,sc7180-trogdor.yaml
Documentation/devicetree/bindings/sound/google,sc7280-herobrine.yaml
Documentation/devicetree/bindings/sound/gtm601.txt [deleted file]
Documentation/devicetree/bindings/sound/imx-audio-card.yaml
Documentation/devicetree/bindings/sound/max9892x.txt [deleted file]
Documentation/devicetree/bindings/sound/maxim,max98925.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mediatek,mt8188-afe.yaml
Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml
Documentation/devicetree/bindings/sound/nau8821.txt [deleted file]
Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nuvoton,nau8822.yaml
Documentation/devicetree/bindings/sound/option,gtm601.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt [deleted file]
Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/renesas,rsnd.yaml
Documentation/devicetree/bindings/sound/samsung,aries-wm8994.yaml
Documentation/devicetree/bindings/sound/samsung,midas-audio.yaml
Documentation/devicetree/bindings/sound/samsung,odroid.yaml
Documentation/devicetree/bindings/sound/samsung,tm2.yaml
Documentation/devicetree/bindings/sound/simple-card.yaml
Documentation/devicetree/bindings/sound/sound-card-common.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wlf,wm8904.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wlf,wm8960.yaml
Documentation/devicetree/bindings/sound/wm8904.txt [deleted file]
Documentation/driver-api/media/dtv-common.rst
MAINTAINERS
drivers/firmware/cirrus/cs_dsp.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/iio/inkern.c
drivers/media/dvb-core/Makefile
drivers/media/dvb-core/dvb_math.c [deleted file]
drivers/media/dvb-frontends/af9013_priv.h
drivers/media/dvb-frontends/af9033_priv.h
drivers/media/dvb-frontends/cxd2820r_priv.h
drivers/media/dvb-frontends/cxd2841er.c
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c
drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt_mon.c
drivers/media/dvb-frontends/cxd2880/cxd2880_top.c
drivers/media/dvb-frontends/dib7000p.c
drivers/media/dvb-frontends/dib8000.c
drivers/media/dvb-frontends/dib9000.c
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/lgdt3305.c
drivers/media/dvb-frontends/lgdt3306a.c
drivers/media/dvb-frontends/lgdt330x.c
drivers/media/dvb-frontends/m88ds3103_priv.h
drivers/media/dvb-frontends/mn88443x.c
drivers/media/dvb-frontends/mn88472_priv.h
drivers/media/dvb-frontends/mn88473_priv.h
drivers/media/dvb-frontends/or51132.c
drivers/media/dvb-frontends/or51211.c
drivers/media/dvb-frontends/rtl2830_priv.h
drivers/media/dvb-frontends/rtl2832_priv.h
drivers/media/dvb-frontends/si2165.c
drivers/media/dvb-frontends/stv0367.c
drivers/media/dvb-frontends/tc90522.c
drivers/media/dvb-frontends/tda10048.c
include/linux/device.h
include/linux/firmware/imx/dsp.h
include/linux/firmware/mediatek/mtk-adsp-ipc.h
include/linux/iio/consumer.h
include/linux/int_log.h [new file with mode: 0644]
include/linux/minmax.h
include/linux/pci_ids.h
include/linux/platform_device.h
include/linux/soundwire/sdw.h
include/linux/soundwire/sdw_intel.h
include/media/dvb_math.h [deleted file]
include/sound/cs35l56.h
include/sound/hda-mlink.h
include/sound/hda_codec.h
include/sound/hdaudio.h
include/sound/rt5665.h
include/sound/rt5668.h
include/sound/rt5682.h
include/sound/rt5682s.h
include/sound/simple_card_utils.h
include/sound/soc-acpi.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/sof/topology.h
include/uapi/sound/sof/tokens.h
lib/math/Makefile
lib/math/int_log.c [new file with mode: 0644]
sound/Kconfig
sound/drivers/serial-generic.c
sound/hda/hdac_i915.c
sound/hda/intel-dsp-config.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/cs35l56_hda.c [new file with mode: 0644]
sound/pci/hda/cs35l56_hda.h [new file with mode: 0644]
sound/pci/hda/cs35l56_hda_i2c.c [new file with mode: 0644]
sound/pci/hda/cs35l56_hda_spi.c [new file with mode: 0644]
sound/pci/hda/hda_auto_parser.h
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/soc/Kconfig
sound/soc/adi/axi-i2s.c
sound/soc/adi/axi-spdif.c
sound/soc/amd/Kconfig
sound/soc/amd/acp-config.c
sound/soc/amd/acp-da7219-max98357a.c
sound/soc/amd/acp-rt5645.c
sound/soc/amd/acp/Kconfig
sound/soc/amd/acp/Makefile
sound/soc/amd/acp/acp-i2s.c
sound/soc/amd/acp/acp-legacy-common.c [new file with mode: 0644]
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
sound/soc/amd/acp/acp-renoir.c
sound/soc/amd/acp/acp-sof-mach.c
sound/soc/amd/acp/amd.h
sound/soc/amd/acp3x-rt5682-max9836.c
sound/soc/amd/mach-config.h
sound/soc/amd/ps/ps-sdw-dma.c
sound/soc/amd/vangogh/acp5x-mach.c
sound/soc/atmel/atmel-i2s.c
sound/soc/atmel/atmel-pdmic.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/tse850-pcm5142.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/psc-ac97.c
sound/soc/bcm/bcm2835-i2s.c
sound/soc/bcm/bcm63xx-i2s-whistler.c
sound/soc/bcm/cygnus-ssp.h
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/adau1372.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/adau7118-i2c.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/audio-iio-aux.c [new file with mode: 0644]
sound/soc/codecs/aw88261.c [new file with mode: 0644]
sound/soc/codecs/aw88261.h [new file with mode: 0644]
sound/soc/codecs/aw88395/aw88395_lib.c
sound/soc/codecs/aw88395/aw88395_reg.h
sound/soc/codecs/cs35l36.c
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l45-tables.c
sound/soc/codecs/cs35l56-i2c.c
sound/soc/codecs/cs35l56-sdw.c
sound/soc/codecs/cs35l56-shared.c
sound/soc/codecs/cs35l56-spi.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/cs35l56.h
sound/soc/codecs/cs4265.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs42l51-i2c.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42xx8.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/cx2072x.c
sound/soc/codecs/es8316.c
sound/soc/codecs/es8326.c
sound/soc/codecs/es8326.h
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/lpass-tx-macro.c
sound/soc/codecs/lpass-va-macro.c
sound/soc/codecs/lpass-wsa-macro.c
sound/soc/codecs/max98363.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/max98926.c
sound/soc/codecs/max98927.c
sound/soc/codecs/msm8916-wcd-analog.c
sound/soc/codecs/nau8825.c
sound/soc/codecs/rt1011.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/rt1015p.c
sound/soc/codecs/rt1016.c
sound/soc/codecs/rt1017-sdca-sdw.c [new file with mode: 0644]
sound/soc/codecs/rt1017-sdca-sdw.h [new file with mode: 0644]
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/rt1318-sdw.c
sound/soc/codecs/rt5514-spi.c
sound/soc/codecs/rt5514.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.h
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5659.c
sound/soc/codecs/rt5660.c
sound/soc/codecs/rt5665.c
sound/soc/codecs/rt5668.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/rt5682s.c
sound/soc/codecs/rt5682s.h
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdca-sdw.c
sound/soc/codecs/rt711-sdca.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt712-sdca-dmic.c
sound/soc/codecs/rt712-sdca-sdw.c
sound/soc/codecs/rt712-sdca.c
sound/soc/codecs/rt715-sdca-sdw.c
sound/soc/codecs/rt715-sdca.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/rt715.c
sound/soc/codecs/rt715.h
sound/soc/codecs/rt722-sdca-sdw.c
sound/soc/codecs/rt722-sdca.c
sound/soc/codecs/ssm3515.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/tas2781-comlib.c
sound/soc/codecs/tas2781-i2c.c
sound/soc/codecs/tas5805m.c
sound/soc/codecs/tlv320aic32x4-clk.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic32x4.h
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wcd938x-sdw.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.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/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/wm8960.h
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.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/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/wm_adsp.h
sound/soc/codecs/wsa881x.c
sound/soc/codecs/wsa883x.c
sound/soc/dwc/dwc-i2s.c
sound/soc/dwc/dwc-pcm.c
sound/soc/dwc/local.h
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_aud2htx.c
sound/soc/fsl/fsl_easrc.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_micfil.h
sound/soc/fsl/fsl_qmc_audio.c
sound/soc/fsl/fsl_rpmsg.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_spdif.h
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_xcvr.c
sound/soc/fsl/imx-audio-rpmsg.c
sound/soc/fsl/imx-es8328.c
sound/soc/fsl/imx-pcm-rpmsg.c
sound/soc/generic/audio-graph-card.c
sound/soc/generic/audio-graph-card2.c
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.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/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst.h
sound/soc/intel/atom/sst/sst_pci.c
sound/soc/intel/atom/sst/sst_stream.c
sound/soc/intel/avs/board_selection.c
sound/soc/intel/avs/boards/Kconfig
sound/soc/intel/avs/boards/Makefile
sound/soc/intel/avs/boards/da7219.c
sound/soc/intel/avs/boards/es8336.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt5663.c [new file with mode: 0644]
sound/soc/intel/avs/boards/rt5682.c
sound/soc/intel/avs/core.c
sound/soc/intel/avs/probes.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/bdw_rt286.c
sound/soc/intel/boards/bxt_da7219_max98357a.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/kbl_da7219_max98357a.c
sound/soc/intel/boards/kbl_da7219_max98927.c
sound/soc/intel/boards/sof_da7219_max98373.c
sound/soc/intel/boards/sof_es8336.c
sound/soc/intel/boards/sof_maxim_common.c
sound/soc/intel/boards/sof_maxim_common.h
sound/soc/intel/boards/sof_nau8825.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/boards/sof_sdw_common.h
sound/soc/intel/boards/sof_sdw_cs42l42.c
sound/soc/intel/boards/sof_sdw_cs_amp.c [new file with mode: 0644]
sound/soc/intel/boards/sof_ssp_amp.c
sound/soc/intel/catpt/pcm.c
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-jsl-match.c
sound/soc/intel/common/soc-acpi-intel-mtl-match.c
sound/soc/intel/common/soc-acpi-intel-rpl-match.c
sound/soc/intel/keembay/kmb_platform.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/loongson/loongson_card.c
sound/soc/loongson/loongson_i2s.c
sound/soc/mediatek/Kconfig
sound/soc/mediatek/Makefile
sound/soc/mediatek/mt7986/Makefile [new file with mode: 0644]
sound/soc/mediatek/mt7986/mt7986-afe-common.h [new file with mode: 0644]
sound/soc/mediatek/mt7986/mt7986-afe-pcm.c [new file with mode: 0644]
sound/soc/mediatek/mt7986/mt7986-dai-etdm.c [new file with mode: 0644]
sound/soc/mediatek/mt7986/mt7986-reg.h [new file with mode: 0644]
sound/soc/mediatek/mt7986/mt7986-wm8960.c [new file with mode: 0644]
sound/soc/mediatek/mt8173/mt8173-max98090.c
sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
sound/soc/mediatek/mt8173/mt8173-rt5650.c
sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
sound/soc/mediatek/mt8186/mt8186-afe-clk.c
sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
sound/soc/mediatek/mt8186/mt8186-mt6366-da7219-max98357.c
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
sound/soc/mediatek/mt8188/mt8188-mt6359.c
sound/soc/mediatek/mt8195/mt8195-dai-etdm.c
sound/soc/meson/aiu-acodec-ctrl.c
sound/soc/meson/aiu-codec-ctrl.c
sound/soc/meson/aiu-fifo-i2s.c
sound/soc/meson/aiu-fifo-spdif.c
sound/soc/meson/aiu.c
sound/soc/meson/axg-frddr.c
sound/soc/meson/axg-pdm.c
sound/soc/meson/axg-spdifin.c
sound/soc/meson/axg-tdm-formatter.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/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/lpass-ipq806x.c
sound/soc/qcom/lpass-sc7180.c
sound/soc/qcom/lpass-sc7280.c
sound/soc/qcom/lpass.h
sound/soc/qcom/qdsp6/q6afe-dai.c
sound/soc/qcom/qdsp6/q6apm.c
sound/soc/qcom/qdsp6/q6apm.h
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
sound/soc/qcom/sc7180.c
sound/soc/qcom/sc7280.c
sound/soc/qcom/sdm845.c
sound/soc/rockchip/rk3399_gru_sound.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_i2s_tdm.c
sound/soc/rockchip/rockchip_pdm.c
sound/soc/rockchip/rockchip_rt5645.c
sound/soc/rockchip/rockchip_spdif.c
sound/soc/samsung/aries_wm8994.c
sound/soc/samsung/i2s.c
sound/soc/samsung/littlemill.c
sound/soc/samsung/lowland.c
sound/soc/samsung/midas_wm1811.c
sound/soc/samsung/odroid.c
sound/soc/samsung/pcm.c
sound/soc/samsung/tm2_wm5110.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/rsnd.h
sound/soc/soc-acpi.c
sound/soc/soc-core.c
sound/soc/soc-dai.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/amd/Kconfig
sound/soc/sof/amd/Makefile
sound/soc/sof/amd/acp-common.c
sound/soc/sof/amd/acp-dsp-offset.h
sound/soc/sof/amd/acp-ipc.c
sound/soc/sof/amd/acp-loader.c
sound/soc/sof/amd/acp-probes.c [new file with mode: 0644]
sound/soc/sof/amd/acp.c
sound/soc/sof/amd/acp.h
sound/soc/sof/amd/pci-rmb.c
sound/soc/sof/amd/pci-rn.c
sound/soc/sof/amd/pci-vangogh.c [new file with mode: 0644]
sound/soc/sof/amd/vangogh.c [new file with mode: 0644]
sound/soc/sof/intel/Kconfig
sound/soc/sof/intel/Makefile
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/hda-dai-ops.c
sound/soc/sof/intel/hda-dai.c
sound/soc/sof/intel/hda-mlink.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/lnl.c [new file with mode: 0644]
sound/soc/sof/intel/mtl.c
sound/soc/sof/intel/mtl.h
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-lnl.c [new file with mode: 0644]
sound/soc/sof/intel/pci-mtl.c
sound/soc/sof/intel/pci-skl.c
sound/soc/sof/intel/pci-tgl.c
sound/soc/sof/intel/pci-tng.c
sound/soc/sof/intel/shim.h
sound/soc/sof/intel/tgl.c
sound/soc/sof/ipc3-dtrace.c
sound/soc/sof/ipc3-pcm.c
sound/soc/sof/ipc3.c
sound/soc/sof/ipc4-pcm.c
sound/soc/sof/ipc4-topology.c
sound/soc/sof/ipc4-topology.h
sound/soc/sof/mediatek/mt8186/mt8186.c
sound/soc/sof/sof-client-probes-ipc4.c
sound/soc/sof/sof-client-probes.c
sound/soc/sof/topology.c
sound/soc/starfive/jh7110_tdm.c
sound/soc/sti/sti_uniperif.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-dmic.c
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra210_admaif.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/ti/davinci-evm.c
sound/soc/ti/davinci-i2s.c
sound/soc/ti/davinci-mcasp.c
sound/soc/ti/omap-dmic.c
sound/soc/ti/omap-mcbsp.c
sound/soc/ti/omap-mcpdm.c
sound/soc/uniphier/aio-cpu.c
sound/soc/uniphier/aio-ld11.c
sound/soc/uniphier/aio-pxs2.c
sound/soc/uniphier/aio.h
sound/soc/ux500/ux500_msp_dai.c
tools/testing/kunit/configs/all_tests.config

index f2bcc5a7ea432d8da0f0dad5105241df8494211e..ae92a2571388ae7fc0b7c5f23a19ed59ac1312cc 100644 (file)
@@ -162,8 +162,10 @@ Base 2 log and power Functions
 .. kernel-doc:: include/linux/log2.h
    :internal:
 
-Integer power Functions
------------------------
+Integer log and power Functions
+-------------------------------
+
+.. kernel-doc:: include/linux/int_log.h
 
 .. kernel-doc:: lib/math/int_pow.c
    :export:
index bf123455034352e64fffc8f2b583fb7723fd1564..5db718e4d0e7abd3f12e8d634111535e67b94fb2 100644 (file)
@@ -9,6 +9,9 @@ title: Amlogic AXG sound card
 maintainers:
   - Jerome Brunet <jbrunet@baylibre.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     const: amlogic,axg-sound-card
@@ -17,23 +20,12 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: list of auxiliary devices
 
-  audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    description:
-      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.
-
   audio-widgets:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
     description:
       A list off component DAPM widget. Each entry is a pair of strings,
       the first being the widget type, the second being the widget name
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
 patternProperties:
   "^dai-link-[0-9]+$":
     type: object
@@ -108,7 +100,6 @@ patternProperties:
       - sound-dai
 
 required:
-  - model
   - dai-link-0
 
 unevaluatedProperties: false
index b358fd601ed381b9a4bababe03790f96e007dc2b..d4277d342e699ac4ab483f8fedb5e48421e17a33 100644 (file)
@@ -9,6 +9,9 @@ title: Amlogic GX sound card
 maintainers:
   - Jerome Brunet <jbrunet@baylibre.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     items:
@@ -18,14 +21,6 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: list of auxiliary devices
 
-  audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    minItems: 2
-    description: |-
-      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.
-
   audio-widgets:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
     minItems: 2
@@ -33,10 +28,6 @@ properties:
       A list off component DAPM widget. Each entry is a pair of strings,
       the first being the widget type, the second being the widget name
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
 patternProperties:
   "^dai-link-[0-9]+$":
     type: object
@@ -86,7 +77,7 @@ required:
   - model
   - dai-link-0
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml b/Documentation/devicetree/bindings/sound/audio-iio-aux.yaml
new file mode 100644 (file)
index 0000000..d3cc1ea
--- /dev/null
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/audio-iio-aux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio IIO auxiliary
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description:
+  Auxiliary device based on Industrial I/O device channels
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: audio-iio-aux
+
+  io-channels:
+    description:
+      Industrial I/O device channels used
+
+  io-channel-names:
+    description:
+      Industrial I/O channel names related to io-channels.
+      These names are used to provides sound controls, widgets and routes names.
+
+  snd-control-invert-range:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      A list of 0/1 flags defining whether or not the related channel is
+      inverted
+    items:
+      enum: [0, 1]
+      default: 0
+      description: |
+        Invert the sound control value compared to the IIO channel raw value.
+          - 1: The related sound control value is inverted meaning that the
+               minimum sound control value correspond to the maximum IIO channel
+               raw value and the maximum sound control value correspond to the
+               minimum IIO channel raw value.
+          - 0: The related sound control value is not inverted meaning that the
+               minimum (resp maximum) sound control value correspond to the
+               minimum (resp maximum) IIO channel raw value.
+
+required:
+  - compatible
+  - io-channels
+  - io-channel-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    iio-aux {
+        compatible = "audio-iio-aux";
+        io-channels = <&iio 0>, <&iio 1>, <&iio 2>, <&iio 3>;
+        io-channel-names = "CH0", "CH1", "CH2", "CH3";
+        /* Invert CH1 and CH2 */
+        snd-control-invert-range = <0 1 1 0>;
+    };
index 35eef7d818a2fb68bbe599648a5cad31795a12fa..4051c2538cafdb493293e8ca9d63cd10c6035952 100644 (file)
@@ -19,7 +19,9 @@ allOf:
 
 properties:
   compatible:
-    const: awinic,aw88395
+    enum:
+      - awinic,aw88395
+      - awinic,aw88261
 
   reg:
     maxItems: 1
index e847611a85f7c2cfab1d0efb04c6638f73762c9a..188f38baddec31b0132cc9699d49d3288be2585b 100644 (file)
@@ -17,6 +17,9 @@ description: |
   such as SAI, MICFIL, .etc through building rpmsg channels between
   Cortex-A and Cortex-M.
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     enum:
@@ -25,10 +28,7 @@ properties:
       - fsl,imx8mm-rpmsg-audio
       - fsl,imx8mp-rpmsg-audio
       - fsl,imx8ulp-rpmsg-audio
-
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
+      - fsl,imx93-rpmsg-audio
 
   clocks:
     items:
@@ -65,13 +65,6 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle
     description: The phandle to a node of audio codec
 
-  audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    description: |
-      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.
-
   fsl,enable-lpa:
     $ref: /schemas/types.yaml#/definitions/flag
     description: enable low power audio path.
@@ -100,9 +93,8 @@ properties:
 
 required:
   - compatible
-  - model
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
index ba5b7728cf333e86825891920fa7b0b5f903742a..bac940553965cb4a7ff307242d36c2e9ada4f23d 100644 (file)
@@ -13,23 +13,15 @@ maintainers:
 description:
   This binding describes the SC7180 sound card which uses LPASS for audio.
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     enum:
       - google,sc7180-trogdor
       - google,sc7180-coachz
 
-  audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    description:
-      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.
-
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
   "#address-cells":
     const: 1
 
@@ -86,11 +78,10 @@ patternProperties:
 
 required:
   - compatible
-  - model
   - "#address-cells"
   - "#size-cells"
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
 
index 0b1a01a4c14ed1e190b72e7a2a668e82dd36e9ee..ec4b6e547ca6efad4b77697c567e30da74707261 100644 (file)
@@ -13,22 +13,14 @@ maintainers:
 description:
   This binding describes the SC7280 sound card which uses LPASS for audio.
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     enum:
       - google,sc7280-herobrine
 
-  audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    description:
-      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.
-
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
   "#address-cells":
     const: 1
 
@@ -97,11 +89,10 @@ patternProperties:
 
 required:
   - compatible
-  - model
   - "#address-cells"
   - "#size-cells"
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
 
diff --git a/Documentation/devicetree/bindings/sound/gtm601.txt b/Documentation/devicetree/bindings/sound/gtm601.txt
deleted file mode 100644 (file)
index efa32a4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-GTM601 UMTS modem audio interface CODEC
-
-This device has no configuration interface. The sample rate and channels are
-based on the compatible string
-       "option,gtm601" = 8kHz mono
-       "broadmobi,bm818" = 48KHz stereo
-
-Required properties:
-
-  - compatible : one of
-       "option,gtm601"
-       "broadmobi,bm818"
-
-
-Example:
-
-codec: gtm601_codec {
-       compatible = "option,gtm601";
-};
index b6f5d486600ed4c22e062b5bee33986912cb3af7..f7ad5ea2491e0f06698181e143a107746f15b323 100644 (file)
@@ -9,23 +9,14 @@ title: NXP i.MX audio sound card.
 maintainers:
   - Shengjiu Wang <shengjiu.wang@nxp.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     enum:
       - fsl,imx-audio-card
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
-  audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
-    description:
-      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.
-
 patternProperties:
   ".*-dai-link$":
     description:
@@ -84,9 +75,8 @@ patternProperties:
 
 required:
   - compatible
-  - model
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/sound/max9892x.txt b/Documentation/devicetree/bindings/sound/max9892x.txt
deleted file mode 100644 (file)
index 98cb9ba..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier
-
-This device supports I2C.
-
-Required properties:
-
-  - compatible : should be one of the following
-    - "maxim,max98925"
-    - "maxim,max98926"
-    - "maxim,max98927"
-
-  - vmon-slot-no : slot number used to send voltage information
-                   or in inteleave mode this will be used as
-                   interleave slot.
-                   MAX98925/MAX98926 slot range : 0 ~ 30,  Default : 0
-                   MAX98927 slot range : 0 ~ 15,  Default : 0
-
-  - imon-slot-no : slot number used to send current information
-                   MAX98925/MAX98926 slot range : 0 ~ 30,  Default : 0
-                   MAX98927 slot range : 0 ~ 15,  Default : 0
-
-  - interleave-mode : When using two MAX9892X in a system it is
-                   possible to create ADC data that that will
-                   overflow the frame size. Digital Audio Interleave
-                   mode provides a means to output VMON and IMON data
-                   from two devices on a single DOUT line when running
-                   smaller frames sizes such as 32 BCLKS per LRCLK or
-                   48 BCLKS per LRCLK.
-                   Range : 0 (off), 1 (on),  Default : 0
-
-  - reg : the I2C address of the device for I2C
-
-Optional properties:
-  - reset-gpios : GPIO to reset the device
-
-Example:
-
-codec: max98927@3a {
-   compatible = "maxim,max98927";
-   vmon-slot-no = <0>;
-   imon-slot-no = <1>;
-   interleave-mode = <0>;
-   reg = <0x3a>;
-};
diff --git a/Documentation/devicetree/bindings/sound/maxim,max98925.yaml b/Documentation/devicetree/bindings/sound/maxim,max98925.yaml
new file mode 100644 (file)
index 0000000..32fd862
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/maxim,max98925.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim Integrated MAX98925/MAX98926/MAX98927 speaker amplifier
+
+maintainers:
+  - Ryan Lee <ryans.lee@maximintegrated.com>
+
+properties:
+  compatible:
+    enum:
+      - maxim,max98925
+      - maxim,max98926
+      - maxim,max98927
+
+  reg:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+
+  '#sound-dai-cells':
+    const: 0
+
+  vmon-slot-no:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 30
+    default: 0
+    description:
+      Slot number used to send voltage information or in inteleave mode this
+      will be used as interleave slot.
+
+  imon-slot-no:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 30
+    default: 0
+    description:
+      Slot number used to send current information.
+
+  maxim,interleave-mode:
+    type: boolean
+    description:
+      When using two MAX9892X in a system it is possible to create ADC data
+      that will overflow the frame size. When enabled, the Digital Audio
+      Interleave mode provides a means to output VMON and IMON data from two
+      devices on a single DOUT line when running smaller frames sizes such as
+      32 BCLKS per LRCLK or 48 BCLKS per LRCLK.
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: dai-common.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - maxim,max98927
+    then:
+      properties:
+        vmon-slot-no:
+          minimum: 0
+          maximum: 15
+
+        imon-slot-no:
+          minimum: 0
+          maximum: 15
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        #include <dt-bindings/gpio/gpio.h>
+        audio-codec@3a {
+            compatible = "maxim,max98927";
+            reg = <0x3a>;
+            #sound-dai-cells = <0>;
+
+            pinctrl-0 = <&speaker_default>;
+            pinctrl-names = "default";
+
+            reset-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>;
+
+            vmon-slot-no = <1>;
+            imon-slot-no = <0>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-afe.yaml
new file mode 100644 (file)
index 0000000..398efdf
--- /dev/null
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt7986-afe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek AFE PCM controller for MT7986
+
+maintainers:
+  - Maso Huang <maso.huang@mediatek.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: mediatek,mt7986-afe
+      - items:
+          - enum:
+              - mediatek,mt7981-afe
+              - mediatek,mt7988-afe
+          - const: mediatek,mt7986-afe
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 5
+    items:
+      - description: audio bus clock
+      - description: audio 26M clock
+      - description: audio intbus clock
+      - description: audio hopping clock
+      - description: audio pll clock
+      - description: mux for pcm_mck
+      - description: audio i2s/pcm mck
+
+  clock-names:
+    minItems: 5
+    items:
+      - const: bus_ck
+      - const: 26m_ck
+      - const: l_ck
+      - const: aud_ck
+      - const: eg2_ck
+      - const: sel
+      - const: i2s_m
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt7986-afe
+    then:
+      properties:
+        clocks:
+          items:
+            - description: audio bus clock
+            - description: audio 26M clock
+            - description: audio intbus clock
+            - description: audio hopping clock
+            - description: audio pll clock
+        clock-names:
+          items:
+            - const: bus_ck
+            - const: 26m_ck
+            - const: l_ck
+            - const: aud_ck
+            - const: eg2_ck
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt7981-afe
+    then:
+      properties:
+        clocks:
+          items:
+            - description: audio bus clock
+            - description: audio 26M clock
+            - description: audio intbus clock
+            - description: audio hopping clock
+            - description: audio pll clock
+            - description: mux for pcm_mck
+        clock-names:
+          items:
+            - const: bus_ck
+            - const: 26m_ck
+            - const: l_ck
+            - const: aud_ck
+            - const: eg2_ck
+            - const: sel
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mediatek,mt7988-afe
+    then:
+      properties:
+        clocks:
+          items:
+            - description: audio bus clock
+            - description: audio 26M clock
+            - description: audio intbus clock
+            - description: audio hopping clock
+            - description: audio pll clock
+            - description: mux for pcm_mck
+            - description: audio i2s/pcm mck
+        clock-names:
+          items:
+            - const: bus_ck
+            - const: 26m_ck
+            - const: l_ck
+            - const: aud_ck
+            - const: eg2_ck
+            - const: sel
+            - const: i2s_m
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/clock/mt7986-clk.h>
+
+    afe@11210000 {
+        compatible = "mediatek,mt7986-afe";
+        reg = <0x11210000 0x9000>;
+        interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&infracfg_ao CLK_INFRA_AUD_BUS_CK>,
+                 <&infracfg_ao CLK_INFRA_AUD_26M_CK>,
+                 <&infracfg_ao CLK_INFRA_AUD_L_CK>,
+                 <&infracfg_ao CLK_INFRA_AUD_AUD_CK>,
+                 <&infracfg_ao CLK_INFRA_AUD_EG2_CK>;
+        clock-names = "bus_ck",
+                      "26m_ck",
+                      "l_ck",
+                      "aud_ck",
+                      "eg2_ck";
+        assigned-clocks = <&topckgen CLK_TOP_A1SYS_SEL>,
+                          <&topckgen CLK_TOP_AUD_L_SEL>,
+                          <&topckgen CLK_TOP_A_TUNER_SEL>;
+        assigned-clock-parents = <&topckgen CLK_TOP_APLL2_D4>,
+                                 <&apmixedsys CLK_APMIXED_APLL2>,
+                                 <&topckgen CLK_TOP_APLL2_D4>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt7986-wm8960.yaml
new file mode 100644 (file)
index 0000000..09247ce
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mt7986-wm8960.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT7986 sound card with WM8960 codec
+
+maintainers:
+  - Maso Huang <maso.huang@mediatek.com>
+
+allOf:
+  - $ref: sound-card-common.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt7986-wm8960-sound
+
+  platform:
+    type: object
+    additionalProperties: false
+    properties:
+      sound-dai:
+        description: The phandle of MT7986 platform.
+        maxItems: 1
+    required:
+      - sound-dai
+
+  codec:
+    type: object
+    additionalProperties: false
+    properties:
+      sound-dai:
+        description: The phandle of wm8960 codec.
+        maxItems: 1
+    required:
+      - sound-dai
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - audio-routing
+  - platform
+  - codec
+
+examples:
+  - |
+    sound {
+        compatible = "mediatek,mt7986-wm8960-sound";
+        model = "mt7986-wm8960";
+        audio-routing =
+            "Headphone", "HP_L",
+            "Headphone", "HP_R",
+            "LINPUT1", "AMIC",
+            "RINPUT1", "AMIC";
+
+        platform {
+            sound-dai = <&afe>;
+        };
+
+        codec {
+            sound-dai = <&wm8960>;
+        };
+    };
+
+...
index e6cb711ece773b347562273bbaebafa472e3ec2f..0b92c71d877957ffd990d8a82df1f74865164d58 100644 (file)
@@ -25,6 +25,12 @@ properties:
   reset-names:
     const: audiosys
 
+  memory-region:
+    maxItems: 1
+    description: |
+      Shared memory region for AFE memif.  A "shared-dma-pool".
+      See ../reserved-memory/reserved-memory.yaml for details.
+
   mediatek,topckgen:
     $ref: /schemas/types.yaml#/definitions/phandle
     description: The phandle of the mediatek topckgen controller
@@ -176,6 +182,7 @@ examples:
         interrupts = <GIC_SPI 822 IRQ_TYPE_LEVEL_HIGH 0>;
         resets = <&watchdog 14>;
         reset-names = "audiosys";
+        memory-region = <&snd_dma_mem_reserved>;
         mediatek,topckgen = <&topckgen>;
         mediatek,infracfg = <&infracfg_ao>;
         power-domains = <&spm 13>; //MT8188_POWER_DOMAIN_AUDIO
index 05e532b5d50a664e1145984accead4ff87485f64..43b3b67bdf3bc38137183c99a389a7c5f6378e1e 100644 (file)
@@ -9,23 +9,19 @@ title: MediaTek MT8188 ASoC sound card
 maintainers:
   - Trevor Wu <trevor.wu@mediatek.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     enum:
       - mediatek,mt8188-mt6359-evb
       - mediatek,mt8188-nau8825
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: User specified audio sound card name
-
   audio-routing:
-    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
     description:
-      A list of the connections between audio components. Each entry is a
-      sink/source pair of strings. Valid names could be the input or output
-      widgets of audio components, power supplies, MicBias of codec and the
-      software switch.
+      Valid names could be the input or output widgets of audio components,
+      power supplies, MicBias of codec and the software switch.
 
   mediatek,platform:
     $ref: /schemas/types.yaml#/definitions/phandle
@@ -86,7 +82,7 @@ patternProperties:
     required:
       - link-name
 
-additionalProperties: false
+unevaluatedProperties: false
 
 required:
   - compatible
@@ -96,6 +92,7 @@ examples:
   - |
     sound {
         compatible = "mediatek,mt8188-mt6359-evb";
+        model = "MT6359-EVB";
         mediatek,platform = <&afe>;
         pinctrl-names = "default";
         pinctrl-0 = <&aud_pins_default>;
diff --git a/Documentation/devicetree/bindings/sound/nau8821.txt b/Documentation/devicetree/bindings/sound/nau8821.txt
deleted file mode 100644 (file)
index 7c84e7c..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Nuvoton NAU88L21 audio codec
-
-This device supports I2C only.
-
-Required properties:
-  - compatible : Must be "nuvoton,nau8821"
-
-  - reg : the I2C address of the device. This is either 0x1B (CSB=0) or 0x54 (CSB=1).
-
-Optional properties:
-  - nuvoton,jkdet-enable: Enable jack detection via JKDET pin.
-  - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled,
-      otherwise pin in high impedance state.
-  - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down.
-  - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low.
-
-  - nuvoton,vref-impedance: VREF Impedance selection
-      0 - Open
-      1 - 25 kOhm
-      2 - 125 kOhm
-      3 - 2.5 kOhm
-
-  - nuvoton,micbias-voltage: Micbias voltage level.
-      0 - VDDA
-      1 - VDDA
-      2 - VDDA * 1.1
-      3 - VDDA * 1.2
-      4 - VDDA * 1.3
-      5 - VDDA * 1.4
-      6 - VDDA * 1.53
-      7 - VDDA * 1.53
-
-  - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
-  - 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:
-
-  headset: nau8821@1b {
-      compatible = "nuvoton,nau8821";
-      reg = <0x1b>;
-      interrupt-parent = <&gpio>;
-      interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
-      nuvoton,jkdet-enable;
-      nuvoton,jkdet-pull-enable;
-      nuvoton,jkdet-pull-up;
-      nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
-      nuvoton,vref-impedance = <2>;
-      nuvoton,micbias-voltage = <6>;
-      nuvoton,jack-insert-debounce = <7>;
-      nuvoton,jack-eject-debounce = <7>;
-      nuvoton,dmic-clk-threshold = 3072000;
-  };
diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml
new file mode 100644 (file)
index 0000000..fc2f4ce
--- /dev/null
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/nuvoton,nau8821.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NAU88L21 audio codec
+
+maintainers:
+  - Seven Lee <wtli@nuvoton.com>
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: nuvoton,nau8821
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  nuvoton,jkdet-enable:
+    description: Enable jack detection via JKDET pin.
+    type: boolean
+
+  nuvoton,jkdet-pull-enable:
+    description: Enable JKDET pin pull. If set - pin pull enabled,
+      otherwise pin in high impedance state.
+    type: boolean
+
+  nuvoton,jkdet-pull-up:
+    description: Pull-up JKDET pin. If set then JKDET pin is pull up,
+      otherwise pull down.
+    type: boolean
+
+  nuvoton,key-enable:
+    description: handles key press detection.
+    type: boolean
+
+  nuvoton,jkdet-polarity:
+    description: JKDET pin polarity.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # active high
+      - 1 # active low
+    default: 1
+
+  nuvoton,micbias-voltage:
+    description: MICBIAS output level select.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # VDDA
+      - 1 # VDDA * 1
+      - 2 # VDDA * 1.1
+      - 3 # VDDA * 1.2
+      - 4 # VDDA * 1.3
+      - 5 # VDDA * 1.4
+      - 6 # VDDA * 1.53
+      - 7 # VDDA * 1.53
+    default: 6
+
+  nuvoton,vref-impedance:
+    description: VMID Tie-off impedance select.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum:
+      - 0 # open
+      - 1 # 25KOhms
+      - 2 # 125KOhms
+      - 3 # 2.5KOhms
+    default: 2
+
+  nuvoton,jack-insert-debounce:
+    description: number from 0 to 7 that sets debounce time to 2^(n+2)ms.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 7
+    default: 7
+
+  nuvoton,jack-eject-debounce:
+    description: number from 0 to 7 that sets debounce time to 2^(n+2)ms.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 7
+    default: 0
+
+  nuvoton,dmic-clk-threshold:
+    description: DMIC clock speed expected value. Unit is Hz.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 3072000
+
+  '#sound-dai-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        codec@1b {
+            compatible = "nuvoton,nau8821";
+            reg = <0x1b>;
+            interrupt-parent = <&gpio>;
+            interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+            nuvoton,jkdet-enable;
+            nuvoton,jkdet-pull-enable;
+            nuvoton,jkdet-pull-up;
+            nuvoton,key-enable;
+            nuvoton,jkdet-polarity = <GPIO_ACTIVE_LOW>;
+            nuvoton,micbias-voltage = <6>;
+            nuvoton,vref-impedance = <2>;
+            nuvoton,jack-insert-debounce = <7>;
+            nuvoton,jack-eject-debounce = <0>;
+            nuvoton,dmic-clk-threshold = <3072000>;
+            #sound-dai-cells = <0>;
+        };
+    };
index 65105402a53dde00a0aa8ae84722d66a01fbf613..cb8182bbc491fca5430e1294d81daf204b6a2669 100644 (file)
@@ -21,6 +21,15 @@ properties:
   reg:
     maxItems: 1
 
+  "#sound-dai-cells":
+    const: 0
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: mclk
+
   nuvoton,spk-btl:
     description:
       If set, configure the two loudspeaker outputs as a Bridge Tied Load output
@@ -31,6 +40,9 @@ required:
   - compatible
   - reg
 
+allOf:
+  - $ref: dai-common.yaml#
+
 additionalProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/sound/option,gtm601.yaml b/Documentation/devicetree/bindings/sound/option,gtm601.yaml
new file mode 100644 (file)
index 0000000..ff813d9
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/option,gtm601.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GTM601 UMTS modem audio interface CODEC
+
+maintainers:
+  - kernel@puri.sm
+
+description: >
+  This device has no configuration interface. The sample rate and channels are
+  based on the compatible string
+
+properties:
+  compatible:
+    oneOf:
+      - description: Broadmobi BM818 (48Khz stereo)
+        items:
+          - const: broadmobi,bm818
+          - const: option,gtm601
+      - description: GTM601 (8kHz mono)
+        const: option,gtm601
+
+  '#sound-dai-cells':
+    const: 0
+
+required:
+  - compatible
+
+allOf:
+  - $ref: dai-common.yaml#
+
+additionalProperties: false
+
+examples:
+  - |
+    codec {
+        compatible = "option,gtm601";
+        #sound-dai-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt
deleted file mode 100644 (file)
index e7d17dd..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-msm8916 analog audio CODEC
-
-Bindings for codec Analog IP which is integrated in pmic pm8916,
-
-## Bindings for codec core on pmic:
-
-Required properties
- - compatible = "qcom,pm8916-wcd-analog-codec";
- - reg: represents the slave base address provided to the peripheral.
- - interrupts: List of interrupts in given SPMI peripheral.
- - interrupt-names: Names specified to above list of interrupts in same
-                   order. List of supported interrupt names are:
-  "cdc_spk_cnp_int" - Speaker click and pop interrupt.
-  "cdc_spk_clip_int" - Speaker clip interrupt.
-  "cdc_spk_ocp_int" - Speaker over current protect interrupt.
-  "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1.
-  "mbhc_but_rel_det" - button release interrupt.
-  "mbhc_but_press_det" - button press event
-  "mbhc_ins_rem_det" - jack insert removal detect interrupt.
-  "mbhc_switch_int"    - multi button headset interrupt.
-  "cdc_ear_ocp_int" - Earphone over current protect interrupt.
-  "cdc_hphr_ocp_int" - Headphone R over current protect interrupt.
-  "cdc_hphl_ocp_det" - Headphone L over current protect interrupt.
-  "cdc_ear_cnp_int" - earphone cnp interrupt.
-  "cdc_hphr_cnp_int" - hphr click and pop interrupt.
-  "cdc_hphl_cnp_int" - hphl click and pop interrupt.
-
- - clocks: Handle to mclk.
- - clock-names: should be "mclk"
- - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node.
- - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node.
- - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node.
-
-Optional Properties:
- - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons
-                            detection on headset when the mbhc is powered up
-                            by internal current source, this is a low power.
- - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons
-                             detection on headset when mbhc is powered up
-                              from micbias.
-- qcom,micbias-lvl:  Voltage (mV) for Mic Bias
-- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a
-                                    NO (Normally Open). If not specified, then
-                                    its assumed that hphl pin on jack is NC
-                                    (Normally Closed).
-- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is
-                                   NO (Normally Open). If not specified, then
-                                   its assumed that gnd pin on jack is NC
-                                   (Normally Closed).
-- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor
-                        connected.
-- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor
-                        connected.
-
-Example:
-
-spmi_bus {
-       ...
-       audio-codec@f000{
-               compatible = "qcom,pm8916-wcd-analog-codec";
-               reg = <0xf000 0x200>;
-               reg-names = "pmic-codec-core";
-               clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
-               clock-names = "mclk";
-               qcom,mbhc-vthreshold-low = <75 150 237 450 500>;
-               qcom,mbhc-vthreshold-high = <75 150 237 450 500>;
-               interrupt-parent = <&spmi_bus>;
-               interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
-                            <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
-                            <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
-                            <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
-                            <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
-                            <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
-                            <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
-                            <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
-               interrupt-names = "cdc_spk_cnp_int",
-                                 "cdc_spk_clip_int",
-                                 "cdc_spk_ocp_int",
-                                 "mbhc_ins_rem_det1",
-                                 "mbhc_but_rel_det",
-                                 "mbhc_but_press_det",
-                                 "mbhc_ins_rem_det",
-                                 "mbhc_switch_int",
-                                 "cdc_ear_ocp_int",
-                                 "cdc_hphr_ocp_int",
-                                 "cdc_hphl_ocp_det",
-                                 "cdc_ear_cnp_int",
-                                 "cdc_hphr_cnp_int",
-                                 "cdc_hphl_cnp_int";
-                      vdd-cdc-io-supply = <&pm8916_l5>;
-                      vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>;
-                      vdd-micbias-supply = <&pm8916_l13>;
-                      #sound-dai-cells = <1>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
new file mode 100644 (file)
index 0000000..94e7a18
--- /dev/null
@@ -0,0 +1,153 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,pm8916-wcd-analog-codec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm PM8916 WCD Analog Audio Codec
+
+maintainers:
+  - Konrad Dybcio <konradybcio@kernel.org>
+
+description:
+  The analog WCD audio codec found on Qualcomm PM8916 PMIC.
+
+properties:
+  compatible:
+    const: qcom,pm8916-wcd-analog-codec
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 14
+
+  interrupt-names:
+    items:
+      - const: cdc_spk_cnp_int
+      - const: cdc_spk_clip_int
+      - const: cdc_spk_ocp_int
+      - const: mbhc_ins_rem_det1
+      - const: mbhc_but_rel_det
+      - const: mbhc_but_press_det
+      - const: mbhc_ins_rem_det
+      - const: mbhc_switch_int
+      - const: cdc_ear_ocp_int
+      - const: cdc_hphr_ocp_int
+      - const: cdc_hphl_ocp_det
+      - const: cdc_ear_cnp_int
+      - const: cdc_hphr_cnp_int
+      - const: cdc_hphl_cnp_int
+
+  vdd-cdc-io-supply:
+    description: 1.8V buck supply
+
+  vdd-cdc-tx-rx-cx-supply:
+    description: 1.8V SIDO buck supply
+
+  vdd-micbias-supply:
+    description: micbias supply
+
+  qcom,mbhc-vthreshold-low:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description:
+      Array of 5 threshold voltages in mV for 5-button detection on
+      headset when MBHC is powered by an internal current source.
+    minItems: 5
+    maxItems: 5
+
+  qcom,mbhc-vthreshold-high:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description:
+      Array of 5 threshold voltages in mV for 5-button detection on
+      headset when MBHC is powered from micbias.
+    minItems: 5
+    maxItems: 5
+
+  qcom,micbias-lvl:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Voltage (mV) for Mic Bias
+
+  qcom,hphl-jack-type-normally-open:
+    type: boolean
+    description:
+      True if the HPHL pin on the jack is NO (Normally Open), false if it's
+      NC (Normally Closed).
+
+  qcom,gnd-jack-type-normally-open:
+    type: boolean
+    description:
+      True if the GND pin on the jack is NO (Normally Open), false if it's
+      NC (Normally Closed).
+
+  qcom,micbias1-ext-cap:
+    type: boolean
+    description:
+      True if micbias1 has an external capacitor.
+
+  qcom,micbias2-ext-cap:
+    type: boolean
+    description:
+      True if micbias2 has an external capacitor.
+
+  "#sound-dai-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/spmi/spmi.h>
+
+    pmic@1 {
+      compatible = "qcom,pm8916", "qcom,spmi-pmic";
+      reg = <0x1 SPMI_USID>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      audio-codec@f000 {
+        compatible = "qcom,pm8916-wcd-analog-codec";
+        reg = <0xf000>;
+        qcom,mbhc-vthreshold-low = <75 150 237 450 500>;
+        qcom,mbhc-vthreshold-high = <75 150 237 450 500>;
+        interrupt-parent = <&spmi_bus>;
+        interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+              <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+              <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+              <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+              <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+              <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+              <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+              <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+        interrupt-names = "cdc_spk_cnp_int",
+                          "cdc_spk_clip_int",
+                          "cdc_spk_ocp_int",
+                          "mbhc_ins_rem_det1",
+                          "mbhc_but_rel_det",
+                          "mbhc_but_press_det",
+                          "mbhc_ins_rem_det",
+                          "mbhc_switch_int",
+                          "cdc_ear_ocp_int",
+                          "cdc_hphr_ocp_int",
+                          "cdc_hphl_ocp_det",
+                          "cdc_ear_cnp_int",
+                          "cdc_hphr_cnp_int",
+                          "cdc_hphl_cnp_int";
+        vdd-cdc-io-supply = <&pm8916_l5>;
+        vdd-cdc-tx-rx-cx-supply = <&pm8916_l5>;
+        vdd-micbias-supply = <&pm8916_l13>;
+        #sound-dai-cells = <1>;
+      };
+    };
index 8a821dec952699252310367cec76b9cbb96318af..13a5a0a10fe6cc2751bf2840ce31c95195331c12 100644 (file)
@@ -9,6 +9,20 @@ title: Renesas R-Car Sound Driver
 maintainers:
   - Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 
+definitions:
+  port-def:
+    $ref: audio-graph-port.yaml#/definitions/port-base
+    unevaluatedProperties: false
+    patternProperties:
+      "^endpoint(@[0-9a-f]+)?":
+        $ref: audio-graph-port.yaml#/definitions/endpoint-base
+        properties:
+          playback:
+            $ref: /schemas/types.yaml#/definitions/phandle-array
+          capture:
+            $ref: /schemas/types.yaml#/definitions/phandle-array
+        unevaluatedProperties: false
+
 properties:
 
   compatible:
@@ -77,6 +91,12 @@ properties:
       it must be 1 if your system has audio_clkout0/1/2/3
     enum: [0, 1]
 
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
   clock-frequency:
     description: for audio_clkout0/1/2/3
 
@@ -103,35 +123,9 @@ properties:
     description: List of necessary clock names.
     # details are defined below
 
-  ports:
-    $ref: audio-graph-port.yaml#/definitions/port-base
-    unevaluatedProperties: false
-    patternProperties:
-      '^port(@[0-9a-f]+)?$':
-        $ref: audio-graph-port.yaml#/definitions/port-base
-        unevaluatedProperties: false
-        patternProperties:
-          "^endpoint(@[0-9a-f]+)?":
-            $ref: audio-graph-port.yaml#/definitions/endpoint-base
-            properties:
-              playback:
-                $ref: /schemas/types.yaml#/definitions/phandle-array
-              capture:
-                $ref: /schemas/types.yaml#/definitions/phandle-array
-            unevaluatedProperties: false
-
+  # ports is below
   port:
-    $ref: audio-graph-port.yaml#/definitions/port-base
-    unevaluatedProperties: false
-    patternProperties:
-      "^endpoint(@[0-9a-f]+)?":
-        $ref: audio-graph-port.yaml#/definitions/endpoint-base
-        properties:
-          playback:
-            $ref: /schemas/types.yaml#/definitions/phandle-array
-          capture:
-            $ref: /schemas/types.yaml#/definitions/phandle-array
-        unevaluatedProperties: false
+    $ref: "#/definitions/port-def"
 
   rcar_sound,dvc:
     description: DVC subnode.
@@ -248,8 +242,9 @@ properties:
           - interrupts
     additionalProperties: false
 
+patternProperties:
   # For DAI base
-  rcar_sound,dai:
+  'rcar_sound,dai(@[0-9a-f]+)?$':
     description: DAI subnode.
     type: object
     patternProperties:
@@ -269,6 +264,13 @@ properties:
               - capture
     additionalProperties: false
 
+  'ports(@[0-9a-f]+)?$':
+    $ref: audio-graph-port.yaml#/definitions/port-base
+    unevaluatedProperties: false
+    patternProperties:
+      '^port(@[0-9a-f]+)?$':
+        $ref: "#/definitions/port-def"
+
 required:
   - compatible
   - reg
index 447e013f6e1718cbbee8f914d173aed62c49b75b..5ea0819a261a52826be2e3c1a04f9c6f38fb7643 100644 (file)
@@ -9,6 +9,9 @@ title: Samsung Aries audio complex with WM8994 codec
 maintainers:
   - Jonathan Bakker <xc-racer2@live.ca>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     enum:
@@ -17,10 +20,6 @@ properties:
       # Without FM radio and modem slave
       - samsung,fascinate4g-wm8994
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: The user-visible name of this sound complex.
-
   cpu:
     type: object
     additionalProperties: false
@@ -46,6 +45,7 @@ properties:
 
   samsung,audio-routing:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    deprecated: true
     description: |
       List of the connections between audio
       components;  each entry is a pair of strings, the first being the
@@ -56,6 +56,7 @@ properties:
       or FM In
       For samsung,fascinate4g-wm8994: HP, SPK, RCV, LINE, Main Mic,
       or HeadsetMic
+      Deprecated, use audio-routing.
 
   extcon:
     description: Extcon phandle for dock detection
@@ -87,10 +88,9 @@ properties:
 
 required:
   - compatible
-  - model
   - cpu
   - codec
-  - samsung,audio-routing
+  - audio-routing
   - extcon
   - main-micbias-supply
   - headset-micbias-supply
@@ -98,7 +98,7 @@ required:
   - headset-detect-gpios
   - headset-key-gpios
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -121,7 +121,7 @@ examples:
         headset-detect-gpios = <&gph0 6 GPIO_ACTIVE_HIGH>;
         headset-key-gpios = <&gph3 6 GPIO_ACTIVE_HIGH>;
 
-        samsung,audio-routing =
+        audio-routing =
             "HP", "HPOUT1L",
             "HP", "HPOUT1R",
 
index 31095913e330dd1c00f34118fc80bd37902db22a..6ec80f529d84778449b4a0a576be4b6f8a6fdd6a 100644 (file)
@@ -9,14 +9,13 @@ title: Samsung Midas audio complex with WM1811 codec
 maintainers:
   - Sylwester Nawrocki <s.nawrocki@samsung.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     const: samsung,midas-audio
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: The user-visible name of this sound complex.
-
   cpu:
     type: object
     additionalProperties: false
@@ -38,6 +37,7 @@ properties:
       - sound-dai
 
   samsung,audio-routing:
+    deprecated: true
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
     description: |
       List of the connections between audio components; each entry is
@@ -45,6 +45,7 @@ properties:
       being the connection's source; valid names for sources and sinks are
       the WM1811's pins (as documented in its binding), and the jacks
       on the board: HP, SPK, Main Mic, Sub Mic, Headset Mic.
+      Deprecated, use audio-routing.
 
   mic-bias-supply:
     description: Supply for the micbias on the Main microphone
@@ -62,14 +63,13 @@ properties:
 
 required:
   - compatible
-  - model
   - cpu
   - codec
-  - samsung,audio-routing
+  - audio-routing
   - mic-bias-supply
   - submic-bias-supply
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -84,7 +84,7 @@ examples:
         mic-bias-supply = <&mic_bias_reg>;
         submic-bias-supply = <&submic_bias_reg>;
 
-        samsung,audio-routing =
+        audio-routing =
                 "HP", "HPOUT1L",
                 "HP", "HPOUT1R",
 
index c6751c40e63f5c6517b7d87db31d17828fdc6324..b77284e3e26aa7f58a791656f2ea730189a5f63c 100644 (file)
@@ -10,6 +10,9 @@ maintainers:
   - Krzysztof Kozlowski <krzk@kernel.org>
   - Sylwester Nawrocki <s.nawrocki@samsung.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     oneOf:
@@ -24,10 +27,6 @@ properties:
       - const: samsung,odroid-xu4-audio
         deprecated: true
 
-  model:
-    $ref: /schemas/types.yaml#/definitions/string
-    description: The user-visible name of this sound complex.
-
   assigned-clock-parents: true
   assigned-clock-rates: true
   assigned-clocks: true
@@ -52,6 +51,7 @@ properties:
 
   samsung,audio-routing:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    deprecated: true
     description: |
       List of the connections between audio
       components;  each entry is a pair of strings, the first being the
@@ -61,6 +61,7 @@ properties:
       For Odroid X2: "Headphone Jack", "Mic Jack", "DMIC"
       For Odroid U3, XU3: "Headphone Jack", "Speakers"
       For Odroid XU4: no entries
+      Deprecated, use audio-routing.
 
   samsung,audio-widgets:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
@@ -70,18 +71,17 @@ properties:
 
 required:
   - compatible
-  - model
   - cpu
   - codec
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
     sound {
         compatible = "hardkernel,odroid-xu3-audio";
         model = "Odroid-XU3";
-        samsung,audio-routing =
+        audio-routing =
                 "Headphone Jack", "HPL",
                 "Headphone Jack", "HPR",
                 "IN1", "Mic Jack",
index 491e08019c040c650647c7c38e382ff190623af2..76059259914346996aa81e0301d211b29b048594 100644 (file)
@@ -10,6 +10,9 @@ maintainers:
   - Krzysztof Kozlowski <krzk@kernel.org>
   - Sylwester Nawrocki <s.nawrocki@samsung.com>
 
+allOf:
+  - $ref: sound-card-common.yaml#
+
 properties:
   compatible:
     const: samsung,tm2-audio
@@ -32,6 +35,8 @@ properties:
       being the connection's source; valid names for sources and sinks are the
       WM5110's and MAX98504's pins and the jacks on the board: HP, SPK, Main
       Mic, Sub Mic, Third Mic, Headset Mic.
+      Deprecated, use audio-routing.
+    deprecated: true
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
 
   i2s-controller:
@@ -44,20 +49,15 @@ properties:
   mic-bias-gpios:
     description: GPIO pin that enables the Main Mic bias regulator.
 
-  model:
-    description: The user-visible name of this sound complex.
-    $ref: /schemas/types.yaml#/definitions/string
-
 required:
   - compatible
   - audio-amplifier
   - audio-codec
-  - samsung,audio-routing
+  - audio-routing
   - i2s-controller
   - mic-bias-gpios
-  - model
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -70,7 +70,7 @@ examples:
         audio-amplifier = <&max98504>;
         mic-bias-gpios = <&gpr3 2 GPIO_ACTIVE_HIGH>;
         model = "wm5110";
-        samsung,audio-routing = "HP", "HPOUT1L",
+        audio-routing = "HP", "HPOUT1L",
                                 "HP", "HPOUT1R",
                                 "SPK", "SPKOUT",
                                 "SPKOUT", "HPOUT2L",
index b05e05c81cc4d2d035566982ce9a4ebbefcfc229..59ac2d1d1ccfa4ce6b38a0c0db82243a19619320 100644 (file)
@@ -148,6 +148,15 @@ definitions:
     required:
       - sound-dai
 
+  additional-devs:
+    type: object
+    description:
+      Additional devices used by the simple audio card.
+    patternProperties:
+      '^iio-aux(-.+)?$':
+        type: object
+        $ref: audio-iio-aux.yaml#
+
 properties:
   compatible:
     contains:
@@ -187,6 +196,8 @@ properties:
     $ref: "#/definitions/mclk-fs"
   simple-audio-card,aux-devs:
     $ref: "#/definitions/aux-devs"
+  simple-audio-card,additional-devs:
+    $ref: "#/definitions/additional-devs"
   simple-audio-card,convert-rate:
     $ref: "#/definitions/convert-rate"
   simple-audio-card,convert-channels:
@@ -359,6 +370,48 @@ examples:
         };
     };
 
+# --------------------
+# route audio to/from a codec through an amplifier
+# designed with a potentiometer driven by IIO:
+# --------------------
+  - |
+    sound {
+        compatible = "simple-audio-card";
+
+        simple-audio-card,aux-devs = <&amp_in>, <&amp_out>;
+        simple-audio-card,routing =
+            "CODEC LEFTIN", "AMP_IN LEFT OUT",
+            "CODEC RIGHTIN", "AMP_IN RIGHT OUT",
+            "AMP_OUT LEFT IN", "CODEC LEFTOUT",
+            "AMP_OUT RIGHT IN", "CODEC RIGHTOUT";
+
+        simple-audio-card,additional-devs {
+            amp_out: iio-aux-out {
+                compatible = "audio-iio-aux";
+                io-channels = <&pot_out 0>, <&pot_out 1>;
+                io-channel-names = "LEFT", "RIGHT";
+                snd-control-invert-range = <1 1>;
+                sound-name-prefix = "AMP_OUT";
+            };
+
+            amp_in: iio_aux-in {
+                compatible = "audio-iio-aux";
+                io-channels = <&pot_in 0>, <&pot_in 1>;
+                io-channel-names = "LEFT", "RIGHT";
+                sound-name-prefix = "AMP_IN";
+            };
+        };
+
+        simple-audio-card,cpu {
+            sound-dai = <&cpu>;
+        };
+
+        simple-audio-card,codec {
+            sound-dai = <&codec>;
+            clocks = <&clocks>;
+        };
+    };
+
 # --------------------
 # Sampling Rate Conversion
 # --------------------
diff --git a/Documentation/devicetree/bindings/sound/sound-card-common.yaml b/Documentation/devicetree/bindings/sound/sound-card-common.yaml
new file mode 100644 (file)
index 0000000..3a94117
--- /dev/null
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/sound-card-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Board Sound Card Common Properties
+
+maintainers:
+  - Mark Brown <broonie@kernel.org>
+
+properties:
+  audio-routing:
+    $ref: /schemas/types.yaml#/definitions/non-unique-string-array
+    description: |
+      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.
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: User specified audio sound card name
+
+required:
+  - model
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8904.yaml
new file mode 100644 (file)
index 0000000..329260c
--- /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/wlf,wm8904.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wolfson WM8904/WM8912 audio codecs
+
+maintainers:
+  - patches@opensource.cirrus.com
+
+description: |
+  Pins on the device (for linking into audio routes):
+  IN1L, IN1R, IN2L, IN2R, IN3L, IN3R, HPOUTL, HPOUTR, LINEOUTL, LINEOUTR,
+  MICBIAS
+
+properties:
+  compatible:
+    enum:
+      - wlf,wm8904
+      - wlf,wm8912
+
+  reg:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 0
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: mclk
+
+  AVDD-supply: true
+  CPVDD-supply: true
+  DBVDD-supply: true
+  DCVDD-supply: true
+  MICVDD-supply: true
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - AVDD-supply
+  - CPVDD-supply
+  - DBVDD-supply
+  - DCVDD-supply
+  - MICVDD-supply
+
+allOf:
+  - $ref: dai-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        codec@1a {
+            compatible = "wlf,wm8904";
+            reg = <0x1a>;
+            clocks = <&pck0>;
+            clock-names = "mclk";
+            AVDD-supply = <&reg_1p8v>;
+            CPVDD-supply = <&reg_1p8v>;
+            DBVDD-supply = <&reg_1p8v>;
+            DCVDD-supply = <&reg_1p8v>;
+            MICVDD-supply = <&reg_1p8v>;
+        };
+    };
index ee8eba7f010497eb37c403cb3795f8a4a1b1b543..62e62c335d07d19a4471827adb8bd20230123dbe 100644 (file)
@@ -26,6 +26,21 @@ properties:
   '#sound-dai-cells':
     const: 0
 
+  AVDD-supply:
+    description: Analogue supply.
+
+  DBVDD-supply:
+    description: Digital Buffer Supply.
+
+  DCVDD-supply:
+    description: Digital Core Supply.
+
+  SPKVDD1-supply:
+    description: Supply for speaker drivers 1.
+
+  SPKVDD2-supply:
+    description: Supply for speaker drivers 2.
+
   wlf,capless:
     type: boolean
     description:
@@ -84,5 +99,10 @@ examples:
             wlf,hp-cfg = <3 2 3>;
             wlf,gpio-cfg = <1 3>;
             wlf,shared-lrclk;
+            DCVDD-supply = <&reg_audio>;
+            DBVDD-supply = <&reg_audio>;
+            AVDD-supply = <&reg_audio>;
+            SPKVDD1-supply = <&reg_audio>;
+            SPKVDD2-supply = <&reg_audio>;
         };
     };
diff --git a/Documentation/devicetree/bindings/sound/wm8904.txt b/Documentation/devicetree/bindings/sound/wm8904.txt
deleted file mode 100644 (file)
index 66bf261..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-WM8904 audio CODEC
-
-This device supports I2C only.
-
-Required properties:
-  - compatible: "wlf,wm8904" or "wlf,wm8912"
-  - reg: the I2C address of the device.
-  - clock-names: "mclk"
-  - clocks: reference to
-    <Documentation/devicetree/bindings/clock/clock-bindings.txt>
-
-Pins on the device (for linking into audio routes):
-
-  * IN1L
-  * IN1R
-  * IN2L
-  * IN2R
-  * IN3L
-  * IN3R
-  * HPOUTL
-  * HPOUTR
-  * LINEOUTL
-  * LINEOUTR
-  * MICBIAS
-
-Examples:
-
-codec: wm8904@1a {
-       compatible = "wlf,wm8904";
-       reg = <0x1a>;
-       clocks = <&pck0>;
-       clock-names = "mclk";
-};
index f8b2c4dc81701119d80b0ac2a63ae5fafe62dcff..207a22bcaf4aad3a0745fe4c4a521d7dfdcdca75 100644 (file)
@@ -3,15 +3,6 @@
 Digital TV Common functions
 ---------------------------
 
-Math functions
-~~~~~~~~~~~~~~
-
-Provide some commonly-used math functions, usually required in order to
-estimate signal strength and signal to noise measurements in dB.
-
-.. kernel-doc:: include/media/dvb_math.h
-
-
 DVB devices
 ~~~~~~~~~~~
 
index 0b5ecca0b39b9eec83234ab36f3da7f7a2c20413..3aaec9532ff9852bfa8108815b5374b1127e5ea4 100644 (file)
@@ -21061,6 +21061,39 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
 F:     sound/soc/ti/
 
+TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS
+M:     Shenghao Ding <shenghao-ding@ti.com>
+M:     Kevin Lu <kevin-lu@ti.com>
+M:     Baojun Xu <x1077012@ti.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/tas2552.txt
+F:     Documentation/devicetree/bindings/sound/tas2562.yaml
+F:     Documentation/devicetree/bindings/sound/tas2770.yaml
+F:     Documentation/devicetree/bindings/sound/tas27xx.yaml
+F:     Documentation/devicetree/bindings/sound/ti,pcm1681.txt
+F:     Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
+F:     Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
+F:     Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
+F:     Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
+F:     Documentation/devicetree/bindings/sound/tpa6130a2.txt
+F:     include/sound/tas2*.h
+F:     include/sound/tlv320*.h
+F:     include/sound/tpa6130a2-plat.h
+F:     sound/pci/hda/tas2781_hda_i2c.c
+F:     sound/soc/codecs/pcm1681.c
+F:     sound/soc/codecs/pcm1789*.*
+F:     sound/soc/codecs/pcm179x*.*
+F:     sound/soc/codecs/pcm186x*.*
+F:     sound/soc/codecs/pcm3008.*
+F:     sound/soc/codecs/pcm3060*.*
+F:     sound/soc/codecs/pcm3168a*.*
+F:     sound/soc/codecs/pcm5102a.c
+F:     sound/soc/codecs/pcm512x*.*
+F:     sound/soc/codecs/tas2*.*
+F:     sound/soc/codecs/tlv320*.*
+F:     sound/soc/codecs/tpa6130a2.*
+
 TEXAS INSTRUMENTS DMA DRIVERS
 M:     Peter Ujfalusi <peter.ujfalusi@gmail.com>
 L:     dmaengine@vger.kernel.org
index 6a9aa97373d37f2403d5e1bfa4e9121017beaa33..49b70c70dc6960b79cc69e5f382a9fdd3e8b9c2e 100644 (file)
@@ -978,7 +978,8 @@ static int cs_dsp_create_control(struct cs_dsp *dsp,
                    ctl->alg_region.alg == alg_region->alg &&
                    ctl->alg_region.type == alg_region->type) {
                        if ((!subname && !ctl->subname) ||
-                           (subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
+                           (subname && (ctl->subname_len == subname_len) &&
+                            !strncmp(ctl->subname, subname, ctl->subname_len))) {
                                if (!ctl->enabled)
                                        ctl->enabled = 1;
                                return 0;
index 5261526d286f5100fb62971450e78e793e241a39..a8dec24b146b3251bda5a3ee8e0b9f3556d68c29 100644 (file)
@@ -2615,9 +2615,13 @@ static int vc4_hdmi_audio_cpu_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops vc4_snd_dai_ops = {
+       .probe  = vc4_hdmi_audio_cpu_dai_probe,
+};
+
 static struct snd_soc_dai_driver vc4_hdmi_audio_cpu_dai_drv = {
        .name = "vc4-hdmi-cpu-dai",
-       .probe  = vc4_hdmi_audio_cpu_dai_probe,
+       .ops = &vc4_snd_dai_ops,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
index 872fd5c241476eadb4ae4062ac3f59a61a0da970..7a1f6713318a36cdd42815675fd9ff9edd0461fe 100644 (file)
@@ -5,9 +5,10 @@
  */
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/slab.h>
-#include <linux/mutex.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/iio-opaque.h>
@@ -849,15 +850,14 @@ static int iio_channel_read_max(struct iio_channel *chan,
                                int *val, int *val2, int *type,
                                enum iio_chan_info_enum info)
 {
-       int unused;
        const int *vals;
        int length;
        int ret;
 
-       if (!val2)
-               val2 = &unused;
-
        ret = iio_channel_read_avail(chan, &vals, type, &length, info);
+       if (ret < 0)
+               return ret;
+
        switch (ret) {
        case IIO_AVAIL_RANGE:
                switch (*type) {
@@ -866,7 +866,8 @@ static int iio_channel_read_max(struct iio_channel *chan,
                        break;
                default:
                        *val = vals[4];
-                       *val2 = vals[5];
+                       if (val2)
+                               *val2 = vals[5];
                }
                return 0;
 
@@ -875,20 +876,16 @@ static int iio_channel_read_max(struct iio_channel *chan,
                        return -EINVAL;
                switch (*type) {
                case IIO_VAL_INT:
-                       *val = vals[--length];
-                       while (length) {
-                               if (vals[--length] > *val)
-                                       *val = vals[length];
-                       }
+                       *val = max_array(vals, length);
                        break;
                default:
-                       /* FIXME: learn about max for other iio values */
+                       /* TODO: learn about max for other iio values */
                        return -EINVAL;
                }
                return 0;
 
        default:
-               return ret;
+               return -EINVAL;
        }
 }
 
@@ -912,6 +909,69 @@ err_unlock:
 }
 EXPORT_SYMBOL_GPL(iio_read_max_channel_raw);
 
+static int iio_channel_read_min(struct iio_channel *chan,
+                               int *val, int *val2, int *type,
+                               enum iio_chan_info_enum info)
+{
+       const int *vals;
+       int length;
+       int ret;
+
+       ret = iio_channel_read_avail(chan, &vals, type, &length, info);
+       if (ret < 0)
+               return ret;
+
+       switch (ret) {
+       case IIO_AVAIL_RANGE:
+               switch (*type) {
+               case IIO_VAL_INT:
+                       *val = vals[0];
+                       break;
+               default:
+                       *val = vals[0];
+                       if (val2)
+                               *val2 = vals[1];
+               }
+               return 0;
+
+       case IIO_AVAIL_LIST:
+               if (length <= 0)
+                       return -EINVAL;
+               switch (*type) {
+               case IIO_VAL_INT:
+                       *val = min_array(vals, length);
+                       break;
+               default:
+                       /* TODO: learn about min for other iio values */
+                       return -EINVAL;
+               }
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+int iio_read_min_channel_raw(struct iio_channel *chan, int *val)
+{
+       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
+       int ret;
+       int type;
+
+       mutex_lock(&iio_dev_opaque->info_exist_lock);
+       if (!chan->indio_dev->info) {
+               ret = -ENODEV;
+               goto err_unlock;
+       }
+
+       ret = iio_channel_read_min(chan, val, NULL, &type, IIO_CHAN_INFO_RAW);
+err_unlock:
+       mutex_unlock(&iio_dev_opaque->info_exist_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_read_min_channel_raw);
+
 int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
index 62b028ded9f784438175969610608e60f35a9353..1cb3ca67bed9ada84dc179e8e3b5a97f21922ee8 100644 (file)
@@ -8,6 +8,6 @@ dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
 
 dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o                 \
                 dvb_ca_en50221.o dvb_frontend.o                \
-                $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o
+                $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y)
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb-core/dvb_math.c b/drivers/media/dvb-core/dvb_math.c
deleted file mode 100644 (file)
index dc90564..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/bug.h>
-#include <media/dvb_math.h>
-
-static const unsigned short logtable[256] = {
-       0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
-       0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
-       0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
-       0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
-       0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
-       0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
-       0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
-       0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
-       0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
-       0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
-       0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
-       0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
-       0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
-       0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
-       0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
-       0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
-       0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
-       0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
-       0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
-       0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
-       0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
-       0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
-       0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
-       0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
-       0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
-       0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
-       0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
-       0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
-       0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
-       0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
-       0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
-       0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
-unsigned int intlog2(u32 value)
-{
-       /**
-        *      returns: log2(value) * 2^24
-        *      wrong result if value = 0 (log2(0) is undefined)
-        */
-       unsigned int msb;
-       unsigned int logentry;
-       unsigned int significand;
-       unsigned int interpolation;
-
-       if (unlikely(value == 0)) {
-               WARN_ON(1);
-               return 0;
-       }
-
-       /* first detect the msb (count begins at 0) */
-       msb = fls(value) - 1;
-
-       /**
-        *      now we use a logtable after the following method:
-        *
-        *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
-        *      where x = msb and therefore 1 <= y < 2
-        *      first y is determined by shifting the value left
-        *      so that msb is bit 31
-        *              0x00231f56 -> 0x8C7D5800
-        *      the result is y * 2^31 -> "significand"
-        *      then the highest 9 bits are used for a table lookup
-        *      the highest bit is discarded because it's always set
-        *      the highest nine bits in our example are 100011000
-        *      so we would use the entry 0x18
-        */
-       significand = value << (31 - msb);
-       logentry = (significand >> 23) & 0xff;
-
-       /**
-        *      last step we do is interpolation because of the
-        *      limitations of the log table the error is that part of
-        *      the significand which isn't used for lookup then we
-        *      compute the ratio between the error and the next table entry
-        *      and interpolate it between the log table entry used and the
-        *      next one the biggest error possible is 0x7fffff
-        *      (in our example it's 0x7D5800)
-        *      needed value for next table entry is 0x800000
-        *      so the interpolation is
-        *      (error / 0x800000) * (logtable_next - logtable_current)
-        *      in the implementation the division is moved to the end for
-        *      better accuracy there is also an overflow correction if
-        *      logtable_next is 256
-        */
-       interpolation = ((significand & 0x7fffff) *
-                       ((logtable[(logentry + 1) & 0xff] -
-                         logtable[logentry]) & 0xffff)) >> 15;
-
-       /* now we return the result */
-       return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
-}
-EXPORT_SYMBOL(intlog2);
-
-unsigned int intlog10(u32 value)
-{
-       /**
-        *      returns: log10(value) * 2^24
-        *      wrong result if value = 0 (log10(0) is undefined)
-        */
-       u64 log;
-
-       if (unlikely(value == 0)) {
-               WARN_ON(1);
-               return 0;
-       }
-
-       log = intlog2(value);
-
-       /**
-        *      we use the following method:
-        *      log10(x) = log2(x) * log10(2)
-        */
-
-       return (log * 646456993) >> 31;
-}
-EXPORT_SYMBOL(intlog10);
index 3b9b9424fe1af95387916963234679a651c73c12..bba7a9693a2355d588f012a651bd5bb01b5cdb1d 100644 (file)
@@ -12,7 +12,7 @@
 #define AF9013_PRIV_H
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "af9013.h"
 #include <linux/firmware.h>
 #include <linux/i2c-mux.h>
index 0e64da0cdeabb19246ba29a212dd5a6682138596..7560da75ef00a04aaaa5f4fb557b140128f95432 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/math64.h>
 #include <linux/regmap.h>
 #include <linux/kernel.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 struct reg_val {
        u32 reg;
index 9b4d9cf8563dc762fdab7f528e9b9cbf89e69070..605320bbc12b674d32ebda15b085e460b8493ac9 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/dvb/version.h>
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "cxd2820r.h"
 #include <linux/gpio/driver.h> /* For gpio_chip */
 #include <linux/math64.h>
index 5431f922f55e4806de3c8021781a13cf361dfa32..ef403a9fb7531a257b848914ed8d77aff2fc8f3b 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/dynamic_debug.h>
 #include <linux/kernel.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include <media/dvb_frontend.h>
 #include "cxd2841er.h"
 #include "cxd2841er_priv.h"
index 604580bf7cf781da29aeb81de80f4dd2a2d02e9d..4e173dd87ecfb44de9c944590c719544b6c8e845 100644 (file)
@@ -11,7 +11,7 @@
 #include "cxd2880_tnrdmd_dvbt2.h"
 #include "cxd2880_tnrdmd_dvbt2_mon.h"
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 static const int ref_dbm_1000[4][8] = {
        {-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
index fedc3b4a2fa08a234ba903e35ae530a15d20805a..86d5a1e4022a80a5384c9a7c43f9a9719c4e30eb 100644 (file)
@@ -11,7 +11,7 @@
 #include "cxd2880_tnrdmd_dvbt.h"
 #include "cxd2880_tnrdmd_dvbt_mon.h"
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 static const int ref_dbm_1000[3][5] = {
        {-93000, -91000, -90000, -89000, -88000},
index d5b1b3788e3927d3da81f991c7cabc92c46542b4..f67b6d24b8d46ce26b4635f613933cdd3e304149 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/spi/spi.h>
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 #include "cxd2880.h"
 #include "cxd2880_tnrdmd_mon.h"
index a90d2f51868ff0b9d9e2add77bca6a9f8f087895..b791e687d2e2f29047df54d6cd088cc88a955e50 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/mutex.h>
 #include <asm/div64.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include <media/dvb_frontend.h>
 
 #include "dib7000p.h"
index fe19d127abb3f35727ac816564b766d532adde91..2abda7d1cb6e35fc3da757dc3e66945a94cd8213 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/mutex.h>
 #include <asm/div64.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 #include <media/dvb_frontend.h>
 
index 914ca820c174b05e2a110c2ba0ff7476e03b01c6..1c57587a917a288b3445ffd2a77c7dbd7085590a 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include <media/dvb_frontend.h>
 
 #include "dib9000.h"
index 3301ef75d44173692d39fca0656e489987e3ea83..6ad4f202f1bf538879eef447c16438e84000d106 100644 (file)
@@ -20,7 +20,7 @@
 #include <media/dvb_frontend.h>
 #include "drxk.h"
 #include "drxk_hard.h"
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 static int power_down_dvbt(struct drxk_state *state, bool set_power_mode);
 static int power_down_qam(struct drxk_state *state);
index 62d743988919663d62189e9de4d58c68ffb63fa3..c15d3735d34c0d72c43e5ae440d9621b9ab2fac0 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/div64.h>
 #include <linux/dvb/frontend.h>
 #include <linux/slab.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "lgdt3305.h"
 
 static int debug;
index 70258884126b0f0114cf21bc17a5e524c2ce3b92..3c6650f6e9a37ce77a7124ee88249d56770749ae 100644 (file)
@@ -12,7 +12,7 @@
 #include <asm/div64.h>
 #include <linux/kernel.h>
 #include <linux/dvb/frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "lgdt3306a.h"
 #include <linux/i2c-mux.h>
 
index 83565209c3b1ee59965896af970953826dd9f036..97a10996c7facaa50e8f69f82dc8f33d75d31fc3 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/byteorder.h>
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "lgdt330x_priv.h"
 #include "lgdt330x.h"
 
index aa5306f40201eac367d1386202a95de1ecdb241d..594ad9cbc2cc6908800d85f7856208bf95b58c83 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <media/dvb_frontend.h>
 #include "m88ds3103.h"
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include <linux/firmware.h>
 #include <linux/i2c-mux.h>
 #include <linux/regmap.h>
index 2ce5692bc22c4a364f0d1d50b2ff0b9897886f58..db2921c736af94ea5956acfc2ffe2ed955551dac 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/of_device.h>
 #include <linux/regmap.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 #include "mn88443x.h"
 
index 337562723f88d12a2b962a2150d288a7eee917b1..41f14bd67bfdbce30fdd0ef65937aa3a696923c3 100644 (file)
@@ -9,7 +9,7 @@
 #define MN88472_PRIV_H
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "mn88472.h"
 #include <linux/firmware.h>
 #include <linux/regmap.h>
index eca7f4e2b769325f6ee01cf78421ea9387750884..e9daaacfa22fd7131e59ae7d97cd4b88db4559bb 100644 (file)
@@ -9,7 +9,7 @@
 #define MN88473_PRIV_H
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "mn88473.h"
 #include <linux/math64.h>
 #include <linux/firmware.h>
index 24de1b115158387e298a307ec52b1b5a0c461c95..355f3598627bff200d1d5f3fcb4b4e9d0fb1f27f 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include <media/dvb_frontend.h>
 #include "or51132.h"
 
index ddcaea5c9941f41c2c0e5d2edcc676e1f0ed2f63..ae732dc5116e2fd61d39526f1b16200598d342fc 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include <media/dvb_frontend.h>
 #include "or51211.h"
 
index fae78ed785221c782cfa8d95692d419a1d787fbf..ae1fc24a4d84efd4e67a2fe8e2147c4a4999bda9 100644 (file)
@@ -9,7 +9,7 @@
 #define RTL2830_PRIV_H
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "rtl2830.h"
 #include <linux/i2c-mux.h>
 #include <linux/math64.h>
index 5f79f95b9475ed9aa5311db57a92eb75b2587fb7..f11ba038d5f0e868cef4a62cb2479e429be719e8 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/bitops.h>
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "rtl2832.h"
 
 struct rtl2832_dev {
index 72810efd1a96a1438e36274044226be57fd9c987..434d003bf397ccd7c49082efacc058f05fee25aa 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/regmap.h>
 
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "si2165_priv.h"
 #include "si2165.h"
 
index 95e376f23506fb84806df53f1f55470833c5ea26..a93f40617469627c57dada1de2aec7a03d0c3206 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 
 #include "stv0367.h"
 #include "stv0367_defs.h"
index 879f028f96828974013ad94a81637a57bcf811a5..1f8cbf45554a716beecdde29b07d8cb33753e660 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/math64.h>
 #include <linux/dvb/frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "tc90522.h"
 
 #define TC90522_I2C_THRU_REG 0xfe
index 0b3f6999515e358e49bc04b647e4df397e954cd5..3cb4e5270e4fab9817f1fbe3131ee39d2ec39ece 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/math64.h>
 #include <asm/div64.h>
 #include <media/dvb_frontend.h>
-#include <media/dvb_math.h>
+#include <linux/int_log.h>
 #include "tda10048.h"
 
 #define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
index bbaeabd04b0d2fe054c05c1fc00be042b2c84b40..6731d7dc1a2aa59aa9c4e8e407270f9ab4dc71c8 100644 (file)
@@ -349,6 +349,7 @@ unsigned long devm_get_free_pages(struct device *dev,
                                  gfp_t gfp_mask, unsigned int order);
 void devm_free_pages(struct device *dev, unsigned long addr);
 
+#ifdef CONFIG_HAS_IOMEM
 void __iomem *devm_ioremap_resource(struct device *dev,
                                    const struct resource *res);
 void __iomem *devm_ioremap_resource_wc(struct device *dev,
@@ -357,6 +358,31 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev,
 void __iomem *devm_of_iomap(struct device *dev,
                            struct device_node *node, int index,
                            resource_size_t *size);
+#else
+
+static inline
+void __iomem *devm_ioremap_resource(struct device *dev,
+                                   const struct resource *res)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline
+void __iomem *devm_ioremap_resource_wc(struct device *dev,
+                                      const struct resource *res)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline
+void __iomem *devm_of_iomap(struct device *dev,
+                           struct device_node *node, int index,
+                           resource_size_t *size)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+#endif
 
 /* allows to add/remove a custom action to devres stack */
 void devm_remove_action(struct device *dev, void (*action)(void *), void *data);
index 4f7895a3b73c70485ea6709739f373f736d22662..1f176a2683fee28471e4982d551967efdd693bc4 100644 (file)
@@ -37,17 +37,11 @@ struct imx_dsp_ipc {
 
 static inline void imx_dsp_set_data(struct imx_dsp_ipc *ipc, void *data)
 {
-       if (!ipc)
-               return;
-
        ipc->private_data = data;
 }
 
 static inline void *imx_dsp_get_data(struct imx_dsp_ipc *ipc)
 {
-       if (!ipc)
-               return NULL;
-
        return ipc->private_data;
 }
 
index 28fd313340b83e4a6c8e13b6d7bcdcad963bef0d..5b1d16fa3f568cf9f0cb462ed1a3c41890e53371 100644 (file)
@@ -46,17 +46,11 @@ struct mtk_adsp_ipc {
 
 static inline void mtk_adsp_ipc_set_data(struct mtk_adsp_ipc *ipc, void *data)
 {
-       if (!ipc)
-               return;
-
        ipc->private_data = data;
 }
 
 static inline void *mtk_adsp_ipc_get_data(struct mtk_adsp_ipc *ipc)
 {
-       if (!ipc)
-               return NULL;
-
        return ipc->private_data;
 }
 
index 6802596b017c9cd57f4b94dc649898bbcdf2db1c..e9910b41d48e66d08c8536fcbfcf402552bbbac2 100644 (file)
@@ -201,8 +201,9 @@ struct iio_dev
  * @chan:              The channel being queried.
  * @val:               Value read back.
  *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units required.
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  */
 int iio_read_channel_raw(struct iio_channel *chan,
                         int *val);
@@ -212,8 +213,9 @@ int iio_read_channel_raw(struct iio_channel *chan,
  * @chan:              The channel being queried.
  * @val:               Value read back.
  *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units required.
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  *
  * In opposit to the normal iio_read_channel_raw this function
  * returns the average of multiple reads.
@@ -281,8 +283,9 @@ int iio_read_channel_attribute(struct iio_channel *chan, int *val,
  * @chan:              The channel being queried.
  * @val:               Value being written.
  *
- * Note raw writes to iio channels are in dac counts and hence
- * scale will need to be applied if standard units required.
+ * Note that for raw writes to iio channels, if the value provided is
+ * in standard units, the affect of the scale and offset must be removed
+ * as (value / scale) - offset.
  */
 int iio_write_channel_raw(struct iio_channel *chan, int val);
 
@@ -292,11 +295,24 @@ int iio_write_channel_raw(struct iio_channel *chan, int val);
  * @chan:              The channel being queried.
  * @val:               Value read back.
  *
- * Note raw reads from iio channels are in adc counts and hence
- * scale will need to be applied if standard units are required.
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  */
 int iio_read_max_channel_raw(struct iio_channel *chan, int *val);
 
+/**
+ * iio_read_min_channel_raw() - read minimum available raw value from a given
+ *                             channel, i.e. the minimum possible value.
+ * @chan:              The channel being queried.
+ * @val:               Value read back.
+ *
+ * Note, if standard units are required, raw reads from iio channels
+ * need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
+ */
+int iio_read_min_channel_raw(struct iio_channel *chan, int *val);
+
 /**
  * iio_read_avail_channel_raw() - read available raw values from a given channel
  * @chan:              The channel being queried.
@@ -308,8 +324,9 @@ int iio_read_max_channel_raw(struct iio_channel *chan, int *val);
  * For ranges, three vals are always returned; min, step and max.
  * For lists, all the possible values are enumerated.
  *
- * Note raw available values from iio channels are in adc counts and
- * hence scale will need to be applied if standard units are required.
+ * Note, if standard units are required, raw available values from iio
+ * channels need the offset (default 0) and scale (default 1) to be applied
+ * as (raw + offset) * scale.
  */
 int iio_read_avail_channel_raw(struct iio_channel *chan,
                               const int **vals, int *length);
diff --git a/include/linux/int_log.h b/include/linux/int_log.h
new file mode 100644 (file)
index 0000000..0a6f58c
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Provides fixed-point logarithm operations.
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ */
+
+#ifndef __LINUX_INT_LOG_H
+#define __LINUX_INT_LOG_H
+
+#include <linux/types.h>
+
+/**
+ * intlog2 - computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * @value: The value (must be != 0)
+ *
+ * to use rational values you can use the following method:
+ *
+ *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * Some usecase examples:
+ *
+ *     intlog2(8) will give 3 << 24 = 3 * 2^24
+ *
+ *     intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ *
+ *     intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ *
+ * return: log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * intlog10 - computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * @value: The value (must be != 0)
+ *
+ * to use rational values you can use the following method:
+ *
+ *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * An usecase example:
+ *
+ *     intlog10(1000) will give 3 << 24 = 3 * 2^24
+ *
+ *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * return: log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
index 396df1121bffba9e3247018ec49256f25774b76d..798c6963909fcbd6ac0df2b4cb7c20fe4d0bbf3c 100644 (file)
  */
 #define max_t(type, x, y)      __careful_cmp((type)(x), (type)(y), >)
 
+/*
+ * Remove a const qualifier from integer types
+ * _Generic(foo, type-name: association, ..., default: association) performs a
+ * comparison against the foo type (not the qualified type).
+ * Do not use the const keyword in the type-name as it will not match the
+ * unqualified type of foo.
+ */
+#define __unconst_integer_type_cases(type)     \
+       unsigned type:  (unsigned type)0,       \
+       signed type:    (signed type)0
+
+#define __unconst_integer_typeof(x) typeof(                    \
+       _Generic((x),                                           \
+               char: (char)0,                                  \
+               __unconst_integer_type_cases(char),             \
+               __unconst_integer_type_cases(short),            \
+               __unconst_integer_type_cases(int),              \
+               __unconst_integer_type_cases(long),             \
+               __unconst_integer_type_cases(long long),        \
+               default: (x)))
+
+/*
+ * Do not check the array parameter using __must_be_array().
+ * In the following legit use-case where the "array" passed is a simple pointer,
+ * __must_be_array() will return a failure.
+ * --- 8< ---
+ * int *buff
+ * ...
+ * min = min_array(buff, nb_items);
+ * --- 8< ---
+ *
+ * The first typeof(&(array)[0]) is needed in order to support arrays of both
+ * 'int *buff' and 'int buff[N]' types.
+ *
+ * The array can be an array of const items.
+ * typeof() keeps the const qualifier. Use __unconst_integer_typeof() in order
+ * to discard the const qualifier for the __element variable.
+ */
+#define __minmax_array(op, array, len) ({                              \
+       typeof(&(array)[0]) __array = (array);                          \
+       typeof(len) __len = (len);                                      \
+       __unconst_integer_typeof(__array[0]) __element = __array[--__len]; \
+       while (__len--)                                                 \
+               __element = op(__element, __array[__len]);              \
+       __element; })
+
+/**
+ * min_array - return minimum of values present in an array
+ * @array: array
+ * @len: array length
+ *
+ * Note that @len must not be zero (empty array).
+ */
+#define min_array(array, len) __minmax_array(min, array, len)
+
+/**
+ * max_array - return maximum of values present in an array
+ * @array: array
+ * @len: array length
+ *
+ * Note that @len must not be zero (empty array).
+ */
+#define max_array(array, len) __minmax_array(max, array, len)
+
 /**
  * clamp_t - return a value clamped to a given range using a given type
  * @type: the type of variable to use
index 2dc75df1437fbe3302c9caf7261cf66297f784a7..a6411aa4c3312e36f5ade07a485ab36fff1f345d 100644 (file)
 
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_EESSC      0x0008
+#define PCI_DEVICE_ID_INTEL_HDA_CML_LP 0x02c8
 #define PCI_DEVICE_ID_INTEL_PXHD_0     0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1     0x0321
 #define PCI_DEVICE_ID_INTEL_PXH_0      0x0329
 #define PCI_DEVICE_ID_INTEL_82424      0x0483
 #define PCI_DEVICE_ID_INTEL_82378      0x0484
 #define PCI_DEVICE_ID_INTEL_82425      0x0486
+#define PCI_DEVICE_ID_INTEL_HDA_CML_H  0x06c8
 #define PCI_DEVICE_ID_INTEL_MRST_SD0   0x0807
 #define PCI_DEVICE_ID_INTEL_MRST_SD1   0x0808
+#define PCI_DEVICE_ID_INTEL_HDA_OAKTRAIL       0x080a
 #define PCI_DEVICE_ID_INTEL_MFD_SD     0x0820
 #define PCI_DEVICE_ID_INTEL_MFD_SDIO1  0x0821
 #define PCI_DEVICE_ID_INTEL_MFD_SDIO2  0x0822
 #define PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB    0x095e
 #define PCI_DEVICE_ID_INTEL_I960       0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM     0x0962
+#define PCI_DEVICE_ID_INTEL_HDA_HSW_0  0x0a0c
+#define PCI_DEVICE_ID_INTEL_HDA_HSW_2  0x0c0c
 #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB      0x0c60
+#define PCI_DEVICE_ID_INTEL_HDA_HSW_3  0x0d0c
+#define PCI_DEVICE_ID_INTEL_HDA_BYT    0x0f04
+#define PCI_DEVICE_ID_INTEL_SST_BYT    0x0f28
 #define PCI_DEVICE_ID_INTEL_8257X_SOL  0x1062
 #define PCI_DEVICE_ID_INTEL_82573E_SOL 0x1085
 #define PCI_DEVICE_ID_INTEL_82573L_SOL 0x108f
 #define PCI_DEVICE_ID_INTEL_82815_MC   0x1130
 #define PCI_DEVICE_ID_INTEL_82815_CGC  0x1132
+#define PCI_DEVICE_ID_INTEL_SST_TNG    0x119a
 #define PCI_DEVICE_ID_INTEL_82092AA_0  0x1221
-#define PCI_DEVICE_ID_INTEL_7505_0     0x2550
-#define PCI_DEVICE_ID_INTEL_7205_0     0x255d
 #define PCI_DEVICE_ID_INTEL_82437      0x122d
 #define PCI_DEVICE_ID_INTEL_82371FB_0  0x122e
 #define PCI_DEVICE_ID_INTEL_82371FB_1  0x1230
 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE  0x1576
 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_NHI     0x1577
 #define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE  0x1578
+#define PCI_DEVICE_ID_INTEL_HDA_BDW    0x160c
 #define PCI_DEVICE_ID_INTEL_80960_RP   0x1960
 #define PCI_DEVICE_ID_INTEL_QAT_C3XXX  0x19e2
 #define PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF       0x19e3
 #define PCI_DEVICE_ID_INTEL_82840_HB   0x1a21
 #define PCI_DEVICE_ID_INTEL_82845_HB   0x1a30
 #define PCI_DEVICE_ID_INTEL_IOAT       0x1a38
+#define PCI_DEVICE_ID_INTEL_HDA_CPT    0x1c20
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN        0x1c41
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX        0x1c5f
+#define PCI_DEVICE_ID_INTEL_HDA_PBG    0x1d20
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0     0x1d40
 #define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1     0x1d41
+#define PCI_DEVICE_ID_INTEL_HDA_PPT    0x1e20
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI  0x1e31
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN       0x1e40
 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX       0x1e5f
 #define PCI_DEVICE_ID_INTEL_VMD_201D   0x201d
+#define PCI_DEVICE_ID_INTEL_HDA_BSW    0x2284
+#define PCI_DEVICE_ID_INTEL_SST_BSW    0x22a8
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN   0x2310
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX   0x231f
 #define PCI_DEVICE_ID_INTEL_82801AA_0  0x2410
 #define PCI_DEVICE_ID_INTEL_82850_HB   0x2530
 #define PCI_DEVICE_ID_INTEL_82860_HB   0x2531
 #define PCI_DEVICE_ID_INTEL_E7501_MCH  0x254c
+#define PCI_DEVICE_ID_INTEL_7505_0     0x2550
+#define PCI_DEVICE_ID_INTEL_7205_0     0x255d
 #define PCI_DEVICE_ID_INTEL_82845G_HB  0x2560
 #define PCI_DEVICE_ID_INTEL_82845G_IG  0x2562
 #define PCI_DEVICE_ID_INTEL_82865_HB   0x2570
 #define PCI_DEVICE_ID_INTEL_ICH6_0     0x2640
 #define PCI_DEVICE_ID_INTEL_ICH6_1     0x2641
 #define PCI_DEVICE_ID_INTEL_ICH6_2     0x2642
+#define PCI_DEVICE_ID_INTEL_HDA_ICH6   0x2668
 #define PCI_DEVICE_ID_INTEL_ICH6_16    0x266a
 #define PCI_DEVICE_ID_INTEL_ICH6_17    0x266d
 #define PCI_DEVICE_ID_INTEL_ICH6_18    0x266e
 #define PCI_DEVICE_ID_INTEL_ICH6_19    0x266f
 #define PCI_DEVICE_ID_INTEL_ESB2_0     0x2670
 #define PCI_DEVICE_ID_INTEL_ESB2_14    0x2698
+#define PCI_DEVICE_ID_INTEL_HDA_ESB2   0x269a
 #define PCI_DEVICE_ID_INTEL_ESB2_17    0x269b
 #define PCI_DEVICE_ID_INTEL_ESB2_18    0x269e
 #define PCI_DEVICE_ID_INTEL_82945G_HB  0x2770
 #define PCI_DEVICE_ID_INTEL_3000_HB    0x2778
 #define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27a0
 #define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27a2
+#define PCI_DEVICE_ID_INTEL_ICH7_30    0x27b0
 #define PCI_DEVICE_ID_INTEL_ICH7_0     0x27b8
 #define PCI_DEVICE_ID_INTEL_ICH7_1     0x27b9
-#define PCI_DEVICE_ID_INTEL_ICH7_30    0x27b0
 #define PCI_DEVICE_ID_INTEL_TGP_LPC    0x27bc
 #define PCI_DEVICE_ID_INTEL_ICH7_31    0x27bd
+#define PCI_DEVICE_ID_INTEL_HDA_ICH7   0x27d8
 #define PCI_DEVICE_ID_INTEL_ICH7_17    0x27da
 #define PCI_DEVICE_ID_INTEL_ICH7_19    0x27dd
 #define PCI_DEVICE_ID_INTEL_ICH7_20    0x27de
 #define PCI_DEVICE_ID_INTEL_ICH8_3     0x2814
 #define PCI_DEVICE_ID_INTEL_ICH8_4     0x2815
 #define PCI_DEVICE_ID_INTEL_ICH8_5     0x283e
+#define PCI_DEVICE_ID_INTEL_HDA_ICH8   0x284b
 #define PCI_DEVICE_ID_INTEL_ICH8_6     0x2850
 #define PCI_DEVICE_ID_INTEL_VMD_28C0   0x28c0
 #define PCI_DEVICE_ID_INTEL_ICH9_0     0x2910
-#define PCI_DEVICE_ID_INTEL_ICH9_1     0x2917
 #define PCI_DEVICE_ID_INTEL_ICH9_2     0x2912
 #define PCI_DEVICE_ID_INTEL_ICH9_3     0x2913
 #define PCI_DEVICE_ID_INTEL_ICH9_4     0x2914
-#define PCI_DEVICE_ID_INTEL_ICH9_5     0x2919
-#define PCI_DEVICE_ID_INTEL_ICH9_6     0x2930
 #define PCI_DEVICE_ID_INTEL_ICH9_7     0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9_1     0x2917
 #define PCI_DEVICE_ID_INTEL_ICH9_8     0x2918
+#define PCI_DEVICE_ID_INTEL_ICH9_5     0x2919
+#define PCI_DEVICE_ID_INTEL_ICH9_6     0x2930
+#define PCI_DEVICE_ID_INTEL_HDA_ICH9_0 0x293e
+#define PCI_DEVICE_ID_INTEL_HDA_ICH9_1 0x293f
 #define PCI_DEVICE_ID_INTEL_I7_MCR     0x2c18
 #define PCI_DEVICE_ID_INTEL_I7_MC_TAD  0x2c19
 #define PCI_DEVICE_ID_INTEL_I7_MC_RAS  0x2c1a
 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR  0x2c31
 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK  0x2c32
 #define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC    0x2c33
-#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41
 #define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40
+#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41
 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE     0x2c50
 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51
 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70
 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2  0x2db1
 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2  0x2db2
 #define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2    0x2db3
+#define PCI_DEVICE_ID_INTEL_HDA_GML    0x3198
 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
 #define PCI_DEVICE_ID_INTEL_IOAT_TBG4  0x3429
 #define PCI_DEVICE_ID_INTEL_IOAT_TBG5  0x342a
 #define PCI_DEVICE_ID_INTEL_IOAT_TBG1  0x3431
 #define PCI_DEVICE_ID_INTEL_IOAT_TBG2  0x3432
 #define PCI_DEVICE_ID_INTEL_IOAT_TBG3  0x3433
+#define PCI_DEVICE_ID_INTEL_HDA_ICL_LP 0x34c8
 #define PCI_DEVICE_ID_INTEL_82830_HB   0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC  0x3577
-#define PCI_DEVICE_ID_INTEL_82854_HB   0x358c
-#define PCI_DEVICE_ID_INTEL_82854_IG   0x358e
 #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580
 #define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582
+#define PCI_DEVICE_ID_INTEL_82854_HB   0x358c
+#define PCI_DEVICE_ID_INTEL_82854_IG   0x358e
 #define PCI_DEVICE_ID_INTEL_E7520_MCH  0x3590
 #define PCI_DEVICE_ID_INTEL_E7320_MCH  0x3592
 #define PCI_DEVICE_ID_INTEL_MCH_PA     0x3595
 #define PCI_DEVICE_ID_INTEL_MCH_PC     0x3599
 #define PCI_DEVICE_ID_INTEL_MCH_PC1    0x359a
 #define PCI_DEVICE_ID_INTEL_E7525_MCH  0x359e
+#define PCI_DEVICE_ID_INTEL_IOAT_CNB   0x360b
+#define PCI_DEVICE_ID_INTEL_FBD_CNB    0x360c
 #define PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 0x360c
 #define PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 0x360f
 #define PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 0x3610
-#define PCI_DEVICE_ID_INTEL_IOAT_CNB   0x360b
-#define PCI_DEVICE_ID_INTEL_FBD_CNB    0x360c
 #define PCI_DEVICE_ID_INTEL_IOAT_JSF0  0x3710
 #define PCI_DEVICE_ID_INTEL_IOAT_JSF1  0x3711
 #define PCI_DEVICE_ID_INTEL_IOAT_JSF2  0x3712
 #define PCI_DEVICE_ID_INTEL_IOAT_JSF9  0x3719
 #define PCI_DEVICE_ID_INTEL_QAT_C62X   0x37c8
 #define PCI_DEVICE_ID_INTEL_QAT_C62X_VF        0x37c9
+#define PCI_DEVICE_ID_INTEL_HDA_ICL_N  0x38c8
 #define PCI_DEVICE_ID_INTEL_ICH10_0    0x3a14
 #define PCI_DEVICE_ID_INTEL_ICH10_1    0x3a16
 #define PCI_DEVICE_ID_INTEL_ICH10_2    0x3a18
 #define PCI_DEVICE_ID_INTEL_ICH10_3    0x3a1a
 #define PCI_DEVICE_ID_INTEL_ICH10_4    0x3a30
+#define PCI_DEVICE_ID_INTEL_HDA_ICH10_0        0x3a3e
 #define PCI_DEVICE_ID_INTEL_ICH10_5    0x3a60
+#define PCI_DEVICE_ID_INTEL_HDA_ICH10_1 0x3a6e
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN      0x3b00
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX      0x3b1f
+#define PCI_DEVICE_ID_INTEL_HDA_5_3400_SERIES_0        0x3b56
+#define PCI_DEVICE_ID_INTEL_HDA_5_3400_SERIES_1        0x3b57
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB0  0x3c20
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB1  0x3c21
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB2  0x3c22
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB7  0x3c27
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB8  0x3c2e
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB9  0x3c2f
-#define PCI_DEVICE_ID_INTEL_UNC_HA     0x3c46
-#define PCI_DEVICE_ID_INTEL_UNC_IMC0   0x3cb0
-#define PCI_DEVICE_ID_INTEL_UNC_IMC1   0x3cb1
-#define PCI_DEVICE_ID_INTEL_UNC_IMC2   0x3cb4
-#define PCI_DEVICE_ID_INTEL_UNC_IMC3   0x3cb5
 #define PCI_DEVICE_ID_INTEL_UNC_QPI0   0x3c41
 #define PCI_DEVICE_ID_INTEL_UNC_QPI1   0x3c42
 #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44
 #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45
+#define PCI_DEVICE_ID_INTEL_UNC_HA     0x3c46
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS    0x3c71  /* 15.1 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0   0x3c72  /* 16.2 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1   0x3c73  /* 16.3 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1   0x3cab  /* 15.3 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2   0x3cac  /* 15.4 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3   0x3cad  /* 15.5 */
+#define PCI_DEVICE_ID_INTEL_UNC_IMC0   0x3cb0
+#define PCI_DEVICE_ID_INTEL_UNC_IMC1   0x3cb1
+#define PCI_DEVICE_ID_INTEL_UNC_IMC2   0x3cb4
+#define PCI_DEVICE_ID_INTEL_UNC_IMC3   0x3cb5
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO  0x3cb8  /* 17.0 */
 #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX      0x3ce0
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0       0x3cf4  /* 12.6 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_BR         0x3cf5  /* 13.6 */
 #define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1       0x3cf6  /* 12.7 */
+#define PCI_DEVICE_ID_INTEL_HDA_ICL_H  0x3dc8
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB   0x402f
 #define PCI_DEVICE_ID_INTEL_5400_ERR   0x4030
 #define PCI_DEVICE_ID_INTEL_5400_FBD0  0x4035
 #define PCI_DEVICE_ID_INTEL_5400_FBD1  0x4036
+#define PCI_DEVICE_ID_INTEL_HDA_TGL_H  0x43c8
+#define PCI_DEVICE_ID_INTEL_HDA_DG1    0x490d
+#define PCI_DEVICE_ID_INTEL_HDA_EHL_0  0x4b55
+#define PCI_DEVICE_ID_INTEL_HDA_EHL_3  0x4b58
+#define PCI_DEVICE_ID_INTEL_HDA_JSL_N  0x4dc8
+#define PCI_DEVICE_ID_INTEL_HDA_DG2_0  0x4f90
+#define PCI_DEVICE_ID_INTEL_HDA_DG2_1  0x4f91
+#define PCI_DEVICE_ID_INTEL_HDA_DG2_2  0x4f92
 #define PCI_DEVICE_ID_INTEL_EP80579_0  0x5031
 #define PCI_DEVICE_ID_INTEL_EP80579_1  0x5032
+#define PCI_DEVICE_ID_INTEL_HDA_ADL_P  0x51c8
+#define PCI_DEVICE_ID_INTEL_HDA_ADL_PS 0x51c9
+#define PCI_DEVICE_ID_INTEL_HDA_RPL_P_0        0x51ca
+#define PCI_DEVICE_ID_INTEL_HDA_RPL_P_1        0x51cb
+#define PCI_DEVICE_ID_INTEL_HDA_ADL_M  0x51cc
+#define PCI_DEVICE_ID_INTEL_HDA_ADL_PX 0x51cd
+#define PCI_DEVICE_ID_INTEL_HDA_RPL_M  0x51ce
+#define PCI_DEVICE_ID_INTEL_HDA_RPL_PX 0x51cf
+#define PCI_DEVICE_ID_INTEL_HDA_ADL_N  0x54c8
+#define PCI_DEVICE_ID_INTEL_HDA_APL    0x5a98
 #define PCI_DEVICE_ID_INTEL_5100_16    0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_19    0x65f3
 #define PCI_DEVICE_ID_INTEL_5100_21    0x65f5
 #define PCI_DEVICE_ID_INTEL_82443GX_0  0x71a0
 #define PCI_DEVICE_ID_INTEL_82443GX_2  0x71a2
 #define PCI_DEVICE_ID_INTEL_82372FB_1  0x7601
+#define PCI_DEVICE_ID_INTEL_HDA_RPL_S  0x7a50
+#define PCI_DEVICE_ID_INTEL_HDA_ADL_S  0x7ad0
+#define PCI_DEVICE_ID_INTEL_HDA_MTL    0x7e28
+#define PCI_DEVICE_ID_INTEL_HDA_ARL_S  0x7f50
 #define PCI_DEVICE_ID_INTEL_SCH_LPC    0x8119
 #define PCI_DEVICE_ID_INTEL_SCH_IDE    0x811a
+#define PCI_DEVICE_ID_INTEL_HDA_POULSBO        0x811b
 #define PCI_DEVICE_ID_INTEL_E6XX_CU    0x8183
 #define PCI_DEVICE_ID_INTEL_ITC_LPC    0x8186
 #define PCI_DEVICE_ID_INTEL_82454GX    0x84c4
 #define PCI_DEVICE_ID_INTEL_82454NX     0x84cb
 #define PCI_DEVICE_ID_INTEL_84460GX    0x84ea
 #define PCI_DEVICE_ID_INTEL_IXP4XX     0x8500
+#define PCI_DEVICE_ID_INTEL_HDA_LPT    0x8c20
+#define PCI_DEVICE_ID_INTEL_HDA_9_SERIES       0x8ca0
+#define PCI_DEVICE_ID_INTEL_HDA_WBG_0  0x8d20
+#define PCI_DEVICE_ID_INTEL_HDA_WBG_1  0x8d21
 #define PCI_DEVICE_ID_INTEL_IXP2800    0x9004
+#define PCI_DEVICE_ID_INTEL_HDA_LKF    0x98c8
 #define PCI_DEVICE_ID_INTEL_VMD_9A0B   0x9a0b
+#define PCI_DEVICE_ID_INTEL_HDA_LPT_LP_0       0x9c20
+#define PCI_DEVICE_ID_INTEL_HDA_LPT_LP_1       0x9c21
+#define PCI_DEVICE_ID_INTEL_HDA_WPT_LP 0x9ca0
+#define PCI_DEVICE_ID_INTEL_HDA_SKL_LP 0x9d70
+#define PCI_DEVICE_ID_INTEL_HDA_KBL_LP 0x9d71
+#define PCI_DEVICE_ID_INTEL_HDA_CNL_LP 0x9dc8
+#define PCI_DEVICE_ID_INTEL_HDA_TGL_LP 0xa0c8
+#define PCI_DEVICE_ID_INTEL_HDA_SKL    0xa170
+#define PCI_DEVICE_ID_INTEL_HDA_KBL    0xa171
+#define PCI_DEVICE_ID_INTEL_HDA_LBG_0  0xa1f0
+#define PCI_DEVICE_ID_INTEL_HDA_LBG_1  0xa270
+#define PCI_DEVICE_ID_INTEL_HDA_KBL_H  0xa2f0
+#define PCI_DEVICE_ID_INTEL_HDA_CNL_H  0xa348
+#define PCI_DEVICE_ID_INTEL_HDA_CML_S  0xa3f0
+#define PCI_DEVICE_ID_INTEL_HDA_LNL_P  0xa828
 #define PCI_DEVICE_ID_INTEL_S21152BB   0xb152
+#define PCI_DEVICE_ID_INTEL_HDA_CML_R  0xf0c8
+#define PCI_DEVICE_ID_INTEL_HDA_RKL_S  0xf1c8
 
 #define PCI_VENDOR_ID_WANGXUN          0x8088
 
index b845fd83f429bbfc0eb88ec772e6be84e70e2f8a..7a41c72c195918af14bda5511bda57d384b26f68 100644 (file)
@@ -63,6 +63,8 @@ extern struct resource *platform_get_mem_or_io(struct platform_device *,
 extern struct device *
 platform_find_device_by_driver(struct device *start,
                               const struct device_driver *drv);
+
+#ifdef CONFIG_HAS_IOMEM
 extern void __iomem *
 devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
                                unsigned int index, struct resource **res);
@@ -72,6 +74,32 @@ devm_platform_ioremap_resource(struct platform_device *pdev,
 extern void __iomem *
 devm_platform_ioremap_resource_byname(struct platform_device *pdev,
                                      const char *name);
+#else
+
+static inline void __iomem *
+devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
+                               unsigned int index, struct resource **res)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+
+static inline void __iomem *
+devm_platform_ioremap_resource(struct platform_device *pdev,
+                              unsigned int index)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline void __iomem *
+devm_platform_ioremap_resource_byname(struct platform_device *pdev,
+                                     const char *name)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+#endif
+
 extern int platform_get_irq(struct platform_device *, unsigned int);
 extern int platform_get_irq_optional(struct platform_device *, unsigned int);
 extern int platform_irq_count(struct platform_device *);
index 8923387a7405bc34da868a27cd3dd76efd2fd606..a388160f4be0d6f174b883981286bd09969e5b7a 100644 (file)
@@ -486,6 +486,11 @@ struct sdw_slave_id {
        __u8 sdw_version:4;
 };
 
+struct sdw_extended_slave_id {
+       int link_id;
+       struct sdw_slave_id id;
+};
+
 /*
  * Helper macros to extract the MIPI-defined IDs
  *
index 11fc88fb0d781bd4cd93e36577bd583bdb0dedff..fa67fad4ef51085f6f63895b55ba79c36028dd4e 100644 (file)
@@ -264,11 +264,6 @@ struct sdw_intel_link_dev;
  */
 #define SDW_INTEL_CLK_STOP_BUS_RESET           BIT(3)
 
-struct sdw_intel_slave_id {
-       int link_id;
-       struct sdw_slave_id id;
-};
-
 struct hdac_bus;
 
 /**
@@ -298,7 +293,7 @@ struct sdw_intel_ctx {
        int num_slaves;
        acpi_handle handle;
        struct sdw_intel_link_dev **ldev;
-       struct sdw_intel_slave_id *ids;
+       struct sdw_extended_slave_id *ids;
        struct list_head link_list;
        struct mutex shim_lock; /* lock for access to shared SHIM registers */
        u32 shim_mask;
diff --git a/include/media/dvb_math.h b/include/media/dvb_math.h
deleted file mode 100644 (file)
index 8690ec4..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- */
-
-#ifndef __DVB_MATH_H
-#define __DVB_MATH_H
-
-#include <linux/types.h>
-
-/**
- * intlog2 - computes log2 of a value; the result is shifted left by 24 bits
- *
- * @value: The value (must be != 0)
- *
- * to use rational values you can use the following method:
- *
- *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
- *
- * Some usecase examples:
- *
- *     intlog2(8) will give 3 << 24 = 3 * 2^24
- *
- *     intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
- *
- *     intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
- *
- *
- * return: log2(value) * 2^24
- */
-extern unsigned int intlog2(u32 value);
-
-/**
- * intlog10 - computes log10 of a value; the result is shifted left by 24 bits
- *
- * @value: The value (must be != 0)
- *
- * to use rational values you can use the following method:
- *
- *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
- *
- * An usecase example:
- *
- *     intlog10(1000) will give 3 << 24 = 3 * 2^24
- *
- *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
- *
- * look at intlog2 for similar examples
- *
- * return: log10(value) * 2^24
- */
-extern unsigned int intlog10(u32 value);
-
-#endif
index 1f9713d7ca76ff4f595416db7f48f434b24454f7..3950322bf3cbbcef845687510cfe6c9786ba73ea 100644 (file)
 #define CS35L56_NUM_BULK_SUPPLIES                      3
 #define CS35L56_NUM_DSP_REGIONS                                5
 
+struct cs35l56_base {
+       struct device *dev;
+       struct regmap *regmap;
+       int irq;
+       struct mutex irq_lock;
+       u8 rev;
+       bool init_done;
+       bool fw_patched;
+       bool secured;
+       bool can_hibernate;
+       struct gpio_desc *reset_gpio;
+};
+
 extern struct regmap_config cs35l56_regmap_i2c;
 extern struct regmap_config cs35l56_regmap_spi;
 extern struct regmap_config cs35l56_regmap_sdw;
 
-extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS];
 extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
 extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
 
-void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap);
+int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
+int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
+int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
+int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base);
+void cs35l56_wait_control_port_ready(void);
+void cs35l56_wait_min_reset_pulse(void);
+void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire);
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
+irqreturn_t cs35l56_irq(int irq, void *data);
+int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
+int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
+int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
+void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
+int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
 int cs35l56_get_bclk_freq_id(unsigned int freq);
 void cs35l56_fill_supply_names(struct regulator_bulk_data *data);
 
index 4f44f0bd538866f62babe7b32a6761d68381a460..228114aca4158d1235f8983c7ab5f8ea8657ef0c 100644 (file)
@@ -42,6 +42,7 @@ int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, i
 int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink);
 int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink);
 
+int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid);
 int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num);
 
 int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
@@ -145,6 +146,9 @@ hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink) { return 0
 static inline int
 hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) { return 0; }
 
+static inline int
+hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) { return 0; }
+
 static inline int
 hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { return 0; }
 
index bbb7805e85d8e2281e77592e087b2ea4ec404960..5497dc9c396a5a3d078d5e7718a3dc92b7bb0fb6 100644 (file)
@@ -18,9 +18,6 @@
 #include <sound/hda_verbs.h>
 #include <sound/hda_regmap.h>
 
-#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
-#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
-
 /*
  * Structures
  */
index 2ffdf58bd6d42ac60919786eb8d7586f82e38a0f..32c59053b48edca72dcf57cda55b674c3a9dd5e3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/iopoll.h>
+#include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/timecounter.h>
 #include <sound/core.h>
@@ -704,4 +705,29 @@ static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
        for ((idx) = 0, (ptr) = (array)->list; (idx) < (array)->used; \
             (ptr) = snd_array_elem(array, ++(idx)))
 
+/*
+ * Device matching
+ */
+
+#define HDA_CONTROLLER_IS_HSW(pci) (pci_match_id((struct pci_device_id []){ \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_0) }, \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_2) }, \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_3) }, \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_BDW) }, \
+                       { } \
+               }, pci))
+
+#define HDA_CONTROLLER_IS_APL(pci) (pci_match_id((struct pci_device_id []){ \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_APL) }, \
+                       { } \
+               }, pci))
+
+#define HDA_CONTROLLER_IN_GPU(pci) (pci_match_id((struct pci_device_id []){ \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG1) }, \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_0) }, \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_1) }, \
+                       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_2) }, \
+                       { } \
+               }, pci) || HDA_CONTROLLER_IS_HSW(pci))
+
 #endif /* __SOUND_HDAUDIO_H */
index 3b3d6a19ca499d381c504247a255d9833d111604..e865f041929bea950f2838086e5d04f7a354b62c 100644 (file)
@@ -31,8 +31,6 @@ struct rt5665_platform_data {
        bool in3_diff;
        bool in4_diff;
 
-       int ldo1_en; /* GPIO for LDO1_EN */
-
        enum rt5665_dmic1_data_pin dmic1_data_pin;
        enum rt5665_dmic2_data_pin dmic2_data_pin;
        enum rt5665_jd_src jd_src;
index 182edfbc9e7a3d87be677674d2c406969f9c620c..b682418c6cd63607ae744e9dacf022c4f6f6fa50 100644 (file)
@@ -25,9 +25,6 @@ enum rt5668_jd_src {
 };
 
 struct rt5668_platform_data {
-
-       int ldo1_en; /* GPIO for LDO1_EN */
-
        enum rt5668_dmic1_data_pin dmic1_data_pin;
        enum rt5668_dmic1_clk_pin dmic1_clk_pin;
        enum rt5668_jd_src jd_src;
index 3900a07e3935fd11f332a6b439579e5330431df5..4256df721e3a63fc06dd4dc633cfef079090d47e 100644 (file)
@@ -31,9 +31,6 @@ enum rt5682_dai_clks {
 };
 
 struct rt5682_platform_data {
-
-       int ldo1_en; /* GPIO for LDO1_EN */
-
        enum rt5682_dmic1_data_pin dmic1_data_pin;
        enum rt5682_dmic1_clk_pin dmic1_clk_pin;
        enum rt5682_jd_src jd_src;
index f18d91308b9a0b14214ab31d46b8a04da05b8d5a..66ca0c75b914e3d077a932b00f49cd21ed8bfb7b 100644 (file)
@@ -32,9 +32,6 @@ enum rt5682s_dai_clks {
 };
 
 struct rt5682s_platform_data {
-
-       int ldo1_en; /* GPIO for LDO1_EN */
-
        enum rt5682s_dmic1_data_pin dmic1_data_pin;
        enum rt5682s_dmic1_clk_pin dmic1_clk_pin;
        enum rt5682s_jd_src jd_src;
index b450d587322745bc9ed57d35b216f2d2915de58a..d1a95bc33c5697bfd2e1b99c83550fad55980a9d 100644 (file)
@@ -192,9 +192,8 @@ int asoc_simple_remove(struct platform_device *pdev);
 
 int asoc_graph_card_probe(struct snd_soc_card *card);
 int asoc_graph_is_ports0(struct device_node *port);
-int asoc_graph_parse_dai(struct device_node *ep,
-                        struct snd_soc_dai_link_component *dlc,
-                        int *is_single_link);
+int asoc_graph_parse_dai(struct device *dev, struct device_node *ep,
+                        struct snd_soc_dai_link_component *dlc, int *is_single_link);
 
 #ifdef DEBUG
 static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
index 528279056b3ab96eb062111774163d431a09afe2..6d31d535e8f6dd99f96879c53f1aeadc73aea086 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/stddef.h>
 #include <linux/acpi.h>
 #include <linux/mod_devicetable.h>
+#include <linux/soundwire/sdw.h>
 
 struct snd_soc_acpi_package_context {
        char *name;           /* package name */
@@ -150,6 +151,7 @@ struct snd_soc_acpi_link_adr {
  * all firmware/topology related fields.
  *
  * @id: ACPI ID (usually the codec's) used to find a matching machine driver.
+ * @uid: ACPI Unique ID, can be used to disambiguate matches.
  * @comp_ids: list of compatible audio codecs using the same machine driver,
  * firmware and topology
  * @link_mask: describes required board layout, e.g. for SoundWire.
@@ -208,4 +210,9 @@ static inline bool snd_soc_acpi_sof_parent(struct device *dev)
                !strncmp(dev->parent->driver->name, "sof-audio-acpi", strlen("sof-audio-acpi"));
 }
 
+bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
+                                       const struct snd_soc_acpi_link_adr *link,
+                                       struct sdw_extended_slave_id *ids,
+                                       int num_slaves);
+
 #endif
index e3906ecda740a6ab373518214d2412a9b82f1855..5fcfba47d98cca27e3eb86128f506103bbaf7f30 100644 (file)
@@ -271,7 +271,18 @@ int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
                                   struct snd_compr_stream *cstream,
                                   struct snd_compr_metadata *metadata);
 
+const char *snd_soc_dai_name_get(struct snd_soc_dai *dai);
+
 struct snd_soc_dai_ops {
+       /* DAI driver callbacks */
+       int (*probe)(struct snd_soc_dai *dai);
+       int (*remove)(struct snd_soc_dai *dai);
+       /* compress dai */
+       int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
+       /* Optional Callback used at pcm creation*/
+       int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
+                      struct snd_soc_dai *dai);
+
        /*
         * DAI clocking configuration, all optional.
         * Called by soc_card drivers, normally in their hw_params.
@@ -353,6 +364,10 @@ struct snd_soc_dai_ops {
        u64 *auto_selectable_formats;
        int num_auto_selectable_formats;
 
+       /* probe ordering - for components with runtime dependencies */
+       int probe_order;
+       int remove_order;
+
        /* bit field */
        unsigned int no_capture_mute:1;
 };
@@ -397,15 +412,7 @@ struct snd_soc_dai_driver {
        unsigned int id;
        unsigned int base;
        struct snd_soc_dobj dobj;
-
-       /* DAI driver callbacks */
-       int (*probe)(struct snd_soc_dai *dai);
-       int (*remove)(struct snd_soc_dai *dai);
-       /* compress dai */
-       int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
-       /* Optional Callback used at pcm creation*/
-       int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
-                      struct snd_soc_dai *dai);
+       struct of_phandle_args *dai_args;
 
        /* ops */
        const struct snd_soc_dai_ops *ops;
@@ -417,10 +424,6 @@ struct snd_soc_dai_driver {
        unsigned int symmetric_rate:1;
        unsigned int symmetric_channels:1;
        unsigned int symmetric_sample_bits:1;
-
-       /* probe ordering - for components with runtime dependencies */
-       int probe_order;
-       int remove_order;
 };
 
 /* for Playback/Capture */
index 87f8e1793af1587a7a846616a116be92f514b618..d2faec9a323ea3e87c99fc04dcdfd93c59c5d8fc 100644 (file)
@@ -42,36 +42,45 @@ struct soc_enum;
 
 /* codec domain */
 #define SND_SOC_DAPM_VMID(wname) \
-{      .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0}
 
 /* platform domain */
 #define SND_SOC_DAPM_SIGGEN(wname) \
-{      .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_SINK(wname) \
-{      .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_INPUT(wname) \
-{      .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_OUTPUT(wname) \
-{      .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_MIC(wname, wevent) \
-{      .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_HP(wname, wevent) \
-{      .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_SPK(wname, wevent) \
-{      .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_LINE(wname, wevent) \
-{      .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
@@ -82,93 +91,110 @@ struct soc_enum;
 /* path domain */
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
-{      .id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pga, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
-{      .id = snd_soc_dapm_out_drv, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_out_drv, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
-{      .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 /* DEPRECATED: use SND_SOC_DAPM_SUPPLY */
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_micbias, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_micbias, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_switch, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_switch, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_mux, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_demux, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_demux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
         wcontrols) \
-{      .id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pga, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
-{      .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pga, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_out_drv, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_out_drv, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
        wcontrols, wncontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, \
        .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_switch, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_switch, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_mux, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
@@ -176,101 +202,121 @@ struct soc_enum;
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pga, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags, \
        .subseq = wsubseq}
 #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
        wflags) \
-{      .id = snd_soc_dapm_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_supply, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags, .subseq = wsubseq}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pga, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
        wcontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_mixer, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
-{      .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_POST(wname, wevent) \
-{      .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 
 /* stream domain */
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
        .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \
                              wevent, wflags)                           \
-{      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
        .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
        .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \
                             wevent, wflags)                            \
-{      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
        .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
 #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
                           wevent, wflags)                              \
-{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
 
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
                           wevent, wflags)                              \
-{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
-{      .id = snd_soc_dapm_clock_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_clock_supply, .name = wname, \
        .reg = SND_SOC_NOPM, .event = dapm_clock_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
 
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
-{      .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
+(struct snd_soc_dapm_widget) { \
+       .id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
        .reg = wreg, .shift = wshift, .mask = wmask, \
        .on_val = won_val, .off_val = woff_val, }
 #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
-{      .id = snd_soc_dapm_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_supply, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)       \
-{      .id = snd_soc_dapm_regulator_supply, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_regulator_supply, .name = wname, \
        .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
        .on_val = wflags}
 #define SND_SOC_DAPM_PINCTRL(wname, active, sleep) \
-{      .id = snd_soc_dapm_pinctrl, .name = wname, \
+(struct snd_soc_dapm_widget) { \
+       .id = snd_soc_dapm_pinctrl, .name = wname, \
        .priv = (&(struct snd_soc_dapm_pinctrl_priv) \
                { .active_state = active, .sleep_state = sleep,}), \
        .reg = SND_SOC_NOPM, .event = dapm_pinctrl_event, \
@@ -604,6 +650,7 @@ struct snd_soc_dapm_widget {
        unsigned char power_checked:1;          /* power checked this run */
        unsigned char is_supply:1;              /* Widget is a supply type widget */
        unsigned char is_ep:2;                  /* Widget is a endpoint type widget */
+       unsigned char no_wname_in_kcontrol_name:1; /* No widget name prefix in kcontrol name */
        int subseq;                             /* sort within widget type */
 
        int (*power_check)(struct snd_soc_dapm_widget *w);
index b27f84580c5b0b840ba360e6b822e82dea839d48..fa2337a3cf4c775b566e1d133844b5dcefb1516a 100644 (file)
@@ -651,6 +651,7 @@ struct snd_soc_dai_link_component {
        const char *name;
        struct device_node *of_node;
        const char *dai_name;
+       struct of_phandle_args *dai_args;
 };
 
 struct snd_soc_dai_link_codec_ch_map {
@@ -1335,6 +1336,11 @@ int snd_soc_add_pcm_runtimes(struct snd_soc_card *card,
 void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
                                struct snd_soc_pcm_runtime *rtd);
 
+void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
+                                    struct snd_soc_dai_link_component *cpus);
+struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev,
+                                             struct of_phandle_args *args);
+struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args);
 struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
                                         struct snd_soc_dai_driver *dai_drv,
                                         bool legacy_dai_naming);
index 88560281d420603598f7b02a48ce168875b5acd8..906e2f327ad2542b7e20b123b323244155a875cf 100644 (file)
@@ -26,9 +26,9 @@ enum sof_comp_type {
        SOF_COMP_MIXER,
        SOF_COMP_MUX,
        SOF_COMP_SRC,
-       SOF_COMP_SPLITTER,
+       SOF_COMP_DEPRECATED0, /* Formerly SOF_COMP_SPLITTER */
        SOF_COMP_TONE,
-       SOF_COMP_SWITCH,
+       SOF_COMP_DEPRECATED1, /* Formerly SOF_COMP_SWITCH */
        SOF_COMP_BUFFER,
        SOF_COMP_EQ_IIR,
        SOF_COMP_EQ_FIR,
index e9ec7e4eb982330c95cac9d701475be15f9e2a1d..453cab2a120988d9b57c227c9a57083098d447b4 100644 (file)
 #define SOF_TKN_COMP_OUTPUT_PIN_BINDING_WNAME  414
 #define SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS   415
 #define SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS  416
-
+/*
+ * The token value is copied to the dapm_widget's
+ * no_wname_in_kcontrol_name.
+ */
+#define SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME 417
 
 /* SSP */
 #define SOF_TKN_INTEL_SSP_CLKS_CONTROL         500
index bfac26ddfc22f295ddb76e6dd34355ac9b6f3c81..91fcdb0c9efe44dd5be7d51fb7549c3a2be3d075 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-y += div64.o gcd.o lcm.o int_pow.o int_sqrt.o reciprocal_div.o
+obj-y += div64.o gcd.o lcm.o int_log.o int_pow.o int_sqrt.o reciprocal_div.o
 
 obj-$(CONFIG_CORDIC)           += cordic.o
 obj-$(CONFIG_PRIME_NUMBERS)    += prime_numbers.o
diff --git a/lib/math/int_log.c b/lib/math/int_log.c
new file mode 100644 (file)
index 0000000..8f9da3a
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * Provides fixed-point logarithm operations.
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ */
+
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/int_log.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/bug.h>
+
+static const unsigned short logtable[256] = {
+       0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+       0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+       0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+       0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+       0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+       0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+       0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+       0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+       0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+       0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+       0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+       0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+       0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+       0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+       0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+       0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+       0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+       0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+       0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+       0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+       0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+       0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+       0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+       0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+       0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+       0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+       0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+       0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+       0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+       0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+       0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+       0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47,
+};
+
+unsigned int intlog2(u32 value)
+{
+       /**
+        *      returns: log2(value) * 2^24
+        *      wrong result if value = 0 (log2(0) is undefined)
+        */
+       unsigned int msb;
+       unsigned int logentry;
+       unsigned int significand;
+       unsigned int interpolation;
+
+       if (unlikely(value == 0)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       /* first detect the msb (count begins at 0) */
+       msb = fls(value) - 1;
+
+       /**
+        *      now we use a logtable after the following method:
+        *
+        *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+        *      where x = msb and therefore 1 <= y < 2
+        *      first y is determined by shifting the value left
+        *      so that msb is bit 31
+        *              0x00231f56 -> 0x8C7D5800
+        *      the result is y * 2^31 -> "significand"
+        *      then the highest 9 bits are used for a table lookup
+        *      the highest bit is discarded because it's always set
+        *      the highest nine bits in our example are 100011000
+        *      so we would use the entry 0x18
+        */
+       significand = value << (31 - msb);
+       logentry = (significand >> 23) % ARRAY_SIZE(logtable);
+
+       /**
+        *      last step we do is interpolation because of the
+        *      limitations of the log table the error is that part of
+        *      the significand which isn't used for lookup then we
+        *      compute the ratio between the error and the next table entry
+        *      and interpolate it between the log table entry used and the
+        *      next one the biggest error possible is 0x7fffff
+        *      (in our example it's 0x7D5800)
+        *      needed value for next table entry is 0x800000
+        *      so the interpolation is
+        *      (error / 0x800000) * (logtable_next - logtable_current)
+        *      in the implementation the division is moved to the end for
+        *      better accuracy there is also an overflow correction if
+        *      logtable_next is 256
+        */
+       interpolation = ((significand & 0x7fffff) *
+                       ((logtable[(logentry + 1) % ARRAY_SIZE(logtable)] -
+                         logtable[logentry]) & 0xffff)) >> 15;
+
+       /* now we return the result */
+       return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+       /**
+        *      returns: log10(value) * 2^24
+        *      wrong result if value = 0 (log10(0) is undefined)
+        */
+       u64 log;
+
+       if (unlikely(value == 0)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       log = intlog2(value);
+
+       /**
+        *      we use the following method:
+        *      log10(x) = log2(x) * log10(2)
+        */
+
+       return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
index 0ddfb717b81dc3970db570a4ee712050540f65e9..f0e15822e858c8bc4d8b8948babceb865c7ca39e 100644 (file)
@@ -39,8 +39,6 @@ config SOUND_OSS_CORE_PRECLAIM
 
 source "sound/oss/dmasound/Kconfig"
 
-if !UML
-
 menuconfig SND
        tristate "Advanced Linux Sound Architecture"
        help
@@ -103,8 +101,6 @@ source "sound/virtio/Kconfig"
 
 endif # SND
 
-endif # !UML
-
 endif # SOUND
 
 config AC97_BUS
index e1f864dc7939a7c0c51fa384e209f5cfeb6ee78b..ea8072bf3aa49e16435d19e2e33b2ce81e7ca946 100644 (file)
@@ -366,7 +366,7 @@ MODULE_DEVICE_TABLE(of, snd_serial_generic_dt_ids);
 static struct serdev_device_driver snd_serial_generic_driver = {
        .driver = {
                .name           = "snd-serial-generic",
-               .of_match_table = of_match_ptr(snd_serial_generic_dt_ids),
+               .of_match_table = snd_serial_generic_dt_ids,
        },
        .probe  = snd_serial_generic_probe,
 };
index 161a9711cd63e8d68d092db9684dc57eed972b3a..b428537f284c725f47e4f16f79867a992dcb99e8 100644 (file)
 #include <sound/hda_i915.h>
 #include <sound/hda_register.h>
 
-#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \
-                               ((pci)->device == 0x0c0c) || \
-                               ((pci)->device == 0x0d0c) || \
-                               ((pci)->device == 0x160c))
-
 /**
  * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW
  * @bus: HDA core bus
@@ -39,7 +34,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
 
        if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq)
                return; /* only for i915 binding */
-       if (!IS_HSW_CONTROLLER(pci))
+       if (!HDA_CONTROLLER_IS_HSW(pci))
                return; /* only HSW/BDW */
 
        cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
@@ -80,14 +75,20 @@ static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac)
        if (bus_a == bus_b)
                return true;
 
-       /*
-        * on i915 discrete GPUs with embedded HDA audio, the two
-        * devices are connected via 2nd level PCI bridge
-        */
        bus_a = bus_a->parent;
        bus_b = bus_b->parent;
+
+       /* connected via parent bus (may be NULL!) */
+       if (bus_a == bus_b)
+               return true;
+
        if (!bus_a || !bus_b)
                return false;
+
+       /*
+        * on i915 discrete GPUs with embedded HDA audio, the two
+        * devices are connected via 2nd level PCI bridge
+        */
        bus_a = bus_a->parent;
        bus_b = bus_b->parent;
        if (bus_a && bus_a == bus_b)
index 317bdf6dcbef42f0954a7b8e3b757b5c8dcf8185..dcf2453138a5797fa0f5e42a90b863a293db22cf 100644 (file)
@@ -50,14 +50,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
        {
                .flags = FLAG_SOF,
-               .device = 0x119a,
-       },
-#endif
-/* Broxton-T */
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
-       {
-               .flags = FLAG_SOF,
-               .device = 0x1a98,
+               .device = PCI_DEVICE_ID_INTEL_SST_TNG,
        },
 #endif
 /*
@@ -68,7 +61,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0x5a98,
+               .device = PCI_DEVICE_ID_INTEL_HDA_APL,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Up Squared",
@@ -82,14 +75,14 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x5a98,
+               .device = PCI_DEVICE_ID_INTEL_HDA_APL,
                .codec_hid =  &essx_83x6,
        },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
        {
                .flags = FLAG_SST,
-               .device = 0x5a98,
+               .device = PCI_DEVICE_ID_INTEL_HDA_APL,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -110,7 +103,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
        {
                .flags = FLAG_SST,
-               .device = 0x9d70,
+               .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -123,14 +116,14 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
-               .device = 0x9d70,
+               .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
        },
 #endif
 /* Kabylake-LP */
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
        {
                .flags = FLAG_SST,
-               .device = 0x9d71,
+               .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -143,7 +136,7 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
-               .device = 0x9d71,
+               .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
        },
 #endif
 
@@ -155,7 +148,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0x3198,
+               .device = PCI_DEVICE_ID_INTEL_HDA_GML,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -168,7 +161,7 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x3198,
+               .device = PCI_DEVICE_ID_INTEL_HDA_GML,
                .codec_hid =  &essx_83x6,
        },
 #endif
@@ -188,7 +181,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0x9dc8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -207,12 +200,12 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x09dc8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x9dc8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
        },
 #endif
 
@@ -220,7 +213,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0xa348,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -233,7 +226,7 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0xa348,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
        },
 #endif
 
@@ -241,7 +234,7 @@ static const struct config_entry config_table[] = {
 /* Cometlake-LP */
        {
                .flags = FLAG_SOF,
-               .device = 0x02c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -267,17 +260,17 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x02c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x02c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
        },
 /* Cometlake-H */
        {
                .flags = FLAG_SOF,
-               .device = 0x06c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .matches = {
@@ -296,12 +289,12 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x06c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x06c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
        },
 #endif
 
@@ -309,7 +302,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0x34c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -322,12 +315,12 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x34c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x34c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
        },
 #endif
 
@@ -335,7 +328,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0x4dc8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -348,12 +341,12 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0x4dc8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
-               .device = 0x4dc8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
        },
 #endif
 
@@ -361,7 +354,7 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
        {
                .flags = FLAG_SOF,
-               .device = 0xa0c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
                .dmi_table = (const struct dmi_system_id []) {
                        {
                                .ident = "Google Chromebooks",
@@ -380,16 +373,16 @@ static const struct config_entry config_table[] = {
        },
        {
                .flags = FLAG_SOF,
-               .device = 0xa0c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0xa0c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x43c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H,
        },
 #endif
 
@@ -397,78 +390,69 @@ static const struct config_entry config_table[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
-               .device = 0x4b55,
+               .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
-               .device = 0x4b58,
+               .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3,
        },
 #endif
 
-/* Alder Lake */
+/* Alder Lake / Raptor Lake */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
-       /* Alderlake-S */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x7ad0,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S,
        },
-       /* RaptorLake-S */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x7a50,
+               .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S,
        },
-       /* Alderlake-P */
        {
                .flags = FLAG_SOF,
-               .device = 0x51c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51cd,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX,
        },
-       /* Alderlake-PS */
        {
                .flags = FLAG_SOF,
-               .device = 0x51c9,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
                .codec_hid =  &essx_83x6,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51c9,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
        },
-       /* Alderlake-M */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51cc,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M,
        },
-       /* Alderlake-N */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x54c8,
+               .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
        },
-       /* RaptorLake-P */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51ca,
+               .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
        },
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51cb,
+               .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
        },
-       /* RaptorLake-M */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51ce,
+               .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
        },
-       /* RaptorLake-PX */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x51cf,
+               .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX,
        },
 #endif
 
@@ -477,10 +461,18 @@ static const struct config_entry config_table[] = {
        /* Meteorlake-P */
        {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
-               .device = 0x7e28,
+               .device = PCI_DEVICE_ID_INTEL_HDA_MTL,
        },
 #endif
 
+/* Lunar Lake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE)
+       /* Lunarlake-P */
+       {
+               .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+               .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P,
+       },
+#endif
 };
 
 static const struct config_entry *snd_intel_dsp_find_config
@@ -549,7 +541,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
        const struct config_entry *cfg;
 
        /* Intel vendor only */
-       if (pci->vendor != 0x8086)
+       if (pci->vendor != PCI_VENDOR_ID_INTEL)
                return SND_INTEL_DSP_DRIVER_ANY;
 
        /*
@@ -557,12 +549,12 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci)
         * for HDMI/DP support, ignore kernel parameter
         */
        switch (pci->device) {
-       case 0x160c: /* Broadwell */
-       case 0x0a0c: /* Haswell */
-       case 0x0c0c:
-       case 0x0d0c:
-       case 0x0f04: /* Baytrail */
-       case 0x2284: /* Braswell */
+       case PCI_DEVICE_ID_INTEL_HDA_BDW:
+       case PCI_DEVICE_ID_INTEL_HDA_HSW_0:
+       case PCI_DEVICE_ID_INTEL_HDA_HSW_2:
+       case PCI_DEVICE_ID_INTEL_HDA_HSW_3:
+       case PCI_DEVICE_ID_INTEL_HDA_BYT:
+       case PCI_DEVICE_ID_INTEL_HDA_BSW:
                return SND_INTEL_DSP_DRIVER_ANY;
        }
 
index 886255a03e8b453c03819adfa80c2495de3ce7b6..dd6922267a4bbf2a03b83d1a45178105baf41e50 100644 (file)
@@ -130,6 +130,37 @@ config SND_HDA_SCODEC_CS35L41_SPI
 comment "Set to Y if you want auto-loading the side codec driver"
        depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m
 
+config SND_HDA_SCODEC_CS35L56
+       tristate
+
+config SND_HDA_SCODEC_CS35L56_I2C
+       tristate "Build CS35L56 HD-audio side codec support for I2C Bus"
+       depends on I2C
+       depends on ACPI || COMPILE_TEST
+       depends on SND_SOC
+       select CS_DSP
+       select SND_HDA_GENERIC
+       select SND_SOC_CS35L56_SHARED
+       select SND_HDA_SCODEC_CS35L56
+       select SND_HDA_CS_DSP_CONTROLS
+       help
+         Say Y or M here to include CS35L56 amplifier support with
+         I2C control.
+
+config SND_HDA_SCODEC_CS35L56_SPI
+       tristate "Build CS35L56 HD-audio side codec support for SPI Bus"
+       depends on SPI_MASTER
+       depends on ACPI || COMPILE_TEST
+       depends on SND_SOC
+       select CS_DSP
+       select SND_HDA_GENERIC
+       select SND_SOC_CS35L56_SHARED
+       select SND_HDA_SCODEC_CS35L56
+       select SND_HDA_CS_DSP_CONTROLS
+       help
+         Say Y or M here to include CS35L56 amplifier support with
+         SPI control.
+
 config SND_HDA_CODEC_REALTEK
        tristate "Build Realtek HD-audio codec support"
        select SND_HDA_GENERIC
index 00d3061044842d50fe3b63a703cddcc5fc9f875c..c6e6509e7b8e87b461b30df30fb0a4d4a81f3498 100644 (file)
@@ -31,6 +31,9 @@ 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-scodec-cs35l56-objs :=         cs35l56_hda.o
+snd-hda-scodec-cs35l56-i2c-objs :=     cs35l56_hda_i2c.o
+snd-hda-scodec-cs35l56-spi-objs :=     cs35l56_hda_spi.o
 snd-hda-cs-dsp-ctls-objs :=            hda_cs_dsp_ctl.o
 
 # common driver
@@ -55,6 +58,9 @@ 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_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
 obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
 
 # this must be the last entry after codec drivers;
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c
new file mode 100644 (file)
index 0000000..71e95e6
--- /dev/null
@@ -0,0 +1,995 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// HDA audio driver for Cirrus Logic CS35L56 smart amp
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+//
+
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include <sound/tlv.h>
+#include "cs35l56_hda.h"
+#include "hda_component.h"
+#include "hda_cs_dsp_ctl.h"
+#include "hda_generic.h"
+
+ /*
+  * The cs35l56_hda_dai_config[] reg sequence configures the device as
+  *  ASP1_BCLK_FREQ = 3.072 MHz
+  *  ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S
+  *  ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots
+  *  ASP1_RX_WL = 24 bits per sample
+  *  ASP1_TX_WL = 24 bits per sample
+  *  ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled
+  */
+static const struct reg_sequence cs35l56_hda_dai_config[] = {
+       { CS35L56_ASP1_CONTROL1,        0x00000021 },
+       { CS35L56_ASP1_CONTROL2,        0x20200200 },
+       { CS35L56_ASP1_CONTROL3,        0x00000003 },
+       { CS35L56_ASP1_DATA_CONTROL5,   0x00000018 },
+       { CS35L56_ASP1_DATA_CONTROL1,   0x00000018 },
+       { CS35L56_ASP1_ENABLES1,        0x00000000 },
+};
+
+static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
+{
+       unsigned int val;
+       int ret;
+
+       pm_runtime_get_sync(cs35l56->base.dev);
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);
+       if (ret == 0) {
+               /* Wait for firmware to enter PS0 power state */
+               ret = regmap_read_poll_timeout(cs35l56->base.regmap,
+                                              CS35L56_TRANSDUCER_ACTUAL_PS,
+                                              val, (val == CS35L56_PS0),
+                                              CS35L56_PS0_POLL_US,
+                                              CS35L56_PS0_TIMEOUT_US);
+               if (ret)
+                       dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
+       }
+       regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+                       BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
+                       cs35l56->asp_tx_mask);
+       cs35l56->playing = true;
+}
+
+static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56)
+{
+       cs35l56->playing = false;
+       cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
+       regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+                         BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
+                         BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) |
+                         BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT));
+
+       pm_runtime_mark_last_busy(cs35l56->base.dev);
+       pm_runtime_put_autosuspend(cs35l56->base.dev);
+}
+
+static void cs35l56_hda_playback_hook(struct device *dev, int action)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action);
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               if (cs35l56->playing)
+                       break;
+
+               /* If we're suspended: flag that resume should start playback */
+               if (cs35l56->suspended) {
+                       cs35l56->playing = true;
+                       break;
+               }
+
+               cs35l56_hda_play(cs35l56);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               if (!cs35l56->playing)
+                       break;
+
+               cs35l56_hda_pause(cs35l56);
+               break;
+       default:
+               break;
+       }
+}
+
+static int __maybe_unused cs35l56_hda_runtime_suspend(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       if (cs35l56->cs_dsp.booted)
+               cs_dsp_stop(&cs35l56->cs_dsp);
+
+       return cs35l56_runtime_suspend_common(&cs35l56->base);
+}
+
+static int __maybe_unused cs35l56_hda_runtime_resume(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = cs35l56_runtime_resume_common(&cs35l56->base, false);
+       if (ret < 0)
+               return ret;
+
+       if (cs35l56->cs_dsp.booted) {
+               ret = cs_dsp_run(&cs35l56->cs_dsp);
+               if (ret) {
+                       dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
+       regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+                    CS35L56_MBOX_CMD_HIBERNATE_NOW);
+
+       regcache_cache_only(cs35l56->base.regmap, true);
+
+       return ret;
+}
+
+static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC;
+       if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC)
+               uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1;
+       strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item],
+               sizeof(uinfo->value.enumerated.name));
+
+       return 0;
+}
+
+static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
+       unsigned int reg_val;
+       int i;
+
+       regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
+       reg_val &= CS35L56_ASP_TXn_SRC_MASK;
+
+       for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
+               if (cs35l56_tx_input_values[i] == reg_val) {
+                       ucontrol->value.enumerated.item[0] = i;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
+       unsigned int item = ucontrol->value.enumerated.item[0];
+       bool changed;
+
+       if (item >= CS35L56_NUM_INPUT_SRC)
+               return -EINVAL;
+
+       regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
+                                CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
+                                &changed);
+
+       return changed;
+}
+
+static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN;
+       uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX;
+       return 0;
+}
+
+static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
+       unsigned int pos;
+       int ret;
+
+       ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_POSTURE_NUMBER, &pos);
+       if (ret)
+               return ret;
+
+       ucontrol->value.integer.value[0] = pos;
+
+       return ret;
+}
+
+static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
+       unsigned long pos = ucontrol->value.integer.value[0];
+       bool changed;
+       int ret;
+
+       if ((pos < CS35L56_MAIN_POSTURE_MIN) ||
+           (pos > CS35L56_MAIN_POSTURE_MAX))
+               return -EINVAL;
+
+       ret = regmap_update_bits_check(cs35l56->base.regmap,
+                                      CS35L56_MAIN_POSTURE_NUMBER,
+                                      CS35L56_MAIN_POSTURE_MASK,
+                                      pos, &changed);
+       if (ret)
+               return ret;
+
+       return changed;
+}
+
+static const struct {
+       const char *name;
+       unsigned int reg;
+} cs35l56_hda_mixer_controls[] = {
+       { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT },
+       { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT },
+       { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT },
+       { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT },
+};
+
+static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0);
+
+static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.step = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
+                                  CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
+
+       return 0;
+}
+
+static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
+       unsigned int raw_vol;
+       int vol;
+       int ret;
+
+       ret = regmap_read(cs35l56->base.regmap, CS35L56_MAIN_RENDER_USER_VOLUME, &raw_vol);
+
+       if (ret)
+               return ret;
+
+       vol = (s16)(raw_vol & 0xFFFF);
+       vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
+
+       if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT))
+               vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1));
+
+       ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
+
+       return 0;
+}
+
+static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = (struct cs35l56_hda *)kcontrol->private_data;
+       long vol = ucontrol->value.integer.value[0];
+       unsigned int raw_vol;
+       bool changed;
+       int ret;
+
+       if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
+                                CS35L56_MAIN_RENDER_USER_VOLUME_MIN)))
+               return -EINVAL;
+
+       raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<
+                 CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
+
+       ret = regmap_update_bits_check(cs35l56->base.regmap,
+                                      CS35L56_MAIN_RENDER_USER_VOLUME,
+                                      CS35L56_MAIN_RENDER_USER_VOLUME_MASK,
+                                      raw_vol, &changed);
+       if (ret)
+               return ret;
+
+       return changed;
+}
+
+static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56)
+{
+       struct snd_kcontrol_new ctl_template = {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = cs35l56_hda_posture_info,
+               .get = cs35l56_hda_posture_get,
+               .put = cs35l56_hda_posture_put,
+       };
+       char name[64];
+       int i;
+
+       snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name);
+       ctl_template.name = name;
+       cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56);
+       if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl))
+               dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
+
+       /* Mixer controls */
+       ctl_template.info = cs35l56_hda_mixer_info;
+       ctl_template.get = cs35l56_hda_mixer_get;
+       ctl_template.put = cs35l56_hda_mixer_put;
+
+       BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls));
+
+       for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) {
+               snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name,
+                        cs35l56_hda_mixer_controls[i].name);
+               ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg;
+               cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56);
+               if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) {
+                       dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n",
+                               ctl_template.name);
+               }
+       }
+
+       ctl_template.info = cs35l56_hda_vol_info;
+       ctl_template.get = cs35l56_hda_vol_get;
+       ctl_template.put = cs35l56_hda_vol_put;
+       ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ);
+       ctl_template.tlv.p = cs35l56_hda_vol_tlv;
+       snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name);
+       ctl_template.name = name;
+       cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56);
+       if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl))
+               dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
+}
+
+static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)
+{
+       int i;
+
+       for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--)
+               snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]);
+
+       snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl);
+       snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);
+}
+
+static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
+       .control_remove = hda_cs_dsp_control_remove,
+};
+
+static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
+                                            const struct firmware **firmware, char **filename,
+                                            const char *dir, const char *system_name,
+                                            const char *amp_name,
+                                            const char *filetype)
+{
+       char *s, c;
+       int ret = 0;
+
+       if (system_name && amp_name)
+               *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s-%s.%s", dir,
+                                     cs35l56->base.secured ? "s" : "", cs35l56->base.rev,
+                                     system_name, amp_name, filetype);
+       else if (system_name)
+               *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc-%s.%s", dir,
+                                     cs35l56->base.secured ? "s" : "", cs35l56->base.rev,
+                                     system_name, filetype);
+       else
+               *filename = kasprintf(GFP_KERNEL, "%scs35l56%s-%02x-dsp1-misc.%s", dir,
+                                     cs35l56->base.secured ? "s" : "", cs35l56->base.rev,
+                                     filetype);
+
+       if (!*filename)
+               return -ENOMEM;
+
+       /*
+        * Make sure that filename is lower-case and any non alpha-numeric
+        * characters except full stop and forward slash 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, cs35l56->base.dev);
+       if (ret) {
+               dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename);
+               kfree(*filename);
+               *filename = NULL;
+               return ret;
+       }
+
+       dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename);
+
+       return 0;
+}
+
+static const char cirrus_dir[] = "cirrus/";
+static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
+                                              const struct firmware **wmfw_firmware,
+                                              char **wmfw_filename,
+                                              const struct firmware **coeff_firmware,
+                                              char **coeff_filename)
+{
+       const char *system_name = cs35l56->system_name;
+       const char *amp_name = cs35l56->amp_name;
+       int ret;
+
+       if (system_name && amp_name) {
+               if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+                                                      cirrus_dir, system_name, amp_name, "wmfw")) {
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         cirrus_dir, system_name, amp_name, "bin");
+                       return;
+               }
+       }
+
+       if (system_name) {
+               if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+                                                      cirrus_dir, system_name, NULL, "wmfw")) {
+                       if (amp_name)
+                               cs35l56_hda_request_firmware_file(cs35l56,
+                                                                 coeff_firmware, coeff_filename,
+                                                                 cirrus_dir, system_name,
+                                                                 amp_name, "bin");
+                       if (!*coeff_firmware)
+                               cs35l56_hda_request_firmware_file(cs35l56,
+                                                                 coeff_firmware, coeff_filename,
+                                                                 cirrus_dir, system_name,
+                                                                 NULL, "bin");
+                       return;
+               }
+       }
+
+       ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+                                               cirrus_dir, NULL, NULL, "wmfw");
+       if (!ret) {
+               cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                 cirrus_dir, NULL, NULL, "bin");
+               return;
+       }
+
+       /* When a firmware file is not found must still search for the coeff files */
+       if (system_name) {
+               if (amp_name)
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         cirrus_dir, system_name, amp_name, "bin");
+               if (!*coeff_firmware)
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         cirrus_dir, system_name, NULL, "bin");
+       }
+
+       if (!*coeff_firmware)
+               cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                 cirrus_dir, NULL, NULL, "bin");
+}
+
+static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
+                                              char *wmfw_filename,
+                                              const struct firmware *coeff_firmware,
+                                              char *coeff_filename)
+{
+       if (wmfw_firmware)
+               release_firmware(wmfw_firmware);
+       kfree(wmfw_filename);
+
+       if (coeff_firmware)
+               release_firmware(coeff_firmware);
+       kfree(coeff_filename);
+}
+
+static void cs35l56_hda_add_dsp_controls(struct cs35l56_hda *cs35l56)
+{
+       struct hda_cs_dsp_ctl_info info;
+
+       info.device_name = cs35l56->amp_name;
+       info.fw_type = HDA_CS_DSP_FW_MISC;
+       info.card = cs35l56->codec->card;
+
+       hda_cs_dsp_add_controls(&cs35l56->cs_dsp, &info);
+}
+
+static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
+{
+       const struct firmware *coeff_firmware = NULL;
+       const struct firmware *wmfw_firmware = NULL;
+       char *coeff_filename = NULL;
+       char *wmfw_filename = NULL;
+       int ret = 0;
+
+       cs35l56_hda_request_firmware_files(cs35l56, &wmfw_firmware, &wmfw_filename,
+                                          &coeff_firmware, &coeff_filename);
+
+       /* Nothing to do - no firmware files were found to download */
+       if (!wmfw_filename && !coeff_filename)
+               return 0;
+
+       mutex_lock(&cs35l56->base.irq_lock);
+       pm_runtime_get_sync(cs35l56->base.dev);
+
+       /*
+        * When the device is running in secure mode the firmware files can
+        * only contain insecure tunings and therefore we do not need to
+        * shutdown the firmware to apply them and can use the lower cost
+        * reinit sequence instead.
+        */
+       if (!cs35l56->base.secured) {
+               ret = cs35l56_firmware_shutdown(&cs35l56->base);
+               if (ret)
+                       goto err;
+       }
+
+       ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
+                             coeff_firmware, coeff_filename, "misc");
+       if (ret) {
+               dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
+               goto err;
+       }
+
+       if (wmfw_filename)
+               dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);
+
+       if (coeff_filename)
+               dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
+
+       ret = cs_dsp_run(&cs35l56->cs_dsp);
+       if (ret) {
+               dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
+               goto err;
+       }
+
+       if (cs35l56->base.secured) {
+               ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
+               if (ret)
+                       goto err;
+       } else {
+               /* Reset the device and wait for it to boot */
+               cs35l56_system_reset(&cs35l56->base, false);
+               ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
+               if (ret)
+                       goto err;
+       }
+
+       /* Disable auto-hibernate so that runtime_pm has control */
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+       if (ret)
+               goto err;
+
+       regcache_mark_dirty(cs35l56->base.regmap);
+       regcache_sync(cs35l56->base.regmap);
+
+       regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS,
+                         CS35L56_FIRMWARE_MISSING);
+       cs35l56->base.fw_patched = true;
+err:
+       pm_runtime_put(cs35l56->base.dev);
+       mutex_unlock(&cs35l56->base.irq_lock);
+
+       cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
+                                          coeff_firmware, coeff_filename);
+
+       return ret;
+}
+
+static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       struct hda_component *comps = master_data;
+       int ret;
+
+       if (!comps || cs35l56->index < 0 || cs35l56->index >= HDA_MAX_COMPONENTS)
+               return -EINVAL;
+
+       comps = &comps[cs35l56->index];
+       if (comps->dev)
+               return -EBUSY;
+
+       comps->dev = dev;
+       cs35l56->codec = comps->codec;
+       strscpy(comps->name, dev_name(dev), sizeof(comps->name));
+       comps->playback_hook = cs35l56_hda_playback_hook;
+
+       ret = cs35l56_hda_fw_load(cs35l56);
+       if (ret)
+               return ret;
+
+       cs35l56_hda_create_controls(cs35l56);
+       cs35l56_hda_add_dsp_controls(cs35l56);
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+       cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);
+       cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
+#endif
+
+       dev_dbg(cs35l56->base.dev, "Bound\n");
+
+       return 0;
+}
+
+static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       struct hda_component *comps = master_data;
+
+       cs35l56_hda_remove_controls(cs35l56);
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+       cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);
+       debugfs_remove_recursive(cs35l56->debugfs_root);
+#endif
+
+       cs_dsp_remove(&cs35l56->cs_dsp);
+
+       if (comps[cs35l56->index].dev == dev)
+               memset(&comps[cs35l56->index], 0, sizeof(*comps));
+
+       dev_dbg(cs35l56->base.dev, "Unbound\n");
+}
+
+static const struct component_ops cs35l56_hda_comp_ops = {
+       .bind = cs35l56_hda_bind,
+       .unbind = cs35l56_hda_unbind,
+};
+
+static int cs35l56_hda_system_suspend(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       if (cs35l56->playing)
+               cs35l56_hda_pause(cs35l56);
+
+       cs35l56->suspended = true;
+
+       /*
+        * The interrupt line is normally shared, but after we start suspending
+        * we can't check if our device is the source of an interrupt, and can't
+        * clear it. Prevent this race by temporarily disabling the parent irq
+        * until we reach _no_irq.
+        */
+       if (cs35l56->base.irq)
+               disable_irq(cs35l56->base.irq);
+
+       return pm_runtime_force_suspend(dev);
+}
+
+static int cs35l56_hda_system_suspend_late(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /*
+        * RESET is usually shared by all amps so it must not be asserted until
+        * all driver instances have done their suspend() stage.
+        */
+       if (cs35l56->base.reset_gpio) {
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+               cs35l56_wait_min_reset_pulse();
+       }
+
+       return 0;
+}
+
+static int cs35l56_hda_system_suspend_no_irq(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
+       if (cs35l56->base.irq)
+               enable_irq(cs35l56->base.irq);
+
+       return 0;
+}
+
+static int cs35l56_hda_system_resume_no_irq(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /*
+        * WAKE interrupts unmask if the CS35L56 hibernates, which can cause
+        * spurious interrupts, and the interrupt line is normally shared.
+        * We can't check if our device is the source of an interrupt, and can't
+        * clear it, until it has fully resumed. Prevent this race by temporarily
+        * disabling the parent irq until we complete resume().
+        */
+       if (cs35l56->base.irq)
+               disable_irq(cs35l56->base.irq);
+
+       return 0;
+}
+
+static int cs35l56_hda_system_resume_early(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /* Ensure a spec-compliant RESET pulse. */
+       if (cs35l56->base.reset_gpio) {
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+               cs35l56_wait_min_reset_pulse();
+
+               /* Release shared RESET before drivers start resume(). */
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
+               cs35l56_wait_control_port_ready();
+       }
+
+       return 0;
+}
+
+static int cs35l56_hda_system_resume(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       int ret;
+
+       /* Undo pm_runtime_force_suspend() before re-enabling the irq */
+       ret = pm_runtime_force_resume(dev);
+       if (cs35l56->base.irq)
+               enable_irq(cs35l56->base.irq);
+
+       if (ret)
+               return ret;
+
+       cs35l56->suspended = false;
+
+       ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
+       dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
+       if (ret > 0) {
+               ret = cs35l56_hda_fw_load(cs35l56);
+               if (ret)
+                       return ret;
+       }
+
+       if (cs35l56->playing)
+               cs35l56_hda_play(cs35l56);
+
+       return 0;
+}
+
+static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id)
+{
+       u32 values[HDA_MAX_COMPONENTS];
+       struct acpi_device *adev;
+       const char *property, *sub;
+       size_t nval;
+       int i, ret;
+
+       /*
+        * ACPI_COMPANION isn't available when this driver was instantiated by
+        * the serial-multi-instantiate driver, so lookup the node by HID
+        */
+       if (!ACPI_COMPANION(cs35l56->base.dev)) {
+               adev = acpi_dev_get_first_match_dev("CSC3556", NULL, -1);
+               if (!adev) {
+                       dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
+                               dev_name(cs35l56->base.dev));
+                       return -ENODEV;
+               }
+               ACPI_COMPANION_SET(cs35l56->base.dev, adev);
+       }
+
+       property = "cirrus,dev-index";
+       ret = device_property_count_u32(cs35l56->base.dev, property);
+       if (ret <= 0)
+               goto err;
+
+       if (ret > ARRAY_SIZE(values)) {
+               ret = -EINVAL;
+               goto err;
+       }
+       nval = ret;
+
+       ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
+       if (ret)
+               goto err;
+
+       cs35l56->index = -1;
+       for (i = 0; i < nval; i++) {
+               if (values[i] == id) {
+                       cs35l56->index = i;
+                       break;
+               }
+       }
+       if (cs35l56->index == -1) {
+               dev_err(cs35l56->base.dev, "No index found in %s\n", property);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
+
+       if (IS_ERR(sub)) {
+               /* If no ACPI SUB, return 0 and fallback to legacy firmware path, otherwise fail */
+               if (PTR_ERR(sub) == -ENODATA)
+                       return 0;
+               else
+                       return PTR_ERR(sub);
+       }
+
+       cs35l56->system_name = sub;
+
+       cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,
+                                                                "reset",
+                                                                cs35l56->index,
+                                                                GPIOD_OUT_LOW);
+       if (IS_ERR(cs35l56->base.reset_gpio)) {
+               ret = PTR_ERR(cs35l56->base.reset_gpio);
+
+               /*
+                * If RESET is shared the first amp to probe will grab the reset
+                * line and reset all the amps
+                */
+               if (ret != -EBUSY)
+                       return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
+
+               dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
+               cs35l56->base.reset_gpio = NULL;
+       }
+
+       return 0;
+
+err:
+       dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);
+
+       return ret;
+}
+
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id)
+{
+       int ret;
+
+       mutex_init(&cs35l56->base.irq_lock);
+       dev_set_drvdata(cs35l56->base.dev, cs35l56);
+
+       ret = cs35l56_hda_read_acpi(cs35l56, id);
+       if (ret) {
+               dev_err_probe(cs35l56->base.dev, ret, "Platform not supported\n");
+               goto err;
+       }
+
+       cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",
+                                          cs35l56->index + 1);
+       if (!cs35l56->amp_name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
+       cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
+
+       if (cs35l56->base.reset_gpio) {
+               dev_dbg(cs35l56->base.dev, "Hard reset\n");
+
+               /*
+                * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the
+                * ACPI defines a different default state. So explicitly set low.
+                */
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+               cs35l56_wait_min_reset_pulse();
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
+       }
+
+       ret = cs35l56_hw_init(&cs35l56->base);
+       if (ret < 0)
+               goto err;
+
+       /* Reset the device and wait for it to boot */
+       cs35l56_system_reset(&cs35l56->base, false);
+       ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
+       if (ret)
+               goto err;
+
+       ret = cs35l56_set_patch(&cs35l56->base);
+       if (ret)
+               return ret;
+
+       regcache_mark_dirty(cs35l56->base.regmap);
+       regcache_sync(cs35l56->base.regmap);
+
+       /* Disable auto-hibernate so that runtime_pm has control */
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+       if (ret)
+               goto err;
+
+       ret = cs_dsp_halo_init(&cs35l56->cs_dsp);
+       if (ret) {
+               dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");
+               goto err;
+       }
+
+       dev_dbg(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
+               cs35l56->system_name, cs35l56->amp_name);
+
+       regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
+                              ARRAY_SIZE(cs35l56_hda_dai_config));
+
+       /*
+        * By default only enable one ASP1TXn, where n=amplifier index,
+        * This prevents multiple amps trying to drive the same slot.
+        */
+       cs35l56->asp_tx_mask = BIT(cs35l56->index);
+
+       pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);
+       pm_runtime_use_autosuspend(cs35l56->base.dev);
+       pm_runtime_set_active(cs35l56->base.dev);
+       pm_runtime_mark_last_busy(cs35l56->base.dev);
+       pm_runtime_enable(cs35l56->base.dev);
+
+       ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
+       if (ret) {
+               dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
+               goto pm_err;
+       }
+
+       cs35l56->base.init_done = true;
+
+       return 0;
+
+pm_err:
+       pm_runtime_disable(cs35l56->base.dev);
+err:
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, SND_HDA_SCODEC_CS35L56);
+
+void cs35l56_hda_remove(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       pm_runtime_get_sync(cs35l56->base.dev);
+       pm_runtime_disable(cs35l56->base.dev);
+
+       component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);
+
+       kfree(cs35l56->system_name);
+       pm_runtime_put_noidle(cs35l56->base.dev);
+
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56);
+
+const struct dev_pm_ops cs35l56_hda_pm_ops = {
+       SET_RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)
+       LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,
+                                cs35l56_hda_system_resume_early)
+       NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,
+                                 cs35l56_hda_system_resume_no_irq)
+};
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56);
+
+MODULE_DESCRIPTION("CS35L56 HDA Driver");
+MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS);
+MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(FW_CS_DSP);
diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h
new file mode 100644 (file)
index 0000000..6e5bc53
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * HDA audio driver for Cirrus Logic CS35L56 smart amp
+ *
+ * Copyright (C) 2023 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __CS35L56_HDA_H__
+#define __CS35L56_HDA_H__
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/regulator/consumer.h>
+#include <sound/cs35l56.h>
+
+struct dentry;
+
+struct cs35l56_hda {
+       struct cs35l56_base base;
+       struct hda_codec *codec;
+
+       int index;
+       const char *system_name;
+       const char *amp_name;
+
+       struct cs_dsp cs_dsp;
+       bool playing;
+       bool suspended;
+       u8 asp_tx_mask;
+
+       struct snd_kcontrol *posture_ctl;
+       struct snd_kcontrol *volume_ctl;
+       struct snd_kcontrol *mixer_ctl[4];
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+       struct dentry *debugfs_root;
+#endif
+};
+
+extern const struct dev_pm_ops cs35l56_hda_pm_ops;
+
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id);
+void cs35l56_hda_remove(struct device *dev);
+
+#endif /*__CS35L56_HDA_H__*/
diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c
new file mode 100644 (file)
index 0000000..83e4acd
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// CS35L56 HDA audio driver I2C binding
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "cs35l56_hda.h"
+
+static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
+{
+       struct cs35l56_hda *cs35l56;
+       int ret;
+
+       cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL);
+       if (!cs35l56)
+               return -ENOMEM;
+
+       cs35l56->base.dev = &clt->dev;
+       cs35l56->base.can_hibernate = true;
+       cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
+               dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = cs35l56_hda_common_probe(cs35l56, clt->addr);
+       if (ret)
+               return ret;
+       ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
+       if (ret < 0)
+               cs35l56_hda_remove(cs35l56->base.dev);
+
+       return ret;
+}
+
+static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
+{
+       cs35l56_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
+       { "cs35l56-hda", 0 },
+       {}
+};
+
+static struct i2c_driver cs35l56_hda_i2c_driver = {
+       .driver = {
+               .name           = "cs35l56-hda",
+               .pm             = &cs35l56_hda_pm_ops,
+       },
+       .id_table       = cs35l56_hda_i2c_id,
+       .probe          = cs35l56_hda_i2c_probe,
+       .remove         = cs35l56_hda_i2c_remove,
+};
+module_i2c_driver(cs35l56_hda_i2c_driver);
+
+MODULE_DESCRIPTION("HDA CS35L56 I2C driver");
+MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56);
+MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c
new file mode 100644 (file)
index 0000000..756aec3
--- /dev/null
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// CS35L56 HDA audio driver SPI binding
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "cs35l56_hda.h"
+
+static int cs35l56_hda_spi_probe(struct spi_device *spi)
+{
+       struct cs35l56_hda *cs35l56;
+       int ret;
+
+       cs35l56 = devm_kzalloc(&spi->dev, sizeof(*cs35l56), GFP_KERNEL);
+       if (!cs35l56)
+               return -ENOMEM;
+
+       cs35l56->base.dev = &spi->dev;
+       cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
+               dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = cs35l56_hda_common_probe(cs35l56, spi->chip_select);
+       if (ret)
+               return ret;
+       ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
+       if (ret < 0)
+               cs35l56_hda_remove(cs35l56->base.dev);
+
+       return ret;
+}
+
+static void cs35l56_hda_spi_remove(struct spi_device *spi)
+{
+       cs35l56_hda_remove(&spi->dev);
+}
+
+static const struct spi_device_id cs35l56_hda_spi_id[] = {
+       { "cs35l56-hda", 0 },
+       {}
+};
+
+static struct spi_driver cs35l56_hda_spi_driver = {
+       .driver = {
+               .name           = "cs35l56-hda",
+               .pm             = &cs35l56_hda_pm_ops,
+       },
+       .id_table       = cs35l56_hda_spi_id,
+       .probe          = cs35l56_hda_spi_probe,
+       .remove         = cs35l56_hda_spi_remove,
+};
+module_spi_driver(cs35l56_hda_spi_driver);
+
+MODULE_DESCRIPTION("HDA CS35L56 SPI driver");
+MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56);
+MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED);
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
index df63d66af1ab1e303e4730f738d025e22ba40f4b..579b11beac718e4847c2a186ee733ee985066158 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __SOUND_HDA_AUTO_PARSER_H
 #define __SOUND_HDA_AUTO_PARSER_H
 
+#include "hda_local.h"
+
 /*
  * Helper for automatic pin configuration
  */
index 34eba40cc6e67b2573482ccb2534d8636c245301..a8eea836762990b9e1b622d6d3795b9385ca8ca3 100644 (file)
@@ -9,6 +9,9 @@
 #define __SOUND_HDA_GENERIC_H
 
 #include <linux/leds.h>
+#include "hda_auto_parser.h"
+
+struct hda_jack_callback;
 
 /* table entry for multi-io paths */
 struct hda_multi_io {
index ef831770ca7daa21fd902f3d7b4bef61c623e25a..765d95e7986171d2d2d3fed9ef2509db975f7074 100644 (file)
@@ -330,18 +330,6 @@ enum {
 #define needs_eld_notify_link(chip)    false
 #endif
 
-#define CONTROLLER_IN_GPU(pci) (((pci)->vendor == 0x8086) &&         \
-                                      (((pci)->device == 0x0a0c) || \
-                                       ((pci)->device == 0x0c0c) || \
-                                       ((pci)->device == 0x0d0c) || \
-                                       ((pci)->device == 0x160c) || \
-                                       ((pci)->device == 0x490d) || \
-                                       ((pci)->device == 0x4f90) || \
-                                       ((pci)->device == 0x4f91) || \
-                                       ((pci)->device == 0x4f92)))
-
-#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
-
 static const char * const driver_short_names[] = {
        [AZX_DRIVER_ICH] = "HDA Intel",
        [AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -573,7 +561,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
        snd_hdac_set_codec_wakeup(bus, false);
 
        /* reduce dma latency to avoid noise */
-       if (IS_BXT(pci))
+       if (HDA_CONTROLLER_IS_APL(pci))
                bxt_reduce_dma_latency(chip);
 
        if (bus->mlcap != NULL)
@@ -2175,7 +2163,7 @@ static int azx_probe(struct pci_dev *pci,
 #endif /* CONFIG_SND_HDA_PATCH_LOADER */
 
 #ifndef CONFIG_SND_HDA_I915
-       if (CONTROLLER_IN_GPU(pci))
+       if (HDA_CONTROLLER_IN_GPU(pci))
                dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
 #endif
 
@@ -2283,7 +2271,7 @@ static int azx_probe_continue(struct azx *chip)
                         * for other chips, still continue probing as other
                         * codecs can be on the same link.
                         */
-                       if (CONTROLLER_IN_GPU(pci)) {
+                       if (HDA_CONTROLLER_IN_GPU(pci)) {
                                dev_err(chip->card->dev,
                                        "HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");
                                goto out_free;
@@ -2294,7 +2282,7 @@ static int azx_probe_continue(struct azx *chip)
                }
 
                /* HSW/BDW controllers need this power */
-               if (CONTROLLER_IN_GPU(pci))
+               if (HDA_CONTROLLER_IN_GPU(pci))
                        hda->need_i915_power = true;
        }
 
@@ -2428,333 +2416,262 @@ static void azx_shutdown(struct pci_dev *pci)
 /* PCI IDs */
 static const struct pci_device_id azx_ids[] = {
        /* CPT */
-       { PCI_DEVICE(0x8086, 0x1c20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       { PCI_DEVICE_DATA(INTEL, HDA_CPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
        /* PBG */
-       { PCI_DEVICE(0x8086, 0x1d20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       { PCI_DEVICE_DATA(INTEL, HDA_PBG, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
        /* Panther Point */
-       { PCI_DEVICE(0x8086, 0x1e20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       { PCI_DEVICE_DATA(INTEL, HDA_PPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
        /* Lynx Point */
-       { PCI_DEVICE(0x8086, 0x8c20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       { PCI_DEVICE_DATA(INTEL, HDA_LPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
        /* 9 Series */
-       { PCI_DEVICE(0x8086, 0x8ca0),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       { PCI_DEVICE_DATA(INTEL, HDA_9_SERIES, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
        /* Wellsburg */
-       { PCI_DEVICE(0x8086, 0x8d20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
-       { PCI_DEVICE(0x8086, 0x8d21),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       { PCI_DEVICE_DATA(INTEL, HDA_WBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
+       { PCI_DEVICE_DATA(INTEL, HDA_WBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
        /* Lewisburg */
-       { PCI_DEVICE(0x8086, 0xa1f0),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
-       { PCI_DEVICE(0x8086, 0xa270),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
+       { PCI_DEVICE_DATA(INTEL, HDA_LBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_LBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Lynx Point-LP */
-       { PCI_DEVICE(0x8086, 0x9c20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
        /* Lynx Point-LP */
-       { PCI_DEVICE(0x8086, 0x9c21),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+       { PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
        /* Wildcat Point-LP */
-       { PCI_DEVICE(0x8086, 0x9ca0),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
-       /* Sunrise Point */
-       { PCI_DEVICE(0x8086, 0xa170),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
-       /* Sunrise Point-LP */
-       { PCI_DEVICE(0x8086, 0x9d70),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+       { PCI_DEVICE_DATA(INTEL, HDA_WPT_LP, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
+       /* Skylake (Sunrise Point) */
+       { PCI_DEVICE_DATA(INTEL, HDA_SKL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       /* Skylake-LP (Sunrise Point-LP) */
+       { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Kabylake */
-       { PCI_DEVICE(0x8086, 0xa171),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Kabylake-LP */
-       { PCI_DEVICE(0x8086, 0x9d71),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Kabylake-H */
-       { PCI_DEVICE(0x8086, 0xa2f0),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Coffelake */
-       { PCI_DEVICE(0x8086, 0xa348),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Cannonlake */
-       { PCI_DEVICE(0x8086, 0x9dc8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* CometLake-LP */
-       { PCI_DEVICE(0x8086, 0x02C8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* CometLake-H */
-       { PCI_DEVICE(0x8086, 0x06C8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0xf1c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RKL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* CometLake-S */
-       { PCI_DEVICE(0x8086, 0xa3f0),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* CometLake-R */
-       { PCI_DEVICE(0x8086, 0xf0c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_R, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Icelake */
-       { PCI_DEVICE(0x8086, 0x34c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Icelake-H */
-       { PCI_DEVICE(0x8086, 0x3dc8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Jasperlake */
-       { PCI_DEVICE(0x8086, 0x38c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x4dc8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Tigerlake */
-       { PCI_DEVICE(0x8086, 0xa0c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Tigerlake-H */
-       { PCI_DEVICE(0x8086, 0x43c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* DG1 */
-       { PCI_DEVICE(0x8086, 0x490d),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_DG1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* DG2 */
-       { PCI_DEVICE(0x8086, 0x4f90),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x4f91),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x4f92),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_DG2_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_DG2_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_DG2_2, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Alderlake-S */
-       { PCI_DEVICE(0x8086, 0x7ad0),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Alderlake-P */
-       { PCI_DEVICE(0x8086, 0x51c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x51c9),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x51cd),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Alderlake-M */
-       { PCI_DEVICE(0x8086, 0x51cc),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Alderlake-N */
-       { PCI_DEVICE(0x8086, 0x54c8),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Elkhart Lake */
-       { PCI_DEVICE(0x8086, 0x4b55),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x4b58),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Raptor Lake */
-       { PCI_DEVICE(0x8086, 0x7a50),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x51ca),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x51cb),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x51ce),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       { PCI_DEVICE(0x8086, 0x51cf),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       /* Meteorlake-P */
-       { PCI_DEVICE(0x8086, 0x7e28),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       { PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
        /* Lunarlake-P */
-       { PCI_DEVICE(0x8086, 0xa828),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
-       /* Broxton-P(Apollolake) */
-       { PCI_DEVICE(0x8086, 0x5a98),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
-       /* Broxton-T */
-       { PCI_DEVICE(0x8086, 0x1a98),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+       { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       /* Arrow Lake-S */
+       { PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
+       /* Apollolake (Broxton-P) */
+       { PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
        /* Gemini-Lake */
-       { PCI_DEVICE(0x8086, 0x3198),
-         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
+       { PCI_DEVICE_DATA(INTEL, HDA_GML, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
        /* Haswell */
-       { PCI_DEVICE(0x8086, 0x0a0c),
-         .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
-       { PCI_DEVICE(0x8086, 0x0c0c),
-         .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
-       { PCI_DEVICE(0x8086, 0x0d0c),
-         .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
+       { PCI_DEVICE_DATA(INTEL, HDA_HSW_0, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
+       { PCI_DEVICE_DATA(INTEL, HDA_HSW_2, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
+       { PCI_DEVICE_DATA(INTEL, HDA_HSW_3, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
        /* Broadwell */
-       { PCI_DEVICE(0x8086, 0x160c),
-         .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL },
+       { PCI_DEVICE_DATA(INTEL, HDA_BDW, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL) },
        /* 5 Series/3400 */
-       { PCI_DEVICE(0x8086, 0x3b56),
-         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
-       { PCI_DEVICE(0x8086, 0x3b57),
-         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_0, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) },
+       { PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_1, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) },
        /* Poulsbo */
-       { PCI_DEVICE(0x8086, 0x811b),
-         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE |
-         AZX_DCAPS_POSFIX_LPIB },
+       { PCI_DEVICE_DATA(INTEL, HDA_POULSBO, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE |
+         AZX_DCAPS_POSFIX_LPIB) },
        /* Oaktrail */
-       { PCI_DEVICE(0x8086, 0x080a),
-         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
+       { PCI_DEVICE_DATA(INTEL, HDA_OAKTRAIL, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE) },
        /* BayTrail */
-       { PCI_DEVICE(0x8086, 0x0f04),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL },
+       { PCI_DEVICE_DATA(INTEL, HDA_BYT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL) },
        /* Braswell */
-       { PCI_DEVICE(0x8086, 0x2284),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL },
+       { PCI_DEVICE_DATA(INTEL, HDA_BSW, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL) },
        /* ICH6 */
-       { PCI_DEVICE(0x8086, 0x2668),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH6, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ICH7 */
-       { PCI_DEVICE(0x8086, 0x27d8),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH7, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ESB2 */
-       { PCI_DEVICE(0x8086, 0x269a),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ESB2, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ICH8 */
-       { PCI_DEVICE(0x8086, 0x284b),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH8, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ICH9 */
-       { PCI_DEVICE(0x8086, 0x293e),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH9_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ICH9 */
-       { PCI_DEVICE(0x8086, 0x293f),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH9_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ICH10 */
-       { PCI_DEVICE(0x8086, 0x3a3e),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH10_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* ICH10 */
-       { PCI_DEVICE(0x8086, 0x3a6e),
-         .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICH10_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
        /* Generic Intel */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE },
        /* ATI SB 450/600/700/800/900 */
-       { PCI_DEVICE(0x1002, 0x437b),
+       { PCI_VDEVICE(ATI, 0x437b),
          .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
-       { PCI_DEVICE(0x1002, 0x4383),
+       { PCI_VDEVICE(ATI, 0x4383),
          .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
        /* AMD Hudson */
-       { PCI_DEVICE(0x1022, 0x780d),
+       { PCI_VDEVICE(AMD, 0x780d),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* AMD, X370 & co */
-       { PCI_DEVICE(0x1022, 0x1457),
+       { PCI_VDEVICE(AMD, 0x1457),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
        /* AMD, X570 & co */
-       { PCI_DEVICE(0x1022, 0x1487),
+       { PCI_VDEVICE(AMD, 0x1487),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
        /* AMD Stoney */
-       { PCI_DEVICE(0x1022, 0x157a),
+       { PCI_VDEVICE(AMD, 0x157a),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
                         AZX_DCAPS_PM_RUNTIME },
        /* AMD Raven */
-       { PCI_DEVICE(0x1022, 0x15e3),
+       { PCI_VDEVICE(AMD, 0x15e3),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
        /* ATI HDMI */
-       { PCI_DEVICE(0x1002, 0x0002),
+       { PCI_VDEVICE(ATI, 0x0002),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0x1308),
+       { PCI_VDEVICE(ATI, 0x1308),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0x157a),
+       { PCI_VDEVICE(ATI, 0x157a),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0x15b3),
+       { PCI_VDEVICE(ATI, 0x15b3),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0x793b),
+       { PCI_VDEVICE(ATI, 0x793b),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0x7919),
+       { PCI_VDEVICE(ATI, 0x7919),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0x960f),
+       { PCI_VDEVICE(ATI, 0x960f),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0x970f),
+       { PCI_VDEVICE(ATI, 0x970f),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0x9840),
+       { PCI_VDEVICE(ATI, 0x9840),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0xaa00),
+       { PCI_VDEVICE(ATI, 0xaa00),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa08),
+       { PCI_VDEVICE(ATI, 0xaa08),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa10),
+       { PCI_VDEVICE(ATI, 0xaa10),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa18),
+       { PCI_VDEVICE(ATI, 0xaa18),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa20),
+       { PCI_VDEVICE(ATI, 0xaa20),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa28),
+       { PCI_VDEVICE(ATI, 0xaa28),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa30),
+       { PCI_VDEVICE(ATI, 0xaa30),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa38),
+       { PCI_VDEVICE(ATI, 0xaa38),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa40),
+       { PCI_VDEVICE(ATI, 0xaa40),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa48),
+       { PCI_VDEVICE(ATI, 0xaa48),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa50),
+       { PCI_VDEVICE(ATI, 0xaa50),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa58),
+       { PCI_VDEVICE(ATI, 0xaa58),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa60),
+       { PCI_VDEVICE(ATI, 0xaa60),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa68),
+       { PCI_VDEVICE(ATI, 0xaa68),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa80),
+       { PCI_VDEVICE(ATI, 0xaa80),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa88),
+       { PCI_VDEVICE(ATI, 0xaa88),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa90),
+       { PCI_VDEVICE(ATI, 0xaa90),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0xaa98),
+       { PCI_VDEVICE(ATI, 0xaa98),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
-       { PCI_DEVICE(0x1002, 0x9902),
+       { PCI_VDEVICE(ATI, 0x9902),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0xaaa0),
+       { PCI_VDEVICE(ATI, 0xaaa0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0xaaa8),
+       { PCI_VDEVICE(ATI, 0xaaa8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0xaab0),
+       { PCI_VDEVICE(ATI, 0xaab0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
-       { PCI_DEVICE(0x1002, 0xaac0),
+       { PCI_VDEVICE(ATI, 0xaac0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xaac8),
+       { PCI_VDEVICE(ATI, 0xaac8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xaad8),
+       { PCI_VDEVICE(ATI, 0xaad8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xaae0),
+       { PCI_VDEVICE(ATI, 0xaae0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xaae8),
+       { PCI_VDEVICE(ATI, 0xaae8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xaaf0),
+       { PCI_VDEVICE(ATI, 0xaaf0),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xaaf8),
+       { PCI_VDEVICE(ATI, 0xaaf8),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab00),
+       { PCI_VDEVICE(ATI, 0xab00),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab08),
+       { PCI_VDEVICE(ATI, 0xab08),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab10),
+       { PCI_VDEVICE(ATI, 0xab10),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab18),
+       { PCI_VDEVICE(ATI, 0xab18),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab20),
+       { PCI_VDEVICE(ATI, 0xab20),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab28),
+       { PCI_VDEVICE(ATI, 0xab28),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab30),
+       { PCI_VDEVICE(ATI, 0xab30),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
-       { PCI_DEVICE(0x1002, 0xab38),
+       { PCI_VDEVICE(ATI, 0xab38),
          .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
          AZX_DCAPS_PM_RUNTIME },
        /* GLENFLY */
@@ -2764,15 +2681,15 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB |
          AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
        /* VIA VT8251/VT8237A */
-       { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
+       { PCI_VDEVICE(VIA, 0x3288), .driver_data = AZX_DRIVER_VIA },
        /* VIA GFX VT7122/VX900 */
-       { PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
        /* VIA GFX VT6122/VX11 */
-       { PCI_DEVICE(0x1106, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
        /* SIS966 */
-       { PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
+       { PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS },
        /* ULI M5461 */
-       { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
+       { PCI_VDEVICE(AL, 0x5461), .driver_data = AZX_DRIVER_ULI },
        /* NVIDIA MCP */
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
@@ -2785,9 +2702,9 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
        /* Creative X-Fi (CA0110-IBG) */
        /* CTHDA chips */
-       { PCI_DEVICE(0x1102, 0x0010),
+       { PCI_VDEVICE(CREATIVE, 0x0010),
          .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
-       { PCI_DEVICE(0x1102, 0x0012),
+       { PCI_VDEVICE(CREATIVE, 0x0012),
          .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
 #if !IS_ENABLED(CONFIG_SND_CTXFI)
        /* the following entry conflicts with snd-ctxfi driver,
@@ -2801,18 +2718,18 @@ static const struct pci_device_id azx_ids[] = {
          AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
-       { PCI_DEVICE(0x1102, 0x0009),
+       { PCI_VDEVICE(CREATIVE, 0x0009),
          .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
          AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
 #endif
        /* CM8888 */
-       { PCI_DEVICE(0x13f6, 0x5011),
+       { PCI_VDEVICE(CMEDIA, 0x5011),
          .driver_data = AZX_DRIVER_CMEDIA |
          AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF },
        /* Vortex86MX */
-       { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_VDEVICE(RDC, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
        /* VMware HDAudio */
-       { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_VDEVICE(VMWARE, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
        /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
@@ -2823,11 +2740,11 @@ static const struct pci_device_id azx_ids[] = {
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
        /* Zhaoxin */
-       { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
+       { PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
        /* Loongson HDAudio*/
-       {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA),
+       { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA),
          .driver_data = AZX_DRIVER_LOONGSON },
-       {PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
+       { PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
          .driver_data = AZX_DRIVER_LOONGSON },
        { 0, }
 };
index bfa9622e1ab1e565ee96c74381754d05ac493d92..439fa631c342ad76dbd5f4974bc28396e9863d57 100644 (file)
@@ -38,6 +38,17 @@ config SND_SOC_TOPOLOGY
        bool
        select SND_DYNAMIC_MINORS
 
+config SND_SOC_TOPOLOGY_BUILD
+       bool "Build topology core"
+       select SND_SOC_TOPOLOGY
+       depends on KUNIT
+       help
+         This option exists to facilitate running the KUnit tests for
+         the topology core, KUnit is frequently tested in virtual
+         environments with minimal drivers enabled but the topology
+         core is usually selected by drivers.  There is little reason
+         to enable it if not doing a KUnit build.
+
 config SND_SOC_TOPOLOGY_KUNIT_TEST
        tristate "KUnit tests for SoC topology"
        depends on KUNIT
index d5b6f5187f8e8e0bec237daa3b8d2bb5e034e340..7b25630757436ae9cda45ffaa8691dc2f836553a 100644 (file)
@@ -147,6 +147,7 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
+       .probe = axi_i2s_dai_probe,
        .startup = axi_i2s_startup,
        .shutdown = axi_i2s_shutdown,
        .trigger = axi_i2s_trigger,
@@ -154,7 +155,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver axi_i2s_dai = {
-       .probe = axi_i2s_dai_probe,
        .ops = &axi_i2s_dai_ops,
        .symmetric_rate = 1,
 };
index e4c99bbc9cdd1b684de8f5be2f721b3292a4e35a..10545bd99704252461c7f4c2e61d5b22eca81af3 100644 (file)
@@ -148,6 +148,7 @@ static void axi_spdif_shutdown(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
+       .probe = axi_spdif_dai_probe,
        .startup = axi_spdif_startup,
        .shutdown = axi_spdif_shutdown,
        .trigger = axi_spdif_trigger,
@@ -155,7 +156,6 @@ static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
 };
 
 static struct snd_soc_dai_driver axi_spdif_dai = {
-       .probe = axi_spdif_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index 1dd8579e803474502e35d92fab5a6a9b5a505727..273688c053172f267ca63e82eea4c1d778e41c04 100644 (file)
@@ -79,14 +79,15 @@ config SND_SOC_AMD_ACP5x
         ACP DMA driver, CPU DAI driver.
 
 config SND_SOC_AMD_VANGOGH_MACH
-       tristate "AMD Vangogh support for NAU8821 CS35L41"
+       tristate "AMD Vangogh support for NAU8821/CS35L41/MAX98388"
        select SND_SOC_NAU8821
        select SND_SOC_CS35L41_SPI
+       select SND_SOC_MAX98388
        select SND_AMD_ACP_CONFIG
        depends on SND_SOC_AMD_ACP5x && I2C && SPI_MASTER
        help
          This option enables machine driver for Vangogh platform
-         using NAU8821 and CS35L41 codecs.
+         using NAU8821 and either CS35L41 or MAX98388 codecs.
          Say m if you have such a device.
          If unsure select "N".
 
index 0932473b63945fb3eda1ac6087245e6daa1f71ff..f27c2758000917b3f39b5962029dcdad9ed339b8 100644 (file)
@@ -47,6 +47,20 @@ static const struct config_entry config_table[] = {
                        {}
                },
        },
+       {
+               .flags = FLAG_AMD_SOF,
+               .device = ACP_PCI_DEV_ID,
+               .dmi_table = (const struct dmi_system_id []) {
+                       {
+                               .matches = {
+                                       DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+                                       DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+                                       DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"),
+                               },
+                       },
+                       {}
+               },
+       },
 };
 
 int snd_amd_acp_find_config(struct pci_dev *pci)
@@ -82,6 +96,11 @@ static struct snd_soc_acpi_codecs amp_max = {
        .codecs = {"MX98360A"}
 };
 
+static struct snd_soc_acpi_codecs amp_max98388 = {
+       .num_codecs = 1,
+       .codecs = {"ADS8388"}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = {
        {
                .id = "10EC5682",
@@ -130,6 +149,20 @@ 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_vangogh_sof_machines[] = {
+       {
+               .id = "NVTN2020",
+               .drv_name = "nau8821-max",
+               .pdata = &acp_quirk_data,
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_max98388,
+               .fw_filename = "sof-vangogh.ri",
+               .sof_tplg_filename = "sof-vangogh-nau8821-max.tplg",
+       },
+       {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_vangogh_sof_machines);
+
 struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = {
        {
                .id = "AMDI1019",
index 7464ca2b596c7c4c30282ff4a400a8d896df3798..9e3133bec2b158ab8cb2f572c9a8cc5fbdfa307c 100644 (file)
 #define RT5682_PLL_FREQ (48000 * 512)
 
 static struct snd_soc_jack cz_jack;
+static struct snd_soc_jack_pin cz_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Line Out",
+               .mask = SND_JACK_LINEOUT,
+       },
+};
+
 static struct clk *da7219_dai_wclk;
 static struct clk *da7219_dai_bclk;
 static struct clk *rt5682_dai_wclk;
@@ -66,11 +81,13 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
        if (IS_ERR(da7219_dai_bclk))
                return PTR_ERR(da7219_dai_bclk);
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                               SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                               SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                               &cz_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &cz_jack,
+                                        cz_jack_pins,
+                                        ARRAY_SIZE(cz_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
@@ -146,11 +163,13 @@ static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd)
        if (IS_ERR(rt5682_dai_bclk))
                return PTR_ERR(rt5682_dai_bclk);
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &cz_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &cz_jack,
+                                        cz_jack_pins,
+                                        ARRAY_SIZE(cz_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
@@ -631,6 +650,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
 static const struct snd_soc_dapm_widget cz_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_MIC("Int Mic", NULL),
 };
@@ -654,6 +674,7 @@ static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = {
 static const struct snd_kcontrol_new cz_mc_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphones"),
        SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Int Mic"),
 };
index 532aa98a2241cbfad07d003dbffa2ecf9bda33c8..c8ed1e0b1ccd015ba23fe853c142da963a81b1ca 100644 (file)
 #define CZ_PLAT_CLK 24000000
 
 static struct snd_soc_jack cz_jack;
+static struct snd_soc_jack_pin cz_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
 
 static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
@@ -76,11 +86,13 @@ static int cz_init(struct snd_soc_pcm_runtime *rtd)
        codec = asoc_rtd_to_codec(rtd, 0)->component;
        card = rtd->card;
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                               SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                               SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                               &cz_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &cz_jack,
+                                        cz_jack_pins,
+                                        ARRAY_SIZE(cz_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
index ce003781074311f9451ff0bc97213ec611354d18..631cdf96d637629cdb6606ed8652c79f3644331c 100644 (file)
@@ -18,6 +18,9 @@ if SND_SOC_AMD_ACP_COMMON
 config SND_SOC_AMD_ACP_PDM
        tristate
 
+config SND_SOC_AMD_ACP_LEGACY_COMMON
+       tristate
+
 config SND_SOC_AMD_ACP_I2S
        tristate
 
@@ -27,6 +30,7 @@ config SND_SOC_AMD_ACP_PCM
 
 config SND_SOC_AMD_ACP_PCI
        tristate "AMD ACP PCI Driver Support"
+       select SND_SOC_AMD_ACP_LEGACY_COMMON
        depends on X86 && PCI
        help
          This options enables generic PCI driver for ACP device.
@@ -36,6 +40,7 @@ config SND_AMD_ASOC_RENOIR
        select SND_SOC_AMD_ACP_PCM
        select SND_SOC_AMD_ACP_I2S
        select SND_SOC_AMD_ACP_PDM
+       select SND_SOC_AMD_ACP_LEGACY_COMMON
        depends on X86 && PCI
        help
          This option enables Renoir I2S support on AMD platform.
@@ -45,6 +50,7 @@ config SND_AMD_ASOC_REMBRANDT
        select SND_SOC_AMD_ACP_PCM
        select SND_SOC_AMD_ACP_I2S
        select SND_SOC_AMD_ACP_PDM
+       select SND_SOC_AMD_ACP_LEGACY_COMMON
        depends on X86 && PCI
        help
          This option enables Rembrandt I2S support on AMD platform.
@@ -61,6 +67,8 @@ config SND_SOC_AMD_MACH_COMMON
        select SND_SOC_MAX98357A
        select SND_SOC_RT5682S
        select SND_SOC_NAU8825
+       select SND_SOC_NAU8821
+       select SND_SOC_MAX98388
        help
          This option enables common Machine driver module for ACP.
 
index d9abb0ee5218f78301ff552cf9b578db9cdd5766..4e65fdbc8dcab2e5e64d1be7b7ad87550a3774d3 100644 (file)
@@ -8,6 +8,7 @@
 snd-acp-pcm-objs     := acp-platform.o
 snd-acp-i2s-objs     := acp-i2s.o
 snd-acp-pdm-objs     := acp-pdm.o
+snd-acp-legacy-common-objs   := acp-legacy-common.o
 snd-acp-pci-objs     := acp-pci.o
 
 #platform specific driver
@@ -22,6 +23,7 @@ snd-acp-sof-mach-objs     := acp-sof-mach.o
 obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o
 obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o
 obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o
+obj-$(CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON) += snd-acp-legacy-common.o
 obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o
 
 obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
index 09b6511c0a263c639835174986ada3c8bde38093..df350014966a05c29c242623818ab1bad31ac183 100644 (file)
@@ -149,6 +149,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
                        dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                        return -EINVAL;
                }
+               adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
        } else {
                switch (dai->driver->id) {
                case I2S_BT_INSTANCE:
@@ -167,6 +168,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
                        dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                        return -EINVAL;
                }
+               adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;
        }
 
        val = readl(adata->acp_base + reg_val);
@@ -537,17 +539,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
        return 0;
 }
 
-const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
-       .startup = acp_i2s_startup,
-       .hw_params = acp_i2s_hwparams,
-       .prepare = acp_i2s_prepare,
-       .trigger = acp_i2s_trigger,
-       .set_fmt = acp_i2s_set_fmt,
-       .set_tdm_slot = acp_i2s_set_tdm_slot,
-};
-EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
-
-int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
+static int acp_i2s_probe(struct snd_soc_dai *dai)
 {
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata = dev_get_drvdata(dev);
@@ -567,7 +559,17 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
 
        return 0;
 }
-EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON);
+
+const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
+       .probe          = acp_i2s_probe,
+       .startup        = acp_i2s_startup,
+       .hw_params      = acp_i2s_hwparams,
+       .prepare        = acp_i2s_prepare,
+       .trigger        = acp_i2s_trigger,
+       .set_fmt        = acp_i2s_set_fmt,
+       .set_tdm_slot   = acp_i2s_set_tdm_slot,
+};
+EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS(DRV_NAME);
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
new file mode 100644 (file)
index 0000000..ba58165
--- /dev/null
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Syed Saba Kareem <Syed.SabaKareem@amd.com>
+//
+
+/*
+ * Common file to be used by amd platforms
+ */
+
+#include "amd.h"
+#include <linux/pci.h>
+#include <linux/export.h>
+
+void acp_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));
+}
+EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON);
+
+void acp_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));
+}
+EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON);
+
+static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream,
+                                   struct snd_soc_dai *dai)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct acp_stream *stream = runtime->private_data;
+       struct device *dev = dai->component->dev;
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
+
+       u32 physical_addr, pdm_size, period_bytes;
+
+       period_bytes = frames_to_bytes(runtime, runtime->period_size);
+       pdm_size = frames_to_bytes(runtime, runtime->buffer_size);
+       physical_addr = stream->reg_offset + MEM_WINDOW_START;
+
+       /* Init ACP PDM Ring buffer */
+       writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR);
+       writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE);
+       writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
+       writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
+}
+
+static void set_acp_pdm_clk(struct snd_pcm_substream *substream,
+                           struct snd_soc_dai *dai)
+{
+       struct device *dev = dai->component->dev;
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
+       unsigned int pdm_ctrl;
+
+       /* Enable default ACP PDM clk */
+       writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL);
+       pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL);
+       pdm_ctrl |= PDM_MISC_CTRL_MASK;
+       writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL);
+       set_acp_pdm_ring_buffer(substream, dai);
+}
+
+void restore_acp_pdm_params(struct snd_pcm_substream *substream,
+                           struct acp_dev_data *adata)
+{
+       struct snd_soc_dai *dai;
+       struct snd_soc_pcm_runtime *soc_runtime;
+       u32 ext_int_ctrl;
+
+       soc_runtime = asoc_substream_to_rtd(substream);
+       dai = asoc_rtd_to_cpu(soc_runtime, 0);
+       /* Programming channel mask and sampling rate */
+       writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);
+       writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR);
+
+       /* Enabling ACP Pdm interuppts */
+       ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));
+       ext_int_ctrl |= PDM_DMA_INTR_MASK;
+       writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));
+       set_acp_pdm_clk(substream, dai);
+}
+EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON);
+
+static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
+                               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;
+       struct acp_stream *stream = substream->runtime->private_data;
+       u32 reg_dma_size, reg_fifo_size, reg_fifo_addr;
+       u32 phy_addr, acp_fifo_addr, ext_int_ctrl;
+       unsigned int dir = substream->stream;
+
+       switch (dai->driver->id) {
+       case I2S_SP_INSTANCE:
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       reg_dma_size = ACP_I2S_TX_DMA_SIZE;
+                       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;
+                       phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
+               } else {
+                       reg_dma_size = ACP_I2S_RX_DMA_SIZE;
+                       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;
+                       phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
+               }
+               break;
+       case I2S_BT_INSTANCE:
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       reg_dma_size = ACP_BT_TX_DMA_SIZE;
+                       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;
+                       phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
+               } else {
+                       reg_dma_size = ACP_BT_RX_DMA_SIZE;
+                       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;
+                       phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
+                       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;
+       }
+
+       writel(DMA_SIZE, adata->acp_base + reg_dma_size);
+       writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
+       writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
+
+       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, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+       return 0;
+}
+
+int restore_acp_i2s_params(struct snd_pcm_substream *substream,
+                          struct acp_dev_data *adata,
+                          struct acp_stream *stream)
+{
+       struct snd_soc_dai *dai;
+       struct snd_soc_pcm_runtime *soc_runtime;
+       u32 tdm_fmt, reg_val, fmt_reg, val;
+
+       soc_runtime = asoc_substream_to_rtd(substream);
+       dai = asoc_rtd_to_cpu(soc_runtime, 0);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1];
+               switch (stream->dai_id) {
+               case I2S_BT_INSTANCE:
+                       reg_val = ACP_BTTDM_ITER;
+                       fmt_reg = ACP_BTTDM_TXFRMT;
+                       break;
+               case I2S_SP_INSTANCE:
+                       reg_val = ACP_I2STDM_ITER;
+                       fmt_reg = ACP_I2STDM_TXFRMT;
+                       break;
+               case I2S_HS_INSTANCE:
+                       reg_val = ACP_HSTDM_ITER;
+                       fmt_reg = ACP_HSTDM_TXFRMT;
+                       break;
+               default:
+                       pr_err("Invalid dai id %x\n", stream->dai_id);
+                       return -EINVAL;
+               }
+               val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3;
+       } else {
+               tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1];
+               switch (stream->dai_id) {
+               case I2S_BT_INSTANCE:
+                       reg_val = ACP_BTTDM_IRER;
+                       fmt_reg = ACP_BTTDM_RXFRMT;
+                       break;
+               case I2S_SP_INSTANCE:
+                       reg_val = ACP_I2STDM_IRER;
+                       fmt_reg = ACP_I2STDM_RXFRMT;
+                       break;
+               case I2S_HS_INSTANCE:
+                       reg_val = ACP_HSTDM_IRER;
+                       fmt_reg = ACP_HSTDM_RXFRMT;
+                       break;
+               default:
+                       pr_err("Invalid dai id %x\n", stream->dai_id);
+                       return -EINVAL;
+               }
+               val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3;
+       }
+       writel(val, adata->acp_base + reg_val);
+       if (adata->tdm_mode == TDM_ENABLE) {
+               writel(tdm_fmt, adata->acp_base + fmt_reg);
+               val = readl(adata->acp_base + reg_val);
+               writel(val | 0x2, adata->acp_base + reg_val);
+       }
+       return set_acp_i2s_dma_fifo(substream, dai);
+}
+EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON);
+
+static int acp_power_on(struct acp_chip_info *chip)
+{
+       u32 val, acp_pgfsm_stat_reg, acp_pgfsm_ctrl_reg;
+       void __iomem *base;
+
+       base = chip->base;
+       switch (chip->acp_rev) {
+       case ACP3X_DEV:
+               acp_pgfsm_stat_reg = ACP_PGFSM_STATUS;
+               acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL;
+               break;
+       case ACP6X_DEV:
+               acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS;
+               acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       val = readl(base + acp_pgfsm_stat_reg);
+       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 + acp_pgfsm_ctrl_reg);
+
+       return readl_poll_timeout(base + acp_pgfsm_stat_reg, val,
+                                 !val, DELAY_US, ACP_TIMEOUT);
+}
+
+static int acp_reset(void __iomem *base)
+{
+       u32 val;
+       int ret;
+
+       writel(1, base + ACP_SOFT_RESET);
+       ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
+                                DELAY_US, ACP_TIMEOUT);
+       if (ret)
+               return ret;
+
+       writel(0, base + ACP_SOFT_RESET);
+       return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
+}
+
+int acp_init(struct acp_chip_info *chip)
+{
+       int ret;
+
+       /* power on */
+       ret = acp_power_on(chip);
+       if (ret) {
+               pr_err("ACP power on failed\n");
+               return ret;
+       }
+       writel(0x01, chip->base + ACP_CONTROL);
+
+       /* Reset */
+       ret = acp_reset(chip->base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON);
+
+int acp_deinit(void __iomem *base)
+{
+       int ret;
+
+       /* Reset */
+       ret = acp_reset(base);
+       if (ret)
+               return ret;
+
+       writel(0, base + ACP_CONTROL);
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON);
+
+int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
+{
+       pci_write_config_dword(dev, 0x60, smn_addr);
+       pci_write_config_dword(dev, 0x64, data);
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON);
+
+int smn_read(struct pci_dev *dev, u32 smn_addr)
+{
+       u32 data;
+
+       pci_write_config_dword(dev, 0x60, smn_addr);
+       pci_read_config_dword(dev, 0x64, &data);
+       return data;
+}
+EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON);
+
+MODULE_LICENSE("Dual BSD/GPL");
index 676ad50638d0d01b5a6217a1ca40478db6329762..6d57d17ddfd77096ff123f3ab7e872fbd20213ab 100644 (file)
@@ -75,23 +75,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
        .tdm_mode = false,
 };
 
-static const struct snd_kcontrol_new acp_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Spk"),
-       SOC_DAPM_PIN_SWITCH("Left Spk"),
-       SOC_DAPM_PIN_SWITCH("Right Spk"),
-
-};
-
-static const struct snd_soc_dapm_widget acp_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_SPK("Spk", NULL),
-       SND_SOC_DAPM_SPK("Left Spk", NULL),
-       SND_SOC_DAPM_SPK("Right Spk", NULL),
-};
-
 static int acp_asoc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = NULL;
@@ -110,11 +93,8 @@ static int acp_asoc_probe(struct platform_device *pdev)
        card->dev = dev;
        card->owner = THIS_MODULE;
        card->name = pdev->id_entry->name;
-       card->dapm_widgets = acp_widgets;
-       card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
-       card->controls = acp_controls;
-       card->num_controls = ARRAY_SIZE(acp_controls);
        card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+       /* Widgets and controls added per-codec in acp-mach-common.c */
 
        acp_card_drvdata = card->drvdata;
        dmi_id = dmi_first_match(acp_quirk_table);
index 6da17140beeaa9fbc27f725f2ae950632618ae37..a06af82b805656f8b45a9c0045744391cea69877 100644 (file)
 #include "../../codecs/rt1019.h"
 #include "../../codecs/rt5682s.h"
 #include "../../codecs/nau8825.h"
+#include "../../codecs/nau8821.h"
 #include "acp-mach.h"
 
 #define PCO_PLAT_CLK 48000000
 #define RT5682_PLL_FREQ (48000 * 512)
 #define DUAL_CHANNEL   2
 #define FOUR_CHANNEL   4
+#define NAU8821_CODEC_DAI      "nau8821-hifi"
+#define NAU8821_BCLK           1536000
+#define NAU8821_FREQ_OUT       12288000
+#define MAX98388_CODEC_DAI     "max98388-aif1"
 
 #define TDM_MODE_ENABLE 1
 
@@ -46,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = {
 };
 EXPORT_SYMBOL_GPL(acp_quirk_table);
 
-static struct snd_soc_jack pco_jack;
-
 static const unsigned int channels[] = {
        DUAL_CHANNEL,
 };
@@ -81,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata,
 SND_SOC_DAILINK_DEF(rt5682,
        DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
 
+static struct snd_soc_jack rt5682_jack;
+static struct snd_soc_jack_pin rt5682_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new rt5682_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget rt5682_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
 static const struct snd_soc_dapm_route rt5682_map[] = {
        { "Headphone Jack", NULL, "HPOL" },
        { "Headphone Jack", NULL, "HPOR" },
@@ -104,22 +129,38 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
        drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
        drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &pco_jack);
+       ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets,
+                                       ARRAY_SIZE(rt5682_widgets));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, rt5682_controls,
+                                       ARRAY_SIZE(rt5682_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &rt5682_jack,
+                                        rt5682_jack_pins,
+                                        ARRAY_SIZE(rt5682_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
        }
 
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+       snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-       ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+       ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL);
        if (ret) {
                dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
                return ret;
@@ -269,6 +310,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = {
 SND_SOC_DAILINK_DEF(rt5682s,
                    DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1")));
 
+static struct snd_soc_jack rt5682s_jack;
+static struct snd_soc_jack_pin rt5682s_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new rt5682s_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget rt5682s_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
 static const struct snd_soc_dapm_route rt5682s_map[] = {
        { "Headphone Jack", NULL, "HPOL" },
        { "Headphone Jack", NULL, "HPOR" },
@@ -293,22 +356,38 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
                drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
        }
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &pco_jack);
+       ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets,
+                                       ARRAY_SIZE(rt5682s_widgets));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, rt5682s_controls,
+                                       ARRAY_SIZE(rt5682s_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &rt5682s_jack,
+                                        rt5682s_jack_pins,
+                                        ARRAY_SIZE(rt5682s_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
        }
 
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+       snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-       ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+       ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL);
        if (ret) {
                dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
                return ret;
@@ -434,6 +513,16 @@ SND_SOC_DAILINK_DEF(rt1019,
        DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"),
                          COMP_CODEC("i2c-10EC1019:01", "rt1019-aif")));
 
+static const struct snd_kcontrol_new rt1019_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget rt1019_widgets[] = {
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
 static const struct snd_soc_dapm_route rt1019_map_lr[] = {
        { "Left Spk", NULL, "Left SPO" },
        { "Right Spk", NULL, "Right SPO" },
@@ -454,10 +543,25 @@ static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
        struct acp_card_drvdata *drvdata = card->drvdata;
+       int ret;
 
        if (drvdata->amp_codec_id != RT1019)
                return -EINVAL;
 
+       ret = snd_soc_dapm_new_controls(&card->dapm, rt1019_widgets,
+                                       ARRAY_SIZE(rt1019_widgets));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, rt1019_controls,
+                                       ARRAY_SIZE(rt1019_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
        return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
                                       ARRAY_SIZE(rt1019_map_lr));
 }
@@ -588,6 +692,14 @@ static const struct snd_soc_ops acp_card_rt1019_ops = {
 SND_SOC_DAILINK_DEF(max98360a,
        DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
 
+static const struct snd_kcontrol_new max98360a_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget max98360a_widgets[] = {
+       SND_SOC_DAPM_SPK("Spk", NULL),
+};
+
 static const struct snd_soc_dapm_route max98360a_map[] = {
        {"Spk", NULL, "Speaker"},
 };
@@ -596,10 +708,25 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
        struct acp_card_drvdata *drvdata = card->drvdata;
+       int ret;
 
        if (drvdata->amp_codec_id != MAX98360A)
                return -EINVAL;
 
+       ret = snd_soc_dapm_new_controls(&card->dapm, max98360a_widgets,
+                                       ARRAY_SIZE(max98360a_widgets));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, max98360a_controls,
+                                       ARRAY_SIZE(max98360a_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
        return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
                                       ARRAY_SIZE(max98360a_map));
 }
@@ -661,10 +788,137 @@ static const struct snd_soc_ops acp_card_maxim_ops = {
        .hw_params = acp_card_maxim_hw_params,
 };
 
+SND_SOC_DAILINK_DEF(max98388,
+                   DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"),
+                                      COMP_CODEC("i2c-ADS8388:01", "max98388-aif1")));
+
+static const struct snd_kcontrol_new max98388_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Left Spk"),
+       SOC_DAPM_PIN_SWITCH("Right Spk"),
+};
+
+static const struct snd_soc_dapm_widget max98388_widgets[] = {
+       SND_SOC_DAPM_SPK("Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Right Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route max98388_map[] = {
+       { "Left Spk", NULL, "Left BE_OUT" },
+       { "Right Spk", NULL, "Right BE_OUT" },
+};
+
+static struct snd_soc_codec_conf max98388_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF("i2c-ADS8388:00"),
+               .name_prefix = "Left",
+       },
+       {
+               .dlc = COMP_CODEC_CONF("i2c-ADS8388:01"),
+               .name_prefix = "Right",
+       },
+};
+
+static const unsigned int max98388_format[] = {16};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_bits_max = {
+       .list = max98388_format,
+       .count = ARRAY_SIZE(max98388_format),
+};
+
+static int acp_card_max98388_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = DUAL_CHANNEL;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &constraints_channels);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                  &constraints_rates);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                  &constraints_sample_bits_max);
+
+       return 0;
+}
+
+static int acp_card_max98388_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct acp_card_drvdata *drvdata = card->drvdata;
+       int ret;
+
+       if (drvdata->amp_codec_id != MAX98388)
+               return -EINVAL;
+
+       ret = snd_soc_dapm_new_controls(&card->dapm, max98388_widgets,
+                                       ARRAY_SIZE(max98388_widgets));
+
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               /* Don't need to add routes if widget addition failed */
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, max98388_controls,
+                                       ARRAY_SIZE(max98388_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_dapm_add_routes(&rtd->card->dapm, max98388_map,
+                                      ARRAY_SIZE(max98388_map));
+}
+
+static int acp_max98388_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 *codec_dai =
+                       snd_soc_card_get_codec_dai(card,
+                                                  MAX98388_CODEC_DAI);
+       int ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static const struct snd_soc_ops acp_max98388_ops = {
+       .startup = acp_card_max98388_startup,
+       .hw_params = acp_max98388_hw_params,
+};
+
 /* Declare nau8825 codec components */
 SND_SOC_DAILINK_DEF(nau8825,
                    DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi")));
 
+static struct snd_soc_jack nau8825_jack;
+static struct snd_soc_jack_pin nau8825_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new nau8825_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget nau8825_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
 static const struct snd_soc_dapm_route nau8825_map[] = {
        { "Headphone Jack", NULL, "HPOL" },
        { "Headphone Jack", NULL, "HPOR" },
@@ -683,22 +937,38 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
        if (drvdata->hs_codec_id != NAU8825)
                return -EINVAL;
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
+       ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets,
+                                       ARRAY_SIZE(nau8825_widgets));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, nau8825_controls,
+                                       ARRAY_SIZE(nau8825_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
                                         SND_JACK_HEADSET | SND_JACK_LINEOUT |
                                         SND_JACK_BTN_0 | SND_JACK_BTN_1 |
                                         SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                        &pco_jack);
+                                        &nau8825_jack,
+                                        nau8825_jack_pins,
+                                        ARRAY_SIZE(nau8825_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
        }
 
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
-       snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+       snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
-       ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
+       ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL);
        if (ret) {
                dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
                return ret;
@@ -790,6 +1060,189 @@ static const struct snd_soc_ops acp_card_nau8825_ops = {
        .hw_params = acp_nau8825_hw_params,
 };
 
+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, NAU8821_CODEC_DAI);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found\n");
+               return -EIO;
+       }
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_INTERNAL,
+                                            0, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       dev_err(card->dev, "set sysclk err = %d\n", ret);
+                       return -EIO;
+               }
+       } else {
+               ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0,
+                                            SND_SOC_CLOCK_IN);
+               if (ret < 0)
+                       dev_err(codec_dai->dev, "can't set FS clock %d\n", ret);
+               ret = snd_soc_dai_set_pll(codec_dai, 0, 0, NAU8821_BCLK,
+                                         NAU8821_FREQ_OUT);
+               if (ret < 0)
+                       dev_err(codec_dai->dev, "can't set FLL: %d\n", ret);
+       }
+       return ret;
+}
+
+static struct snd_soc_jack nau8821_jack;
+static struct snd_soc_jack_pin nau8821_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static const struct snd_kcontrol_new nau8821_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const struct snd_soc_dapm_widget nau8821_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", 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 nau8821_audio_route[] = {
+       /* HP jack connectors - unknown if we have jack detection */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+       { "MICL", NULL, "Headset Mic" },
+       { "MICR", NULL, "Headset Mic" },
+       { "DMIC", NULL, "Int Mic" },
+       { "Headphone Jack", NULL, "Platform Clock" },
+       { "Headset Mic", NULL, "Platform Clock" },
+       { "Int Mic", NULL, "Platform Clock" },
+};
+
+static const unsigned int nau8821_format[] = {16};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_bits = {
+       .list = nau8821_format,
+       .count = ARRAY_SIZE(nau8821_format),
+};
+
+static int acp_8821_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       int ret;
+
+       dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
+
+       ret = snd_soc_dapm_new_controls(&card->dapm, nau8821_widgets,
+                                       ARRAY_SIZE(nau8821_widgets));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret);
+               // Don't need to add routes if widget addition failed
+               return ret;
+       }
+
+       ret = snd_soc_add_card_controls(card, nau8821_controls,
+                                       ARRAY_SIZE(nau8821_controls));
+       if (ret) {
+               dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &nau8821_jack,
+                                        nau8821_jack_pins,
+                                        ARRAY_SIZE(nau8821_jack_pins));
+       if (ret) {
+               dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+
+       nau8821_enable_jack_detect(component, &nau8821_jack);
+
+       return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route,
+                                      ARRAY_SIZE(nau8821_audio_route));
+}
+
+static int acp_8821_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.channels_max = DUAL_CHANNEL;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &constraints_channels);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                  &constraints_rates);
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+                                  &constraints_sample_bits);
+       return 0;
+}
+
+static int acp_nau8821_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_card *card = rtd->card;
+       struct acp_card_drvdata *drvdata = card->drvdata;
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       int ret;
+       unsigned int fmt;
+
+       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_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(card->dev, "can't set FS clock %d\n", ret);
+       ret = snd_soc_dai_set_pll(codec_dai, 0, 0, snd_soc_params_to_bclk(params),
+                                 params_rate(params) * 256);
+       if (ret < 0)
+               dev_err(card->dev, "can't set FLL: %d\n", ret);
+
+       return ret;
+}
+
+static const struct snd_soc_ops acp_8821_ops = {
+       .startup = acp_8821_startup,
+       .hw_params = acp_nau8821_hw_params,
+};
+
+SND_SOC_DAILINK_DEF(nau8821,
+                   DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00",
+                                                 "nau8821-hifi")));
+
 /* Declare DMIC codec components */
 SND_SOC_DAILINK_DEF(dmic_codec,
                DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
@@ -920,6 +1373,12 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
                        links[i].init = acp_card_rt5682s_init;
                        links[i].ops = &acp_card_rt5682s_ops;
                }
+               if (drv_data->hs_codec_id == NAU8821) {
+                       links[i].codecs = nau8821;
+                       links[i].num_codecs = ARRAY_SIZE(nau8821);
+                       links[i].init = acp_8821_init;
+                       links[i].ops = &acp_8821_ops;
+               }
                i++;
        }
 
@@ -1007,6 +1466,14 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
                        links[i].ops = &acp_card_maxim_ops;
                        links[i].init = acp_card_maxim_init;
                }
+               if (drv_data->amp_codec_id == MAX98388) {
+                       links[i].codecs = max98388;
+                       links[i].num_codecs = ARRAY_SIZE(max98388);
+                       links[i].ops = &acp_max98388_ops;
+                       links[i].init = acp_card_max98388_init;
+                       card->codec_conf = max98388_conf;
+                       card->num_configs = ARRAY_SIZE(max98388_conf);
+               }
                if (drv_data->amp_codec_id == RT1019) {
                        links[i].codecs = rt1019;
                        links[i].num_codecs = ARRAY_SIZE(rt1019);
index 165f407697c009bb7ef24c866991d64bf1648365..2b3ec65940230d96255b6860671855b4986ddd0e 100644 (file)
@@ -41,6 +41,8 @@ enum codec_endpoints {
        MAX98360A,
        RT5682S,
        NAU8825,
+       NAU8821,
+       MAX98388,
 };
 
 enum platform_end_point {
index 8154fbfd1229d2e67551425477edc2808cc86297..a32c14a109b77bbfa311472451c268ffc71c41ca 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include "amd.h"
 #include "../mach-config.h"
@@ -106,6 +107,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
                goto unregister_dmic_dev;
        }
 
+       acp_init(chip);
        res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL);
        if (!res) {
                ret = -ENOMEM;
@@ -139,7 +141,12 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
                ret = PTR_ERR(pdev);
                goto unregister_dmic_dev;
        }
-
+       chip->chip_pdev = pdev;
+       dev_set_drvdata(&pci->dev, chip);
+       pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
+       pm_runtime_use_autosuspend(&pci->dev);
+       pm_runtime_put_noidle(&pci->dev);
+       pm_runtime_allow(&pci->dev);
        return ret;
 
 unregister_dmic_dev:
@@ -152,12 +159,56 @@ disable_pci:
        return ret;
 };
 
+static int __maybe_unused snd_acp_suspend(struct device *dev)
+{
+       struct acp_chip_info *chip;
+       int ret;
+
+       chip = dev_get_drvdata(dev);
+       ret = acp_deinit(chip->base);
+       if (ret)
+               dev_err(dev, "ACP de-init failed\n");
+       return ret;
+}
+
+static int __maybe_unused snd_acp_resume(struct device *dev)
+{
+       struct acp_chip_info *chip;
+       struct acp_dev_data *adata;
+       struct device child;
+       int ret;
+
+       chip = dev_get_drvdata(dev);
+       ret = acp_init(chip);
+       if (ret)
+               dev_err(dev, "ACP init failed\n");
+       child = chip->chip_pdev->dev;
+       adata = dev_get_drvdata(&child);
+       if (adata)
+               acp_enable_interrupts(adata);
+       return ret;
+}
+
+static const struct dev_pm_ops acp_pm_ops = {
+       SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume)
+};
+
 static void acp_pci_remove(struct pci_dev *pci)
 {
+       struct acp_chip_info *chip;
+       int ret;
+
+       chip = pci_get_drvdata(pci);
+       pm_runtime_forbid(&pci->dev);
+       pm_runtime_get_noresume(&pci->dev);
        if (dmic_dev)
                platform_device_unregister(dmic_dev);
        if (pdev)
                platform_device_unregister(pdev);
+       ret = acp_deinit(chip->base);
+       if (ret)
+               dev_err(&pci->dev, "ACP de-init failed\n");
 }
 
 /* PCI IDs */
@@ -173,8 +224,12 @@ static struct pci_driver snd_amd_acp_pci_driver = {
        .id_table = acp_pci_ids,
        .probe = acp_pci_probe,
        .remove = acp_pci_remove,
+       .driver = {
+               .pm = &acp_pm_ops,
+       },
 };
 module_pci_driver(snd_amd_acp_pci_driver);
 
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
 MODULE_ALIAS(DRV_NAME);
index f8030b79ac17c1c19f016f973e007167191f5cfd..f754bf79b5e3f7e210952f21a5049dc32d6d849f 100644 (file)
 
 #define DRV_NAME "acp-pdm"
 
-#define PDM_DMA_STAT           0x10
-#define PDM_DMA_INTR_MASK      0x10000
-#define PDM_DEC_64             0x2
-#define PDM_CLK_FREQ_MASK      0x07
-#define PDM_MISC_CTRL_MASK     0x10
-#define PDM_ENABLE             0x01
-#define PDM_DISABLE            0x00
-#define DMA_EN_MASK            0x02
-#define DELAY_US               5
-#define PDM_TIMEOUT            1000
-#define ACP_REGION2_OFFSET     0x02000000
-
 static int acp_dmic_prepare(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
@@ -135,6 +123,7 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       adata->ch_mask = ch_mask;
        if (params_format(hwparams) != SNDRV_PCM_FORMAT_S32_LE) {
                dev_err(dai->dev, "Invalid format:%d\n", params_format(hwparams));
                return -EINVAL;
index f220378ec20edc5ffc318c41adc1e47dfaede730..f516daf6fef41cf33595e355a69c6dfa04bae453 100644 (file)
@@ -127,7 +127,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
        return IRQ_NONE;
 }
 
-static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream)
+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;
@@ -143,8 +143,9 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream
        writel(PAGE_SIZE_4K_ENABLE,  adata->acp_base + pte_size);
        writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
 }
+EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON);
 
-static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size)
+void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size)
 {
        struct snd_pcm_substream *substream = stream->substream;
        struct acp_resource *rsrc = adata->rsrc;
@@ -168,6 +169,7 @@ static void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream
                addr += PAGE_SIZE;
        }
 }
+EXPORT_SYMBOL_NS_GPL(config_acp_dma, SND_SOC_ACP_COMMON);
 
 static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream)
 {
index 1b997837c7d81def5fc3ba3cfaedffa2a980d890..1bf7b2e68a118bde715cb75da250e251b71ad00e 100644 (file)
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 #include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.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);
+#define MP1_C2PMSG_69 0x3B10A14
+#define MP1_C2PMSG_85 0x3B10A54
+#define MP1_C2PMSG_93 0x3B10A74
+#define HOST_BRIDGE_ID 0x14B5
 
 static struct acp_resource rsrc = {
        .offset = 0,
@@ -111,7 +98,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
                .rate_max = 48000,
        },
        .ops = &asoc_acp_cpu_dai_ops,
-       .probe = &asoc_acp_i2s_probe,
 },
 {
        .name = "acp-i2s-bt",
@@ -137,7 +123,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
                .rate_max = 48000,
        },
        .ops = &asoc_acp_cpu_dai_ops,
-       .probe = &asoc_acp_i2s_probe,
 },
 {
        .name = "acp-i2s-hs",
@@ -163,7 +148,6 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
                .rate_max = 48000,
        },
        .ops = &asoc_acp_cpu_dai_ops,
-       .probe = &asoc_acp_i2s_probe,
 },
 {
        .name = "acp-pdm-dmic",
@@ -180,108 +164,22 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
 },
 };
 
-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_reset(void __iomem *base)
+static int acp6x_master_clock_generate(struct device *dev)
 {
-       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));
-}
+       int data = 0;
+       struct pci_dev *smn_dev;
 
-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;
+       smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL);
+       if (!smn_dev) {
+               dev_err(dev, "Failed to get host bridge device\n");
+               return -ENODEV;
        }
 
-       writel(0x00, base + ACP_CONTROL);
+       smn_write(smn_dev, MP1_C2PMSG_93, 0);
+       smn_write(smn_dev, MP1_C2PMSG_85, 0xC4);
+       smn_write(smn_dev, MP1_C2PMSG_69, 0x4);
+       read_poll_timeout(smn_read, data, data, DELAY_US,
+                         ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93);
        return 0;
 }
 
@@ -303,8 +201,6 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       rmb_acp_init(chip->base);
-
        adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
        if (!adata)
                return -ENOMEM;
@@ -335,9 +231,14 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
        acp_machine_select(adata);
 
        dev_set_drvdata(dev, adata);
-       acp6x_enable_interrupts(adata);
+       acp6x_master_clock_generate(dev);
+       acp_enable_interrupts(adata);
        acp_platform_register(dev);
-
+       pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_mark_last_busy(&pdev->dev);
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
        return 0;
 }
 
@@ -345,19 +246,49 @@ static void 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 = dev_get_platdata(dev);
-
-       rmb_acp_deinit(chip->base);
 
-       acp6x_disable_interrupts(adata);
+       acp_disable_interrupts(adata);
        acp_platform_unregister(dev);
+       pm_runtime_disable(&pdev->dev);
 }
 
+static int __maybe_unused rmb_pcm_resume(struct device *dev)
+{
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_stream *stream;
+       struct snd_pcm_substream *substream;
+       snd_pcm_uframes_t buf_in_frames;
+       u64 buf_size;
+
+       acp6x_master_clock_generate(dev);
+       spin_lock(&adata->acp_lock);
+       list_for_each_entry(stream, &adata->stream_list, list) {
+               substream = stream->substream;
+               if (substream && substream->runtime) {
+                       buf_in_frames = (substream->runtime->buffer_size);
+                       buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
+                       config_pte_for_stream(adata, stream);
+                       config_acp_dma(adata, stream, buf_size);
+                       if (stream->dai_id)
+                               restore_acp_i2s_params(substream, adata, stream);
+                       else
+                               restore_acp_pdm_params(substream, adata);
+               }
+       }
+       spin_unlock(&adata->acp_lock);
+       return 0;
+}
+
+static const struct dev_pm_ops rmb_dma_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume)
+};
+
 static struct platform_driver rembrandt_driver = {
        .probe = rembrandt_audio_probe,
        .remove_new = rembrandt_audio_remove,
        .driver = {
                .name = "acp_asoc_rembrandt",
+               .pm = &rmb_dma_pm_ops,
        },
 };
 
index f188365fe214b7d23c82780e1989e59f3bc6f52a..54235cad9cc90addc80309407bcda0686ae0a955 100644 (file)
 
 #define DRV_NAME "acp_asoc_renoir"
 
-#define ACP_SOFT_RST_DONE_MASK 0x00010001
-
-#define ACP_PWR_ON_MASK                0x01
-#define ACP_PWR_OFF_MASK       0x00
-#define ACP_PGFSM_STAT_MASK    0x03
-#define ACP_POWERED_ON         0x00
-#define ACP_PWR_ON_IN_PROGRESS 0x01
-#define ACP_POWERED_OFF                0x02
-#define DELAY_US               5
-#define ACP_TIMEOUT            500
-
-#define ACP_ERROR_MASK 0x20000000
-#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
-
 static struct acp_resource rsrc = {
        .offset = 20,
        .no_of_ctrls = 1,
@@ -111,7 +97,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
                .rate_max = 48000,
        },
        .ops = &asoc_acp_cpu_dai_ops,
-       .probe = &asoc_acp_i2s_probe,
 },
 {
        .name = "acp-i2s-bt",
@@ -137,7 +122,6 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
                .rate_max = 48000,
        },
        .ops = &asoc_acp_cpu_dai_ops,
-       .probe = &asoc_acp_i2s_probe,
 },
 {
        .name = "acp-pdm-dmic",
@@ -154,89 +138,7 @@ static struct snd_soc_dai_driver acp_renoir_dai[] = {
 },
 };
 
-static int acp3x_power_on(void __iomem *base)
-{
-       u32 val;
-
-       val = readl(base + ACP_PGFSM_STATUS);
-
-       if (val == ACP_POWERED_ON)
-               return 0;
-
-       if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS)
-               writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL);
-
-       return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT);
-}
-
-static int acp3x_reset(void __iomem *base)
-{
-       u32 val;
-       int ret;
-
-       writel(1, base + ACP_SOFT_RESET);
-
-       ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
-                                DELAY_US, ACP_TIMEOUT);
-       if (ret)
-               return ret;
-
-       writel(0, base + ACP_SOFT_RESET);
-
-       return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
-}
-
-static void acp3x_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 acp3x_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 rn_acp_init(void __iomem *base)
-{
-       int ret;
-
-       /* power on */
-       ret = acp3x_power_on(base);
-       if (ret)
-               return ret;
-
-       writel(0x01, base + ACP_CONTROL);
-
-       /* Reset */
-       ret = acp3x_reset(base);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int rn_acp_deinit(void __iomem *base)
-{
-       int ret = 0;
-
-       /* Reset */
-       ret = acp3x_reset(base);
-       if (ret)
-               return ret;
-
-       writel(0x00, base + ACP_CONTROL);
-       return 0;
-}
 static int renoir_audio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -256,12 +158,6 @@ static int renoir_audio_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ret = rn_acp_init(chip->base);
-       if (ret) {
-               dev_err(&pdev->dev, "ACP Init failed\n");
-               return -EINVAL;
-       }
-
        adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
        if (!adata)
                return -ENOMEM;
@@ -290,7 +186,7 @@ static int renoir_audio_probe(struct platform_device *pdev)
        acp_machine_select(adata);
 
        dev_set_drvdata(dev, adata);
-       acp3x_enable_interrupts(adata);
+       acp_enable_interrupts(adata);
        acp_platform_register(dev);
 
        return 0;
@@ -300,17 +196,8 @@ static void 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);
-
-       acp3x_disable_interrupts(adata);
-
-       ret = rn_acp_deinit(chip->base);
-       if (ret)
-               dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret));
 
+       acp_disable_interrupts(adata);
        acp_platform_unregister(dev);
 }
 
index 99a7d3879340d9bd4c5d7b4064b0fed09a93139c..5223033a122f86fc290f054c8dae98e12639678a 100644 (file)
@@ -83,20 +83,15 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
        .tdm_mode = false,
 };
 
-static const struct snd_kcontrol_new acp_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Spk"),
-       SOC_DAPM_PIN_SWITCH("Left Spk"),
-       SOC_DAPM_PIN_SWITCH("Right Spk"),
-};
-
-static const struct snd_soc_dapm_widget acp_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_SPK("Spk", NULL),
-       SND_SOC_DAPM_SPK("Left Spk", NULL),
-       SND_SOC_DAPM_SPK("Right Spk", NULL),
+static struct acp_card_drvdata sof_nau8821_max98388_data = {
+       .hs_cpu_id = I2S_SP,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = NONE,
+       .hs_codec_id = NAU8821,
+       .amp_codec_id = MAX98388,
+       .dmic_codec_id = NONE,
+       .soc_mclk = true,
+       .tdm_mode = false,
 };
 
 static int acp_sof_probe(struct platform_device *pdev)
@@ -117,11 +112,8 @@ static int acp_sof_probe(struct platform_device *pdev)
        card->dev = dev;
        card->owner = THIS_MODULE;
        card->name = pdev->id_entry->name;
-       card->dapm_widgets = acp_widgets;
-       card->num_dapm_widgets = ARRAY_SIZE(acp_widgets);
-       card->controls = acp_controls;
-       card->num_controls = ARRAY_SIZE(acp_controls);
        card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
+       /* Widgets and controls added per-codec in acp-mach-common.c */
 
        acp_card_drvdata = card->drvdata;
        dmi_id = dmi_first_match(acp_quirk_table);
@@ -166,6 +158,10 @@ static const struct platform_device_id board_ids[] = {
                .name = "rt5682s-hs-rt1019",
                .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
        },
+       {
+               .name = "nau8821-max",
+               .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data
+       },
        { }
 };
 static struct platform_driver acp_asoc_audio = {
@@ -187,4 +183,5 @@ MODULE_ALIAS("platform:rt5682s-max");
 MODULE_ALIAS("platform:rt5682s-rt1019");
 MODULE_ALIAS("platform:nau8825-max");
 MODULE_ALIAS("platform:rt5682s-hs-rt1019");
+MODULE_ALIAS("platform:nau8821-max");
 MODULE_LICENSE("GPL v2");
index 12a176a50fd6e8cf031f74edfa8239f2f40fc792..d6cfae6ec5f74a472501011d8e3ab3974775b626 100644 (file)
 #define SLOT_WIDTH_24  0x18
 #define SLOT_WIDTH_32  0x20
 
+#define ACP6X_PGFSM_CONTROL                     0x1024
+#define ACP6X_PGFSM_STATUS                      0x1028
+
+#define ACP_SOFT_RST_DONE_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
+
+#define ACP_TIMEOUT            500
+#define DELAY_US               5
+#define ACP_SUSPEND_DELAY_MS   2000
+
+#define PDM_DMA_STAT            0x10
+#define PDM_DMA_INTR_MASK       0x10000
+#define PDM_DEC_64              0x2
+#define PDM_CLK_FREQ_MASK       0x07
+#define PDM_MISC_CTRL_MASK      0x10
+#define PDM_ENABLE              0x01
+#define PDM_DISABLE             0x00
+#define DMA_EN_MASK             0x02
+#define DELAY_US                5
+#define PDM_TIMEOUT             1000
+#define ACP_REGION2_OFFSET      0x02000000
+
 struct acp_chip_info {
        char *name;             /* Platform name */
        unsigned int acp_rev;   /* ACP Revision id */
        void __iomem *base;     /* ACP memory PCI base */
+       struct platform_device *chip_pdev;
 };
 
 struct acp_stream {
@@ -144,8 +177,11 @@ struct acp_dev_data {
        u32 lrclk_div;
 
        struct acp_resource *rsrc;
+       u32 ch_mask;
        u32 tdm_tx_fmt[3];
        u32 tdm_rx_fmt[3];
+       u32 xfer_tx_resolution[3];
+       u32 xfer_rx_resolution[3];
 };
 
 union acp_i2stdm_mstrclkgen {
@@ -162,15 +198,29 @@ union acp_i2stdm_mstrclkgen {
 extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
 extern const struct snd_soc_dai_ops acp_dmic_dai_ops;
 
-int asoc_acp_i2s_probe(struct snd_soc_dai *dai);
 int acp_platform_register(struct device *dev);
 int acp_platform_unregister(struct device *dev);
 
 int acp_machine_select(struct acp_dev_data *adata);
 
+int smn_read(struct pci_dev *dev, u32 smn_addr);
+int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data);
+
+int acp_init(struct acp_chip_info *chip);
+int acp_deinit(void __iomem *base);
+void acp_enable_interrupts(struct acp_dev_data *adata);
+void acp_disable_interrupts(struct acp_dev_data *adata);
 /* Machine configuration */
 int snd_amd_acp_find_config(struct pci_dev *pci);
 
+void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream);
+void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size);
+void restore_acp_pdm_params(struct snd_pcm_substream *substream,
+                           struct acp_dev_data *adata);
+
+int restore_acp_i2s_params(struct snd_pcm_substream *substream,
+                          struct acp_dev_data *adata, struct acp_stream *stream);
+
 static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
 {
        u64 byte_count = 0, low = 0, high = 0;
index 0543dda75b99a7a26be0c8fc8d6aa32fc3fcfe33..28ad5f5b9a7660284abc4927d3acb231c09d7cc9 100644 (file)
 #define DUAL_CHANNEL           2
 
 static struct snd_soc_jack pco_jack;
+static struct snd_soc_jack_pin pco_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 static struct clk *rt5682_dai_wclk;
 static struct clk *rt5682_dai_bclk;
 static struct gpio_desc *dmic_sel;
@@ -86,11 +97,13 @@ static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd)
        rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk");
        rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk");
 
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                               SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                               SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                               &pco_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &pco_jack,
+                                        pco_jack_pins,
+                                        ARRAY_SIZE(pco_jack_pins));
        if (ret) {
                dev_err(card->dev, "HP jack creation failed %d\n", ret);
                return ret;
index 7b4c625da40d8e9441b0f806f80ceff16e405486..d392e6d6e6e1628bd4b64d36b2020f051f918299 100644 (file)
@@ -20,6 +20,7 @@
 
 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[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[];
 
 struct config_entry {
        u32 flags;
index 324c80fca67284fbff1691f0263d6be21f80333c..6230d1b1222517b668c68dca6212dc24df6e998a 100644 (file)
@@ -488,10 +488,9 @@ static int acp63_sdw_platform_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int acp63_sdw_platform_remove(struct platform_device *pdev)
+static void acp63_sdw_platform_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
-       return 0;
 }
 
 static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
@@ -552,7 +551,7 @@ static const struct dev_pm_ops acp63_pm_ops = {
 
 static struct platform_driver acp63_sdw_dma_driver = {
        .probe = acp63_sdw_platform_probe,
-       .remove = acp63_sdw_platform_remove,
+       .remove_new = acp63_sdw_platform_remove,
        .driver = {
                .name = "amd_ps_sdw_dma",
                .pm = &acp63_pm_ops,
index e5bcd1e6eb73acb61538ddb92c524a630cfb1556..eda464545866cab19e69fca5623ea4231e21de2d 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Machine driver for AMD Vangogh platform using NAU8821 & CS35L41
- * codecs.
+ * Machine driver for AMD Vangogh platform using either
+ * NAU8821 & CS35L41 or NAU8821 & MAX98388 codecs.
  *
  * Copyright 2021 Advanced Micro Devices, Inc.
  */
@@ -22,7 +22,6 @@
 
 #define DRV_NAME                       "acp5x_mach"
 #define DUAL_CHANNEL                   2
-#define VG_JUPITER                     1
 #define ACP5X_NAU8821_BCLK             3072000
 #define ACP5X_NAU8821_FREQ_OUT         12288000
 #define ACP5X_NAU8821_COMP_NAME        "i2c-NVTN2020:00"
 #define ACP5X_CS35L41_COMP_LNAME       "spi-VLV1776:00"
 #define ACP5X_CS35L41_COMP_RNAME       "spi-VLV1776:01"
 #define ACP5X_CS35L41_DAI_NAME         "cs35l41-pcm"
+#define ACP5X_MAX98388_COMP_LNAME      "i2c-ADS8388:00"
+#define ACP5X_MAX98388_COMP_RNAME      "i2c-ADS8388:01"
+#define ACP5X_MAX98388_DAI_NAME                "max98388-aif1"
 
-static unsigned long acp5x_machine_id;
 static struct snd_soc_jack vg_headset;
 
 SND_SOC_DAILINK_DEF(platform,  DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0")));
@@ -169,6 +170,9 @@ static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME);
        int ret, bclk;
 
+       if (!dai)
+               return -EINVAL;
+
        ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN);
        if (ret < 0)
                dev_err(card->dev, "can't set FS clock %d\n", ret);
@@ -242,7 +246,6 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream,
        }
 
        return 0;
-
 }
 
 static const struct snd_soc_ops acp5x_cs35l41_play_ops = {
@@ -292,8 +295,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = {
        },
 };
 
-
-
 static const struct snd_soc_dapm_widget acp5x_8821_35l41_widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -331,16 +332,110 @@ static struct snd_soc_card acp5x_8821_35l41_card = {
        .num_controls = ARRAY_SIZE(acp5x_8821_controls),
 };
 
-static int acp5x_vg_quirk_cb(const struct dmi_system_id *id)
+static int acp5x_max98388_startup(struct snd_pcm_substream *substream)
 {
-       acp5x_machine_id = VG_JUPITER;
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       machine->play_i2s_instance = I2S_HS_INSTANCE;
 
-       return 1;
+       runtime->hw.channels_max = DUAL_CHANNEL;
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                  &constraints_channels);
+       snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                  &constraints_rates);
+       return 0;
 }
 
+static const struct snd_soc_ops acp5x_max98388_play_ops = {
+       .startup = acp5x_max98388_startup,
+};
+
+static struct snd_soc_codec_conf acp5x_max98388_conf[] = {
+       {
+               .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_LNAME),
+               .name_prefix = "Left",
+       },
+       {
+               .dlc = COMP_CODEC_CONF(ACP5X_MAX98388_COMP_RNAME),
+               .name_prefix = "Right",
+       },
+};
+
+SND_SOC_DAILINK_DEF(max98388, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_MAX98388_COMP_LNAME,
+                                                           ACP5X_MAX98388_DAI_NAME),
+                                                COMP_CODEC(ACP5X_MAX98388_COMP_RNAME,
+                                                           ACP5X_MAX98388_DAI_NAME)));
+
+static struct snd_soc_dai_link acp5x_8821_98388_dai[] = {
+       {
+               .name = "acp5x-8821-play",
+               .stream_name = "Playback/Capture",
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                          SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBC_CFC,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &acp5x_8821_ops,
+               .init = acp5x_8821_init,
+               SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform),
+       },
+       {
+               .name = "acp5x-max98388-play",
+               .stream_name = "MAX98388 Playback",
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                          SND_SOC_DAIFMT_NB_NF |
+                          SND_SOC_DAIFMT_CBC_CFC,
+               .dpcm_playback = 1,
+               .playback_only = 1,
+               .ops = &acp5x_max98388_play_ops,
+               SND_SOC_DAILINK_REG(acp5x_bt, max98388, platform),
+       },
+};
+
+static const struct snd_soc_dapm_widget acp5x_8821_98388_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+                           platform_clock_control,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SPK("SPK", NULL),
+};
+
+static const struct snd_soc_dapm_route acp5x_8821_98388_route[] = {
+       { "Headphone", NULL, "HPOL" },
+       { "Headphone", NULL, "HPOR" },
+       { "MICL", NULL, "Headset Mic" },
+       { "MICR", NULL, "Headset Mic" },
+       { "DMIC", NULL, "Int Mic" },
+
+       { "Headphone", NULL, "Platform Clock" },
+       { "Headset Mic", NULL, "Platform Clock" },
+       { "Int Mic", NULL, "Platform Clock" },
+
+       { "SPK", NULL, "Left BE_OUT" },
+       { "SPK", NULL, "Right BE_OUT" },
+};
+
+static struct snd_soc_card acp5x_8821_98388_card = {
+       .name = "acp5x-max98388",
+       .owner = THIS_MODULE,
+       .dai_link = acp5x_8821_98388_dai,
+       .num_links = ARRAY_SIZE(acp5x_8821_98388_dai),
+       .dapm_widgets = acp5x_8821_98388_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_98388_widgets),
+       .dapm_routes = acp5x_8821_98388_route,
+       .num_dapm_routes = ARRAY_SIZE(acp5x_8821_98388_route),
+       .codec_conf = acp5x_max98388_conf,
+       .num_configs = ARRAY_SIZE(acp5x_max98388_conf),
+       .controls = acp5x_8821_controls,
+       .num_controls = ARRAY_SIZE(acp5x_8821_controls),
+};
+
 static const struct dmi_system_id acp5x_vg_quirk_table[] = {
        {
-               .callback = acp5x_vg_quirk_cb,
                .matches = {
                        DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"),
                        DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"),
@@ -351,23 +446,31 @@ static const struct dmi_system_id acp5x_vg_quirk_table[] = {
 
 static int acp5x_probe(struct platform_device *pdev)
 {
+       const struct dmi_system_id *dmi_id;
        struct acp5x_platform_info *machine;
        struct device *dev = &pdev->dev;
        struct snd_soc_card *card;
        int ret;
 
+       card = (struct snd_soc_card *)device_get_match_data(dev);
+       if (!card) {
+               /*
+                * This is normally the result of directly probing the driver
+                * in pci-acp5x through platform_device_register_full(), which
+                * is necessary for the CS35L41 variant, as it doesn't support
+                * ACPI probing and relies on DMI quirks.
+                */
+               dmi_id = dmi_first_match(acp5x_vg_quirk_table);
+               if (!dmi_id)
+                       return -ENODEV;
+
+               card = &acp5x_8821_35l41_card;
+       }
+
        machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL);
        if (!machine)
                return -ENOMEM;
 
-       dmi_check_system(acp5x_vg_quirk_table);
-       switch (acp5x_machine_id) {
-       case VG_JUPITER:
-               card = &acp5x_8821_35l41_card;
-               break;
-       default:
-               return -ENODEV;
-       }
        card->dev = dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
@@ -379,10 +482,17 @@ static int acp5x_probe(struct platform_device *pdev)
        return 0;
 }
 
+static const struct acpi_device_id acp5x_acpi_match[] = {
+       { "AMDI8821", (kernel_ulong_t)&acp5x_8821_98388_card },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, acp5x_acpi_match);
+
 static struct platform_driver acp5x_mach_driver = {
        .driver = {
-               .name = "acp5x_mach",
+               .name = DRV_NAME,
                .pm = &snd_soc_pm_ops,
+               .acpi_match_table = acp5x_acpi_match,
        },
        .probe = acp5x_probe,
 };
@@ -390,6 +500,6 @@ static struct platform_driver acp5x_mach_driver = {
 module_platform_driver(acp5x_mach_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
-MODULE_DESCRIPTION("NAU8821 & CS35L41 audio support");
+MODULE_DESCRIPTION("NAU8821/CS35L41 & NAU8821/MAX98388 audio support");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRV_NAME);
index 69a88dc6516523d8748075751f3ca674e53caf13..6c20c643f32186ab13cb705c451ab065a3c7261d 100644 (file)
@@ -532,13 +532,6 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return err;
 }
 
-static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
-       .prepare        = atmel_i2s_prepare,
-       .trigger        = atmel_i2s_trigger,
-       .hw_params      = atmel_i2s_hw_params,
-       .set_fmt        = atmel_i2s_set_dai_fmt,
-};
-
 static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -547,8 +540,15 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
+       .probe          = atmel_i2s_dai_probe,
+       .prepare        = atmel_i2s_prepare,
+       .trigger        = atmel_i2s_trigger,
+       .hw_params      = atmel_i2s_hw_params,
+       .set_fmt        = atmel_i2s_set_dai_fmt,
+};
+
 static struct snd_soc_dai_driver atmel_i2s_dai = {
-       .probe  = atmel_i2s_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -730,7 +730,7 @@ static void atmel_i2s_remove(struct platform_device *pdev)
 static struct platform_driver atmel_i2s_driver = {
        .driver         = {
                .name   = "atmel_i2s",
-               .of_match_table = of_match_ptr(atmel_i2s_dt_ids),
+               .of_match_table = atmel_i2s_dt_ids,
        },
        .probe          = atmel_i2s_probe,
        .remove_new     = atmel_i2s_remove,
index efcbdd1a629fe3f3fa020168c49430cc9def4d8c..0db7815d230c3cccb9177d69e322c25f118b9ba3 100644 (file)
@@ -690,7 +690,7 @@ unregister_codec:
 static struct platform_driver atmel_pdmic_driver = {
        .driver = {
                .name           = "atmel-pdmic",
-               .of_match_table = of_match_ptr(atmel_pdmic_of_match),
+               .of_match_table = atmel_pdmic_of_match,
                .pm             = &snd_soc_pm_ops,
        },
        .probe  = atmel_pdmic_probe,
index 7c83d48ca1a021a04ba456824f00a246ce6b4d86..25ed0b953bfdeadc554f8b4d548dd9d51cc0b727 100644 (file)
@@ -870,17 +870,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
-       .set_sysclk     = mchp_i2s_mcc_set_sysclk,
-       .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
-       .startup        = mchp_i2s_mcc_startup,
-       .trigger        = mchp_i2s_mcc_trigger,
-       .hw_params      = mchp_i2s_mcc_hw_params,
-       .hw_free        = mchp_i2s_mcc_hw_free,
-       .set_fmt        = mchp_i2s_mcc_set_dai_fmt,
-       .set_tdm_slot   = mchp_i2s_mcc_set_dai_tdm_slot,
-};
-
 static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
 {
        struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -895,6 +884,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
+       .probe          = mchp_i2s_mcc_dai_probe,
+       .set_sysclk     = mchp_i2s_mcc_set_sysclk,
+       .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
+       .startup        = mchp_i2s_mcc_startup,
+       .trigger        = mchp_i2s_mcc_trigger,
+       .hw_params      = mchp_i2s_mcc_hw_params,
+       .hw_free        = mchp_i2s_mcc_hw_free,
+       .set_fmt        = mchp_i2s_mcc_set_dai_fmt,
+       .set_tdm_slot   = mchp_i2s_mcc_set_dai_tdm_slot,
+};
+
 #define MCHP_I2SMCC_RATES              SNDRV_PCM_RATE_8000_192000
 
 #define MCHP_I2SMCC_FORMATS    (SNDRV_PCM_FMTBIT_S8 |          \
@@ -906,7 +907,6 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
                                 SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
-       .probe  = mchp_i2s_mcc_dai_probe,
        .playback = {
                .stream_name = "I2SMCC-Playback",
                .channels_min = 1,
@@ -1098,7 +1098,7 @@ static void mchp_i2s_mcc_remove(struct platform_device *pdev)
 static struct platform_driver mchp_i2s_mcc_driver = {
        .driver         = {
                .name   = "mchp_i2s_mcc",
-               .of_match_table = of_match_ptr(mchp_i2s_mcc_dt_ids),
+               .of_match_table = mchp_i2s_mcc_dt_ids,
        },
        .probe          = mchp_i2s_mcc_probe,
        .remove_new     = mchp_i2s_mcc_remove,
index c79c73e6791e1f68e6bfd423945d77ff1fe00629..944d78ef2f36925b2a0e33176a33fc00a8ad5e8d 100644 (file)
@@ -706,13 +706,6 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
-       .set_fmt        = mchp_pdmc_set_fmt,
-       .startup        = mchp_pdmc_startup,
-       .hw_params      = mchp_pdmc_hw_params,
-       .trigger        = mchp_pdmc_trigger,
-};
-
 static int mchp_pdmc_add_chmap_ctls(struct snd_pcm *pcm, struct mchp_pdmc *dd)
 {
        struct mchp_pdmc_chmap *info;
@@ -765,8 +758,16 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd,
        return ret;
 }
 
+static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
+       .probe          = mchp_pdmc_dai_probe,
+       .set_fmt        = mchp_pdmc_set_fmt,
+       .startup        = mchp_pdmc_startup,
+       .hw_params      = mchp_pdmc_hw_params,
+       .trigger        = mchp_pdmc_trigger,
+       .pcm_new        = &mchp_pdmc_pcm_new,
+};
+
 static struct snd_soc_dai_driver mchp_pdmc_dai = {
-       .probe  = mchp_pdmc_dai_probe,
        .capture = {
                .stream_name    = "Capture",
                .channels_min   = 1,
@@ -777,7 +778,6 @@ static struct snd_soc_dai_driver mchp_pdmc_dai = {
                .formats        = SNDRV_PCM_FMTBIT_S24_LE,
        },
        .ops = &mchp_pdmc_dai_ops,
-       .pcm_new = &mchp_pdmc_pcm_new,
 };
 
 /* PDMC interrupt handler */
index ff6aba143aeeadcee601b3e0cf9976ed452b36a3..33ce5e54482bebd5b212e9971f510eb478373285 100644 (file)
@@ -503,11 +503,6 @@ unlock:
        return ret;
 }
 
-static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = {
-       .trigger        = mchp_spdifrx_trigger,
-       .hw_params      = mchp_spdifrx_hw_params,
-};
-
 #define MCHP_SPDIF_RATES       SNDRV_PCM_RATE_8000_192000
 
 #define MCHP_SPDIF_FORMATS     (SNDRV_PCM_FMTBIT_S16_LE |      \
@@ -1009,10 +1004,15 @@ static int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = {
+       .probe          = mchp_spdifrx_dai_probe,
+       .remove         = mchp_spdifrx_dai_remove,
+       .trigger        = mchp_spdifrx_trigger,
+       .hw_params      = mchp_spdifrx_hw_params,
+};
+
 static struct snd_soc_dai_driver mchp_spdifrx_dai = {
        .name = "mchp-spdifrx",
-       .probe  = mchp_spdifrx_dai_probe,
-       .remove = mchp_spdifrx_dai_remove,
        .capture = {
                .stream_name = "S/PDIF Capture",
                .channels_min = SPDIFRX_CHANNELS,
@@ -1197,7 +1197,7 @@ static struct platform_driver mchp_spdifrx_driver = {
        .remove_new = mchp_spdifrx_remove,
        .driver = {
                .name   = "mchp_spdifrx",
-               .of_match_table = of_match_ptr(mchp_spdifrx_dt_ids),
+               .of_match_table = mchp_spdifrx_dt_ids,
                .pm     = pm_ptr(&mchp_spdifrx_pm_ops),
        },
 };
index 1d3e17119888d4686e7001a059d025e2cff48000..a201a96fa69062ef11233fe379be9189e695db3a 100644 (file)
@@ -516,14 +516,6 @@ static int mchp_spdiftx_hw_free(struct snd_pcm_substream *substream,
                            SPDIFTX_CR_SWRST | SPDIFTX_CR_FCLR);
 }
 
-static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = {
-       .startup        = mchp_spdiftx_dai_startup,
-       .shutdown       = mchp_spdiftx_dai_shutdown,
-       .trigger        = mchp_spdiftx_trigger,
-       .hw_params      = mchp_spdiftx_hw_params,
-       .hw_free        = mchp_spdiftx_hw_free,
-};
-
 #define MCHP_SPDIFTX_RATES     SNDRV_PCM_RATE_8000_192000
 
 #define MCHP_SPDIFTX_FORMATS   (SNDRV_PCM_FMTBIT_S8 |          \
@@ -703,9 +695,17 @@ static int mchp_spdiftx_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = {
+       .probe          = mchp_spdiftx_dai_probe,
+       .startup        = mchp_spdiftx_dai_startup,
+       .shutdown       = mchp_spdiftx_dai_shutdown,
+       .trigger        = mchp_spdiftx_trigger,
+       .hw_params      = mchp_spdiftx_hw_params,
+       .hw_free        = mchp_spdiftx_hw_free,
+};
+
 static struct snd_soc_dai_driver mchp_spdiftx_dai = {
        .name = "mchp-spdiftx",
-       .probe  = mchp_spdiftx_dai_probe,
        .playback = {
                .stream_name = "S/PDIF Playback",
                .channels_min = 1,
@@ -891,7 +891,7 @@ static struct platform_driver mchp_spdiftx_driver = {
        .remove_new = mchp_spdiftx_remove,
        .driver = {
                .name   = "mchp_spdiftx",
-               .of_match_table = of_match_ptr(mchp_spdiftx_dt_ids),
+               .of_match_table = mchp_spdiftx_dt_ids,
                .pm = pm_ptr(&mchp_spdiftx_pm_ops)
        },
 };
index efead272d92b163f33db8262f99ce608657cbbcb..c809b121037f04a389b8875a0edbdfe53c832755 100644 (file)
@@ -430,7 +430,7 @@ MODULE_DEVICE_TABLE(of, tse850_dt_ids);
 static struct platform_driver tse850_driver = {
        .driver = {
                .name = "axentia-tse850-pcm5142",
-               .of_match_table = of_match_ptr(tse850_dt_ids),
+               .of_match_table = tse850_dt_ids,
        },
        .probe = tse850_probe,
        .remove_new = tse850_remove,
index a11d6841afc2b41348b687fd85a5fab79298fc24..b0e1a1253e10896562f1eae4b8ca46ef02132000 100644 (file)
@@ -195,18 +195,18 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
-       .startup                = alchemy_ac97c_startup,
-};
-
 static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
 {
        return ac97c_workdata ? 0 : -ENODEV;
 }
 
+static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
+       .probe                  = au1xac97c_dai_probe,
+       .startup                = alchemy_ac97c_startup,
+};
+
 static struct snd_soc_dai_driver au1xac97c_dai_driver = {
        .name                   = "alchemy-ac97c",
-       .probe                  = au1xac97c_dai_probe,
        .playback = {
                .rates          = AC97_RATES,
                .formats        = AC97_FMTS,
index 9fd91aea7d1a8a9eda05e3f76d5ea006e53f8fa0..5d50ebc2bdd5665e5672a1f3fdfbc68a90bd9428 100644 (file)
@@ -333,13 +333,13 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+       .probe          = au1xpsc_ac97_probe,
        .startup        = au1xpsc_ac97_startup,
        .trigger        = au1xpsc_ac97_trigger,
        .hw_params      = au1xpsc_ac97_hw_params,
 };
 
 static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
-       .probe                  = au1xpsc_ac97_probe,
        .playback = {
                .rates          = AC97_RATES,
                .formats        = AC97_FMTS,
index 85f705afcdbbbb34e12fe56cbc466b58ca65eba1..9bda6499e66e1c10c8c48a02129e6c2e058ef3a6 100644 (file)
@@ -737,7 +737,19 @@ static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
        bcm2835_i2s_stop_clock(dev);
 }
 
+static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai,
+                                 &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+                                 &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
+       .probe          = bcm2835_i2s_dai_probe,
        .startup        = bcm2835_i2s_startup,
        .shutdown       = bcm2835_i2s_shutdown,
        .prepare        = bcm2835_i2s_prepare,
@@ -748,20 +760,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
        .set_tdm_slot   = bcm2835_i2s_set_dai_tdm_slot,
 };
 
-static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
-{
-       struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_init_dma_data(dai,
-                       &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
-                       &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
-
-       return 0;
-}
-
 static struct snd_soc_dai_driver bcm2835_i2s_dai = {
        .name   = "bcm2835-i2s",
-       .probe  = bcm2835_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index 18c51dbbc8dc507d334652b7e4c2f0e2e7d18be4..c64609718738b321da4fe95082437926aea600a9 100644 (file)
@@ -225,7 +225,6 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
        void __iomem *regs;
-       struct resource *r_mem, *region;
        struct bcm_i2s_priv *i2s_priv;
        struct regmap *regmap_i2s;
        struct clk *i2s_clk;
@@ -241,20 +240,7 @@ static int bcm63xx_i2s_dev_probe(struct platform_device *pdev)
                return PTR_ERR(i2s_clk);
        }
 
-       r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r_mem) {
-               dev_err(&pdev->dev, "Unable to get register resource.\n");
-               return -ENODEV;
-       }
-
-       region = devm_request_mem_region(&pdev->dev, r_mem->start,
-                                       resource_size(r_mem), DRV_NAME);
-       if (!region) {
-               dev_err(&pdev->dev, "Memory region already claimed\n");
-               return -EBUSY;
-       }
-
-       regs = devm_ioremap_resource(&pdev->dev, r_mem);
+       regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs)) {
                ret = PTR_ERR(regs);
                return ret;
index 74152b2d770d1c325b659da5d3c5c4759cc710ef..4925e03c3c304566f96adb488eadc38aaf281022 100644 (file)
@@ -117,8 +117,6 @@ struct cygnus_audio {
        unsigned long vco_rate;
 };
 
-extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai);
-extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd);
 extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai,
                                                int len);
 extern int cygnus_soc_platform_register(struct device *dev,
index afc6b5b570ea042f0f78d63a9ff0a4066ebaf5fa..522de4b802939892a804798c243789dfc6226dbd 100644 (file)
@@ -407,6 +407,7 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component)
 #endif
 
 static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+       .probe          = ep93xx_i2s_dai_probe,
        .startup        = ep93xx_i2s_startup,
        .shutdown       = ep93xx_i2s_shutdown,
        .hw_params      = ep93xx_i2s_hw_params,
@@ -418,7 +419,6 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
 
 static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .symmetric_rate = 1,
-       .probe          = ep93xx_i2s_dai_probe,
        .playback       = {
                .channels_min   = 2,
                .channels_max   = 2,
index 3574c68e0dda393ec117bfc36d65bfa8d85593f3..d99b674d574b7e1dcd9f2f4aff1b9184d44bc1fb 100644 (file)
@@ -143,7 +143,7 @@ struct pm860x_priv {
        struct pm860x_det       det;
 
        int                     irq[4];
-       unsigned char           name[4][MAX_NAME_LEN+1];
+       unsigned char           name[4][MAX_NAME_LEN];
 };
 
 /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@@ -1373,7 +1373,7 @@ static int pm860x_codec_probe(struct platform_device *pdev)
                        return -EINVAL;
                }
                pm860x->irq[i] = res->start + chip->irq_base;
-               strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+               strscpy(pm860x->name[i], res->name, MAX_NAME_LEN);
        }
 
        ret = devm_snd_soc_register_component(&pdev->dev,
index 49367d49b4164e40c5064938bee1ddd1f791ba78..9ddebd1358928638be30831ddf844a7dd32f7c08 100644 (file)
@@ -53,8 +53,10 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_AK5558
        imply SND_SOC_ALC5623
        imply SND_SOC_ALC5632
+       imply SND_SOC_AUDIO_IIO_AUX
        imply SND_SOC_AW8738
        imply SND_SOC_AW88395
+       imply SND_SOC_AW88261
        imply SND_SOC_BT_SCO
        imply SND_SOC_BD28623
        imply SND_SOC_CHV3_CODEC
@@ -185,6 +187,7 @@ config SND_SOC_ALL_CODECS
        imply SND_SOC_RT1015
        imply SND_SOC_RT1015P
        imply SND_SOC_RT1016
+       imply SND_SOC_RT1017_SDCA_SDW
        imply SND_SOC_RT1019
        imply SND_SOC_RT1305
        imply SND_SOC_RT1308
@@ -616,6 +619,17 @@ config SND_SOC_ALC5632
        tristate
        depends on I2C
 
+config SND_SOC_AUDIO_IIO_AUX
+       tristate "Audio IIO Auxiliary device"
+       depends on IIO
+       help
+         Enable support for Industrial I/O devices as audio auxiliary devices.
+         This allows to have an IIO device present in the audio path and
+         controlled using mixer controls.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-soc-audio-iio-aux.
+
 config SND_SOC_AW8738
        tristate "Awinic AW8738 Audio Amplifier"
        select GPIOLIB
@@ -642,6 +656,20 @@ config SND_SOC_AW88395
          digital Smart K audio amplifier with an integrated 10V
          smart boost convert.
 
+config SND_SOC_AW88261
+       tristate "Soc Audio for awinic aw88261"
+       depends on I2C
+       select CRC8
+       select REGMAP_I2C
+       select GPIOLIB
+       select SND_SOC_AW88395_LIB
+       help
+         This option enables support for aw88261 Smart PA.
+         The awinic AW88261 is an I2S/TDM input, high efficiency
+         digital Smart K audio amplifier. The output voltage of
+         boost converter can be adjusted smartly according to
+         the input amplitude.
+
 config SND_SOC_BD28623
        tristate "ROHM BD28623 CODEC"
        help
@@ -1432,6 +1460,11 @@ config SND_SOC_RT1016
        tristate
        depends on I2C
 
+config SND_SOC_RT1017_SDCA_SDW
+       tristate "Realtek RT1017 SDCA Codec - SDW"
+       depends on SOUNDWIRE
+       select REGMAP_SOUNDWIRE
+
 config SND_SOC_RT1019
        tristate
        depends on I2C
@@ -1724,6 +1757,7 @@ config SND_SOC_STA529
 config SND_SOC_STAC9766
        tristate
        depends on SND_SOC_AC97_BUS
+       select REGMAP_AC97
 
 config SND_SOC_STI_SAS
        tristate "codec Audio support for STI SAS codec"
index 20d1a841991df75c0bca0eff664153aa0fb1ae75..95cbb42253e2666c18da5586486b87eebdfbe0b5 100644 (file)
@@ -45,10 +45,12 @@ snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-ak5558-objs := ak5558.o
 snd-soc-arizona-objs := arizona.o arizona-jack.o
+snd-soc-audio-iio-aux-objs := audio-iio-aux.o
 snd-soc-aw8738-objs := aw8738.o
 snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o
 snd-soc-aw88395-objs := aw88395/aw88395.o \
                        aw88395/aw88395_device.o
+snd-soc-aw88261-objs := aw88261.o
 snd-soc-bd28623-objs := bd28623.o
 snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-chv3-codec-objs := chv3-codec.o
@@ -206,6 +208,7 @@ snd-soc-rt1011-objs := rt1011.o
 snd-soc-rt1015-objs := rt1015.o
 snd-soc-rt1015p-objs := rt1015p.o
 snd-soc-rt1016-objs := rt1016.o
+snd-soc-rt1017-sdca-objs := rt1017-sdca-sdw.o
 snd-soc-rt1019-objs := rt1019.o
 snd-soc-rt1305-objs := rt1305.o
 snd-soc-rt1308-objs := rt1308.o
@@ -430,9 +433,11 @@ obj-$(CONFIG_SND_SOC_AK5558)       += snd-soc-ak5558.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)  += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)  += snd-soc-arizona.o
+obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX)    += snd-soc-audio-iio-aux.o
 obj-$(CONFIG_SND_SOC_AW8738)   += snd-soc-aw8738.o
 obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o
 obj-$(CONFIG_SND_SOC_AW88395)  +=snd-soc-aw88395.o
+obj-$(CONFIG_SND_SOC_AW88261)  +=snd-soc-aw88261.o
 obj-$(CONFIG_SND_SOC_BD28623)  += snd-soc-bd28623.o
 obj-$(CONFIG_SND_SOC_BT_SCO)   += snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
@@ -585,6 +590,7 @@ obj-$(CONFIG_SND_SOC_RT1011)        += snd-soc-rt1011.o
 obj-$(CONFIG_SND_SOC_RT1015)   += snd-soc-rt1015.o
 obj-$(CONFIG_SND_SOC_RT1015P)  += snd-soc-rt1015p.o
 obj-$(CONFIG_SND_SOC_RT1016)   += snd-soc-rt1016.o
+obj-$(CONFIG_SND_SOC_RT1017_SDCA_SDW)  += snd-soc-rt1017-sdca.o
 obj-$(CONFIG_SND_SOC_RT1019)   += snd-soc-rt1019.o
 obj-$(CONFIG_SND_SOC_RT1305)   += snd-soc-rt1305.o
 obj-$(CONFIG_SND_SOC_RT1308)   += snd-soc-rt1308.o
index 2c64df96b5ce92213e58826c684bc3eec1d983cf..949077108bef4f43d98fee76db28f7a5c72c9088 100644 (file)
@@ -358,7 +358,7 @@ static const struct regmap_config ad1836_regmap_config = {
        .max_register = AD1836_ADC_CTRL3,
        .reg_defaults = ad1836_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int ad1836_spi_probe(struct spi_device *spi)
index 5e777d7fd5d91e6eec7d5ddd5c97511dcb2573d9..3c1ae13c1aaeccf95c5df2b8ab9ba95b7407638b 100644 (file)
@@ -92,7 +92,7 @@ static const struct regmap_config ad1980_regmap_config = {
        .reg_stride = 2,
        .val_bits = 16,
        .max_register = 0x7e,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = regmap_ac97_default_volatile,
        .readable_reg = ad1980_readable_reg,
index d9bde7eb043ad31c962283f2e2b4f6f05678c1bb..98380a7ce64d80cbfffee17060cf41350395a915 100644 (file)
@@ -1056,7 +1056,7 @@ const struct regmap_config adau1372_regmap_config = {
        .reg_defaults = adau1372_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(adau1372_reg_defaults),
        .volatile_reg = adau1372_volatile_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(adau1372_regmap_config);
 
index c5b087b8fffc7adaf8f566f23d529c2ad014f595..b0ab0a69b2079407cc1912d43743640b10802fd7 100644 (file)
@@ -1451,7 +1451,7 @@ static const struct regmap_config adau1373_regmap_config = {
        .volatile_reg = adau1373_register_volatile,
        .max_register = ADAU1373_SOFT_RESET,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = adau1373_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
 };
index 8c8de3b3c9014b3a90c28ba396a48606e4aedd4a..94831aad7ac6944cffeab487f410f09ac8704d88 100644 (file)
@@ -778,7 +778,7 @@ static const struct regmap_config adau1701_regmap = {
        .reg_bits               = 16,
        .val_bits               = 32,
        .max_register           = ADAU1701_MAX_REGISTER,
-       .cache_type             = REGCACHE_RBTREE,
+       .cache_type             = REGCACHE_MAPLE,
        .volatile_reg           = adau1701_volatile_reg,
        .reg_write              = adau1701_reg_write,
        .reg_read               = adau1701_reg_read,
index 3ccc7acac20560d38ad935239956f29d6b7fde09..1f09ea385f8af981f86d0f2b3716e0f9117b90c1 100644 (file)
@@ -1014,7 +1014,7 @@ const struct regmap_config adau1761_regmap_config = {
        .readable_reg = adau1761_readable_register,
        .volatile_reg = adau17x1_volatile_register,
        .precious_reg = adau17x1_precious_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(adau1761_regmap_config);
 
index ff6be24863bfb801bac56a4194dd0ddc843ce9c0..faad2f9f8dd2b28adde6678d77ae067de61a900d 100644 (file)
@@ -472,7 +472,7 @@ const struct regmap_config adau1781_regmap_config = {
        .readable_reg           = adau1781_readable_register,
        .volatile_reg           = adau17x1_volatile_register,
        .precious_reg           = adau17x1_precious_register,
-       .cache_type             = REGCACHE_RBTREE,
+       .cache_type             = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(adau1781_regmap_config);
 
index 7a9672f94fc6cd719392f8de6ef4489808c35fef..ae59efb38f265f039ee1e362c4a893816c46aeb8 100644 (file)
@@ -991,7 +991,7 @@ const struct regmap_config adau1977_regmap_config = {
        .max_register = ADAU1977_REG_DC_HPF_CAL,
        .volatile_reg = adau1977_register_volatile,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = adau1977_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
 };
index 73f181f7757e6606e63ae23481a2cb315244190c..b302b28eca7c97fb2d2e7aace464f25eddaad068 100644 (file)
@@ -43,7 +43,7 @@ static const struct regmap_config adau7118_regmap_config = {
        .val_bits = 8,
        .reg_defaults = adau7118_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(adau7118_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .max_register = ADAU7118_REG_RESET,
        .volatile_reg = adau7118_volatile,
 };
index fcff35f26cecb0c99b7020fabf27165922d3e613..bb08969c59171d70f42b688daf872ae18a9c1937 100644 (file)
@@ -870,7 +870,7 @@ const struct regmap_config adav80x_regmap_config = {
 
        .max_register = ADAV80X_PLL_OUTE,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = adav80x_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
 };
index ad56caec9dac309e4945c7ee0c975d1c7d9711b3..619a817ee91cb8fc0f06362aedb3e9ba317d47cb 100644 (file)
@@ -880,20 +880,11 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
 static int ak4613_i2c_probe(struct i2c_client *i2c)
 {
        struct device *dev = &i2c->dev;
-       struct device_node *np = dev->of_node;
        const struct regmap_config *regmap_cfg;
        struct regmap *regmap;
        struct ak4613_priv *priv;
 
-       regmap_cfg = NULL;
-       if (np)
-               regmap_cfg = of_device_get_match_data(dev);
-       else {
-               const struct i2c_device_id *id =
-                       i2c_match_id(ak4613_i2c_id, i2c);
-               regmap_cfg = (const struct regmap_config *)id->driver_data;
-       }
-
+       regmap_cfg = i2c_get_match_data(i2c);
        if (!regmap_cfg)
                return -EINVAL;
 
diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c
new file mode 100644 (file)
index 0000000..a8bf142
--- /dev/null
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// ALSA SoC glue to use IIO devices as audio components
+//
+// Copyright 2023 CS GROUP France
+//
+// Author: Herve Codina <herve.codina@bootlin.com>
+
+#include <linux/iio/consumer.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+struct audio_iio_aux_chan {
+       struct iio_channel *iio_chan;
+       const char *name;
+       int max;
+       int min;
+       bool is_invert_range;
+};
+
+struct audio_iio_aux {
+       struct device *dev;
+       struct audio_iio_aux_chan *chans;
+       unsigned int num_chans;
+};
+
+static int audio_iio_aux_info_volsw(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = chan->max - chan->min;
+       uinfo->type = (uinfo->value.integer.max == 1) ?
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+       return 0;
+}
+
+static int audio_iio_aux_get_volsw(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+       int max = chan->max;
+       int min = chan->min;
+       bool invert_range = chan->is_invert_range;
+       int ret;
+       int val;
+
+       ret = iio_read_channel_raw(chan->iio_chan, &val);
+       if (ret < 0)
+               return ret;
+
+       ucontrol->value.integer.value[0] = val - min;
+       if (invert_range)
+               ucontrol->value.integer.value[0] = max - ucontrol->value.integer.value[0];
+
+       return 0;
+}
+
+static int audio_iio_aux_put_volsw(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct audio_iio_aux_chan *chan = (struct audio_iio_aux_chan *)kcontrol->private_value;
+       int max = chan->max;
+       int min = chan->min;
+       bool invert_range = chan->is_invert_range;
+       int val;
+       int ret;
+       int tmp;
+
+       val = ucontrol->value.integer.value[0];
+       if (val < 0)
+               return -EINVAL;
+       if (val > max - min)
+               return -EINVAL;
+
+       val = val + min;
+       if (invert_range)
+               val = max - val;
+
+       ret = iio_read_channel_raw(chan->iio_chan, &tmp);
+       if (ret < 0)
+               return ret;
+
+       if (tmp == val)
+               return 0;
+
+       ret = iio_write_channel_raw(chan->iio_chan, val);
+       if (ret)
+               return ret;
+
+       return 1; /* The value changed */
+}
+
+static int audio_iio_aux_add_controls(struct snd_soc_component *component,
+                                     struct audio_iio_aux_chan *chan)
+{
+       struct snd_kcontrol_new control = {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = chan->name,
+               .info = audio_iio_aux_info_volsw,
+               .get = audio_iio_aux_get_volsw,
+               .put = audio_iio_aux_put_volsw,
+               .private_value = (unsigned long)chan,
+       };
+
+       return snd_soc_add_component_controls(component, &control, 1);
+}
+
+/*
+ * These data could be on stack but they are pretty big.
+ * As ASoC internally copy them and protect them against concurrent accesses
+ * (snd_soc_bind_card() protects using client_mutex), keep them in the global
+ * data area.
+ */
+static struct snd_soc_dapm_widget widgets[3];
+static struct snd_soc_dapm_route routes[2];
+
+/* Be sure sizes are correct (need 3 widgets and 2 routes) */
+static_assert(ARRAY_SIZE(widgets) >= 3, "3 widgets are needed");
+static_assert(ARRAY_SIZE(routes) >= 2, "2 routes are needed");
+
+static int audio_iio_aux_add_dapms(struct snd_soc_component *component,
+                                  struct audio_iio_aux_chan *chan)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+       char *output_name;
+       char *input_name;
+       char *pga_name;
+       int ret;
+
+       input_name = kasprintf(GFP_KERNEL, "%s IN", chan->name);
+       if (!input_name)
+               return -ENOMEM;
+
+       output_name = kasprintf(GFP_KERNEL, "%s OUT", chan->name);
+       if (!output_name) {
+               ret = -ENOMEM;
+               goto out_free_input_name;
+       }
+
+       pga_name = kasprintf(GFP_KERNEL, "%s PGA", chan->name);
+       if (!pga_name) {
+               ret = -ENOMEM;
+               goto out_free_output_name;
+       }
+
+       widgets[0] = SND_SOC_DAPM_INPUT(input_name);
+       widgets[1] = SND_SOC_DAPM_OUTPUT(output_name);
+       widgets[2] = SND_SOC_DAPM_PGA(pga_name, SND_SOC_NOPM, 0, 0, NULL, 0);
+       ret = snd_soc_dapm_new_controls(dapm, widgets, 3);
+       if (ret)
+               goto out_free_pga_name;
+
+       routes[0].sink = pga_name;
+       routes[0].control = NULL;
+       routes[0].source = input_name;
+       routes[1].sink = output_name;
+       routes[1].control = NULL;
+       routes[1].source = pga_name;
+       ret = snd_soc_dapm_add_routes(dapm, routes, 2);
+
+       /* Allocated names are no more needed (duplicated in ASoC internals) */
+
+out_free_pga_name:
+       kfree(pga_name);
+out_free_output_name:
+       kfree(output_name);
+out_free_input_name:
+       kfree(input_name);
+       return ret;
+}
+
+static int audio_iio_aux_component_probe(struct snd_soc_component *component)
+{
+       struct audio_iio_aux *iio_aux = snd_soc_component_get_drvdata(component);
+       struct audio_iio_aux_chan *chan;
+       int ret;
+       int i;
+
+       for (i = 0; i < iio_aux->num_chans; i++) {
+               chan = iio_aux->chans + i;
+
+               ret = iio_read_max_channel_raw(chan->iio_chan, &chan->max);
+               if (ret)
+                       return dev_err_probe(component->dev, ret,
+                                            "chan[%d] %s: Cannot get max raw value\n",
+                                            i, chan->name);
+
+               ret = iio_read_min_channel_raw(chan->iio_chan, &chan->min);
+               if (ret)
+                       return dev_err_probe(component->dev, ret,
+                                            "chan[%d] %s: Cannot get min raw value\n",
+                                            i, chan->name);
+
+               if (chan->min > chan->max) {
+                       /*
+                        * This should never happen but to avoid any check
+                        * later, just swap values here to ensure that the
+                        * minimum value is lower than the maximum value.
+                        */
+                       dev_dbg(component->dev, "chan[%d] %s: Swap min and max\n",
+                               i, chan->name);
+                       swap(chan->min, chan->max);
+               }
+
+               /* Set initial value */
+               ret = iio_write_channel_raw(chan->iio_chan,
+                                           chan->is_invert_range ? chan->max : chan->min);
+               if (ret)
+                       return dev_err_probe(component->dev, ret,
+                                            "chan[%d] %s: Cannot set initial value\n",
+                                            i, chan->name);
+
+               ret = audio_iio_aux_add_controls(component, chan);
+               if (ret)
+                       return ret;
+
+               ret = audio_iio_aux_add_dapms(component, chan);
+               if (ret)
+                       return ret;
+
+               dev_dbg(component->dev, "chan[%d]: Added %s (min=%d, max=%d, invert=%s)\n",
+                       i, chan->name, chan->min, chan->max,
+                       str_on_off(chan->is_invert_range));
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_component_driver audio_iio_aux_component_driver = {
+       .probe = audio_iio_aux_component_probe,
+};
+
+static int audio_iio_aux_probe(struct platform_device *pdev)
+{
+       struct audio_iio_aux_chan *iio_aux_chan;
+       struct device *dev = &pdev->dev;
+       struct audio_iio_aux *iio_aux;
+       const char **names;
+       u32 *invert_ranges;
+       int count;
+       int ret;
+       int i;
+
+       iio_aux = devm_kzalloc(dev, sizeof(*iio_aux), GFP_KERNEL);
+       if (!iio_aux)
+               return -ENOMEM;
+
+       iio_aux->dev = dev;
+
+       count = device_property_string_array_count(dev, "io-channel-names");
+       if (count < 0)
+               return dev_err_probe(dev, count, "failed to count io-channel-names\n");
+
+       iio_aux->num_chans = count;
+
+       iio_aux->chans = devm_kmalloc_array(dev, iio_aux->num_chans,
+                                           sizeof(*iio_aux->chans), GFP_KERNEL);
+       if (!iio_aux->chans)
+               return -ENOMEM;
+
+       names = kcalloc(iio_aux->num_chans, sizeof(*names), GFP_KERNEL);
+       if (!names)
+               return -ENOMEM;
+
+       invert_ranges = kcalloc(iio_aux->num_chans, sizeof(*invert_ranges), GFP_KERNEL);
+       if (!invert_ranges) {
+               ret = -ENOMEM;
+               goto out_free_names;
+       }
+
+       ret = device_property_read_string_array(dev, "io-channel-names",
+                                               names, iio_aux->num_chans);
+       if (ret < 0) {
+               dev_err_probe(dev, ret, "failed to read io-channel-names\n");
+               goto out_free_invert_ranges;
+       }
+
+       /*
+        * snd-control-invert-range is optional and can contain fewer items
+        * than the number of channels. Unset values default to 0.
+        */
+       count = device_property_count_u32(dev, "snd-control-invert-range");
+       if (count > 0) {
+               count = min_t(unsigned int, count, iio_aux->num_chans);
+               ret = device_property_read_u32_array(dev, "snd-control-invert-range",
+                                                    invert_ranges, count);
+               if (ret < 0) {
+                       dev_err_probe(dev, ret, "failed to read snd-control-invert-range\n");
+                       goto out_free_invert_ranges;
+               }
+       }
+
+       for (i = 0; i < iio_aux->num_chans; i++) {
+               iio_aux_chan = iio_aux->chans + i;
+               iio_aux_chan->name = names[i];
+               iio_aux_chan->is_invert_range = invert_ranges[i];
+
+               iio_aux_chan->iio_chan = devm_iio_channel_get(dev, iio_aux_chan->name);
+               if (IS_ERR(iio_aux_chan->iio_chan)) {
+                       ret = PTR_ERR(iio_aux_chan->iio_chan);
+                       dev_err_probe(dev, ret, "get IIO channel '%s' failed\n",
+                                     iio_aux_chan->name);
+                       goto out_free_invert_ranges;
+               }
+       }
+
+       platform_set_drvdata(pdev, iio_aux);
+
+       ret = devm_snd_soc_register_component(dev, &audio_iio_aux_component_driver,
+                                             NULL, 0);
+out_free_invert_ranges:
+       kfree(invert_ranges);
+out_free_names:
+       kfree(names);
+       return ret;
+}
+
+static const struct of_device_id audio_iio_aux_ids[] = {
+       { .compatible = "audio-iio-aux" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, audio_iio_aux_ids);
+
+static struct platform_driver audio_iio_aux_driver = {
+       .driver = {
+               .name = "audio-iio-aux",
+               .of_match_table = audio_iio_aux_ids,
+       },
+       .probe = audio_iio_aux_probe,
+};
+module_platform_driver(audio_iio_aux_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("IIO ALSA SoC aux driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
new file mode 100644 (file)
index 0000000..6e2266b
--- /dev/null
@@ -0,0 +1,1300 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88261.c  --  AW88261 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "aw88261.h"
+#include "aw88395/aw88395_data_type.h"
+#include "aw88395/aw88395_device.h"
+
+static const struct regmap_config aw88261_remap_config = {
+       .val_bits = 16,
+       .reg_bits = 8,
+       .max_register = AW88261_REG_MAX - 1,
+       .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+       .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+       struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+       unsigned int real_value, volume;
+       unsigned int reg_value;
+
+       volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL);
+       real_value = DB_TO_REG_VAL(volume);
+
+       regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, &reg_value);
+
+       real_value = (real_value | (reg_value & AW88261_VOL_START_MASK));
+
+       dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value);
+
+       regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value);
+}
+
+static void aw88261_dev_fade_in(struct aw_device *aw_dev)
+{
+       struct aw_volume_desc *desc = &aw_dev->volume_desc;
+       int fade_in_vol = desc->ctl_volume;
+       int fade_step = aw_dev->fade_step;
+       int i;
+
+       if (fade_step == 0 || aw_dev->fade_in_time == 0) {
+               aw88261_dev_set_volume(aw_dev, fade_in_vol);
+               return;
+       }
+
+       for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+               aw88261_dev_set_volume(aw_dev, i);
+               usleep_range(aw_dev->fade_in_time,
+                                       aw_dev->fade_in_time + 10);
+       }
+
+       if (i != fade_in_vol)
+               aw88261_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw88261_dev_fade_out(struct aw_device *aw_dev)
+{
+       struct aw_volume_desc *desc = &aw_dev->volume_desc;
+       int fade_step = aw_dev->fade_step;
+       int i;
+
+       if (fade_step == 0 || aw_dev->fade_out_time == 0) {
+               aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL);
+               return;
+       }
+
+       for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) {
+               aw88261_dev_set_volume(aw_dev, i);
+               usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+       }
+
+       if (i != AW88261_MUTE_VOL) {
+               aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL);
+               usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+       }
+}
+
+static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+       if (flag)
+               regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG,
+                       ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_ENABLE_VALUE);
+       else
+               regmap_update_bits(aw_dev->regmap, AW88261_I2SCFG1_REG,
+                       ~AW88261_I2STXEN_MASK, AW88261_I2STXEN_DISABLE_VALUE);
+}
+
+static void aw88261_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+       if (pwd)
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_PWDN_MASK, AW88261_PWDN_POWER_DOWN_VALUE);
+       else
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_PWDN_MASK, AW88261_PWDN_WORKING_VALUE);
+}
+
+static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+       if (amppd)
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_AMPPD_MASK, AW88261_AMPPD_POWER_DOWN_VALUE);
+       else
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_AMPPD_MASK, AW88261_AMPPD_WORKING_VALUE);
+}
+
+static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+       if (is_mute) {
+               aw88261_dev_fade_out(aw_dev);
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE);
+       } else {
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE);
+               aw88261_dev_fade_in(aw_dev);
+       }
+}
+
+static void aw88261_dev_clear_int_status(struct aw_device *aw_dev)
+{
+       unsigned int int_status;
+
+       /* read int status and clear */
+       regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status);
+       /* make sure int status is clear */
+       regmap_read(aw_dev->regmap, AW88261_SYSINT_REG, &int_status);
+
+       dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status);
+}
+
+static int aw88261_dev_get_iis_status(struct aw_device *aw_dev)
+{
+       unsigned int reg_val;
+       int ret;
+
+       ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, &reg_val);
+       if (ret)
+               return ret;
+       if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) {
+               dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+       int ret, i;
+
+       for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+               ret = aw88261_dev_get_iis_status(aw_dev);
+               if (ret) {
+                       dev_err(aw_dev->dev, "mode1 iis signal check error");
+                       usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+               } else {
+                       return ret;
+               }
+       }
+
+       return -EPERM;
+}
+
+static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+       unsigned int reg_val;
+       int ret, i;
+
+       ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, &reg_val);
+       if (ret)
+               return ret;
+
+       reg_val &= (~AW88261_CCO_MUX_MASK);
+       if (reg_val == AW88261_CCO_MUX_DIVIDED_VALUE) {
+               dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
+               return -EPERM;
+       }
+
+       /* change mode2 */
+       ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
+                       ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+               ret = aw88261_dev_get_iis_status(aw_dev);
+               if (ret) {
+                       dev_err(aw_dev->dev, "mode2 iis signal check error");
+                       usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+               } else {
+                       break;
+               }
+       }
+
+       /* change mode1 */
+       ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG,
+                       ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE);
+       if (ret == 0) {
+               usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+               for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+                       ret = aw88261_dev_check_mode1_pll(aw_dev);
+                       if (ret) {
+                               dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+                               usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+                       } else {
+                               break;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static int aw88261_dev_check_syspll(struct aw_device *aw_dev)
+{
+       int ret;
+
+       ret = aw88261_dev_check_mode1_pll(aw_dev);
+       if (ret) {
+               dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+               ret = aw88261_dev_check_mode2_pll(aw_dev);
+               if (ret) {
+                       dev_err(aw_dev->dev, "mode2 check iis failed");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int aw88261_dev_check_sysst(struct aw_device *aw_dev)
+{
+       unsigned int check_val;
+       unsigned int reg_val;
+       int ret, i;
+
+       for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) {
+               ret = regmap_read(aw_dev->regmap, AW88261_SYSST_REG, &reg_val);
+               if (ret)
+                       return ret;
+
+               check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK)
+                                                       & AW88261_BIT_SYSST_CHECK;
+               if (check_val != AW88261_BIT_SYSST_CHECK) {
+                       dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
+                               reg_val, AW88261_BIT_SYSST_CHECK);
+                       usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+               } else {
+                       return 0;
+               }
+       }
+
+       return -EPERM;
+}
+
+static void aw88261_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
+{
+       if (uls_hmute)
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_ULS_HMUTE_MASK,
+                               AW88261_ULS_HMUTE_ENABLE_VALUE);
+       else
+               regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG,
+                               ~AW88261_ULS_HMUTE_MASK,
+                               AW88261_ULS_HMUTE_DISABLE_VALUE);
+}
+
+static void aw88261_reg_force_set(struct aw88261 *aw88261)
+{
+       if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) {
+               /* set FORCE_PWM */
+               regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG,
+                               AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE);
+               /* set BOOST_OS_WIDTH */
+               regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG,
+                               AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE);
+               /* set BURST_LOOPR */
+               regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG,
+                               AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE);
+               /* set RSQN_DLY */
+               regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG,
+                               AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE);
+               /* set BURST_SSMODE */
+               regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG,
+                               AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE);
+               /* set BST_BURST */
+               regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG,
+                               AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE);
+       } else {
+               dev_dbg(aw88261->aw_pa->dev, "needn't set reg value");
+       }
+}
+
+static int aw88261_dev_get_icalk(struct aw_device *aw_dev, int16_t *icalk)
+{
+       u16 reg_icalk, reg_icalkl;
+       unsigned int reg_val;
+       int ret;
+
+       ret = regmap_read(aw_dev->regmap, AW88261_EFRH4_REG, &reg_val);
+       if (ret)
+               return ret;
+
+       reg_icalk = reg_val & (~AW88261_EF_ISN_GESLP_H_MASK);
+
+       ret = regmap_read(aw_dev->regmap, AW88261_EFRL4_REG, &reg_val);
+       if (ret)
+               return ret;
+
+       reg_icalkl = reg_val & (~AW88261_EF_ISN_GESLP_L_MASK);
+
+       reg_icalk = (reg_icalk >> AW88261_ICALK_SHIFT) & (reg_icalkl >> AW88261_ICALKL_SHIFT);
+
+       if (reg_icalk & (~AW88261_EF_ISN_GESLP_SIGN_MASK))
+               reg_icalk = reg_icalk | ~AW88261_EF_ISN_GESLP_NEG;
+
+       *icalk = (int16_t)reg_icalk;
+
+       return ret;
+}
+
+static int aw88261_dev_get_vcalk(struct aw_device *aw_dev, int16_t *vcalk)
+{
+       u16 reg_vcalk, reg_vcalkl;
+       unsigned int reg_val;
+       int ret;
+
+       ret = regmap_read(aw_dev->regmap, AW88261_EFRH3_REG, &reg_val);
+       if (ret)
+               return ret;
+
+       reg_vcalk = (u16)reg_val & (~AW88261_EF_VSN_GESLP_H_MASK);
+
+       ret = regmap_read(aw_dev->regmap, AW88261_EFRL3_REG, &reg_val);
+       if (ret)
+               return ret;
+
+       reg_vcalkl = (u16)reg_val & (~AW88261_EF_VSN_GESLP_L_MASK);
+
+       reg_vcalk = (reg_vcalk >> AW88261_VCALK_SHIFT) & (reg_vcalkl >> AW88261_VCALKL_SHIFT);
+
+       if (reg_vcalk & AW88261_EF_VSN_GESLP_SIGN_MASK)
+               reg_vcalk = reg_vcalk | (~AW88261_EF_VSN_GESLP_NEG);
+       *vcalk = (int16_t)reg_vcalk;
+
+       return ret;
+}
+
+static int aw88261_dev_set_vcalb(struct aw_device *aw_dev)
+{
+       int16_t icalk_val, vcalk_val;
+       int icalk, vcalk, vcalb;
+       u32 reg_val;
+       int ret;
+
+       ret = aw88261_dev_get_icalk(aw_dev, &icalk_val);
+       if (ret)
+               return ret;
+
+       ret = aw88261_dev_get_vcalk(aw_dev, &vcalk_val);
+       if (ret)
+               return ret;
+
+       icalk = AW88261_CABL_BASE_VALUE + AW88261_ICABLK_FACTOR * icalk_val;
+       vcalk = AW88261_CABL_BASE_VALUE + AW88261_VCABLK_FACTOR * vcalk_val;
+       if (!vcalk)
+               return -EINVAL;
+
+       vcalb = AW88261_VCAL_FACTOR * icalk / vcalk;
+       reg_val = (unsigned int)vcalb;
+
+       dev_dbg(aw_dev->dev, "icalk=%d, vcalk=%d, vcalb=%d, reg_val=0x%04x",
+                       icalk, vcalk, vcalb, reg_val);
+       ret = regmap_write(aw_dev->regmap, AW88261_VSNTM1_REG, reg_val);
+
+       return ret;
+}
+
+static int aw88261_dev_reg_update(struct aw88261 *aw88261,
+                                       unsigned char *data, unsigned int len)
+{
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+       unsigned int read_val, efcheck_val, read_vol;
+       int data_len, i, ret;
+       int16_t *reg_data;
+       u16 reg_val;
+       u8 reg_addr;
+
+       if (!len || !data) {
+               dev_err(aw_dev->dev, "reg data is null or len is 0");
+               return -EINVAL;
+       }
+
+       reg_data = (int16_t *)data;
+       data_len = len >> 1;
+
+       if (data_len & 0x1) {
+               dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < data_len; i += 2) {
+               reg_addr = reg_data[i];
+               reg_val = reg_data[i + 1];
+
+               if (reg_addr == AW88261_SYSCTRL_REG) {
+                       aw88261->amppd_st = reg_val & (~AW88261_AMPPD_MASK);
+                       ret = regmap_read(aw_dev->regmap, reg_addr, &read_val);
+                       if (ret)
+                               break;
+
+                       read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) |
+                                                               (~AW88261_HMUTE_MASK);
+                       reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK);
+                       reg_val |= read_val;
+
+                       /* enable uls hmute */
+                       reg_val &= AW88261_ULS_HMUTE_MASK;
+                       reg_val |= AW88261_ULS_HMUTE_ENABLE_VALUE;
+               }
+
+               if (reg_addr == AW88261_DBGCTRL_REG) {
+                       efcheck_val = reg_val & (~AW88261_EF_DBMD_MASK);
+                       if (efcheck_val == AW88261_OR_VALUE)
+                               aw88261->efuse_check = AW88261_EF_OR_CHECK;
+                       else
+                               aw88261->efuse_check = AW88261_EF_AND_CHECK;
+               }
+
+               /* i2stxen */
+               if (reg_addr == AW88261_I2SCTRL3_REG) {
+                       /* close tx */
+                       reg_val &= AW88261_I2STXEN_MASK;
+                       reg_val |= AW88261_I2STXEN_DISABLE_VALUE;
+               }
+
+               if (reg_addr == AW88261_SYSCTRL2_REG) {
+                       read_vol = (reg_val & (~AW88261_VOL_MASK)) >>
+                               AW88261_VOL_START_BIT;
+                       aw_dev->volume_desc.init_volume =
+                               REG_VAL_TO_DB(read_vol);
+               }
+
+               if (reg_addr == AW88261_VSNTM1_REG)
+                       continue;
+
+               ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+               if (ret)
+                       break;
+       }
+
+       ret = aw88261_dev_set_vcalb(aw_dev);
+       if (ret)
+               return ret;
+
+       if (aw_dev->prof_cur != aw_dev->prof_index)
+               vol_desc->ctl_volume = 0;
+
+       /* keep min volume */
+       aw88261_dev_set_volume(aw_dev, vol_desc->mute_volume);
+
+       return ret;
+}
+
+static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index)
+{
+       struct aw_prof_info *prof_info = &aw_dev->prof_info;
+       struct aw_prof_desc *prof_desc;
+
+       if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+               dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+                       index, aw_dev->prof_info.count);
+               return NULL;
+       }
+
+       prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+       return prof_info->prof_name_list[prof_desc->id];
+}
+
+static int aw88261_dev_get_prof_data(struct aw_device *aw_dev, int index,
+                       struct aw_prof_desc **prof_desc)
+{
+       if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+               dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
+                               __func__, index, aw_dev->prof_info.count);
+               return -EINVAL;
+       }
+
+       *prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+       return 0;
+}
+
+static int aw88261_dev_fw_update(struct aw88261 *aw88261)
+{
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       struct aw_prof_desc *prof_index_desc;
+       struct aw_sec_data_desc *sec_desc;
+       char *prof_name;
+       int ret;
+
+       prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index);
+       if (!prof_name) {
+               dev_err(aw_dev->dev, "get prof name failed");
+               return -EINVAL;
+       }
+
+       dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+       ret = aw88261_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+       if (ret)
+               return ret;
+
+       /* update reg */
+       sec_desc = prof_index_desc->sec_desc;
+       ret = aw88261_dev_reg_update(aw88261, sec_desc[AW88395_DATA_TYPE_REG].data,
+                                       sec_desc[AW88395_DATA_TYPE_REG].len);
+       if (ret) {
+               dev_err(aw_dev->dev, "update reg failed");
+               return ret;
+       }
+
+       aw_dev->prof_cur = aw_dev->prof_index;
+
+       return ret;
+}
+
+static int aw88261_dev_start(struct aw88261 *aw88261)
+{
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       int ret;
+
+       if (aw_dev->status == AW88261_DEV_PW_ON) {
+               dev_info(aw_dev->dev, "already power on");
+               return 0;
+       }
+
+       /* power on */
+       aw88261_dev_pwd(aw_dev, false);
+       usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
+
+       ret = aw88261_dev_check_syspll(aw_dev);
+       if (ret) {
+               dev_err(aw_dev->dev, "pll check failed cannot start");
+               goto pll_check_fail;
+       }
+
+       /* amppd on */
+       aw88261_dev_amppd(aw_dev, false);
+       usleep_range(AW88261_1000_US, AW88261_1000_US + 50);
+
+       /* check i2s status */
+       ret = aw88261_dev_check_sysst(aw_dev);
+       if (ret) {
+               dev_err(aw_dev->dev, "sysst check failed");
+               goto sysst_check_fail;
+       }
+
+       /* enable tx feedback */
+       aw88261_dev_i2s_tx_enable(aw_dev, true);
+
+       if (aw88261->amppd_st)
+               aw88261_dev_amppd(aw_dev, true);
+
+       aw88261_reg_force_set(aw88261);
+
+       /* close uls mute */
+       aw88261_dev_uls_hmute(aw_dev, false);
+
+       /* close mute */
+       if (!aw88261->mute_st)
+               aw88261_dev_mute(aw_dev, false);
+
+       /* clear inturrupt */
+       aw88261_dev_clear_int_status(aw_dev);
+       aw_dev->status = AW88261_DEV_PW_ON;
+
+       return 0;
+
+sysst_check_fail:
+       aw88261_dev_i2s_tx_enable(aw_dev, false);
+       aw88261_dev_clear_int_status(aw_dev);
+       aw88261_dev_amppd(aw_dev, true);
+pll_check_fail:
+       aw88261_dev_pwd(aw_dev, true);
+       aw_dev->status = AW88261_DEV_PW_OFF;
+
+       return ret;
+}
+
+static int aw88261_dev_stop(struct aw_device *aw_dev)
+{
+       if (aw_dev->status == AW88261_DEV_PW_OFF) {
+               dev_info(aw_dev->dev, "already power off");
+               return 0;
+       }
+
+       aw_dev->status = AW88261_DEV_PW_OFF;
+
+       /* clear inturrupt */
+       aw88261_dev_clear_int_status(aw_dev);
+
+       aw88261_dev_uls_hmute(aw_dev, true);
+       /* set mute */
+       aw88261_dev_mute(aw_dev, true);
+
+       /* close tx feedback */
+       aw88261_dev_i2s_tx_enable(aw_dev, false);
+       usleep_range(AW88261_1000_US, AW88261_1000_US + 100);
+
+       /* enable amppd */
+       aw88261_dev_amppd(aw_dev, true);
+
+       /* set power down */
+       aw88261_dev_pwd(aw_dev, true);
+
+       return 0;
+}
+
+static int aw88261_reg_update(struct aw88261 *aw88261, bool force)
+{
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       int ret;
+
+       if (force) {
+               ret = regmap_write(aw_dev->regmap,
+                                       AW88261_ID_REG, AW88261_SOFT_RESET_VALUE);
+               if (ret)
+                       return ret;
+
+               ret = aw88261_dev_fw_update(aw88261);
+               if (ret)
+                       return ret;
+       } else {
+               if (aw_dev->prof_cur != aw_dev->prof_index) {
+                       ret = aw88261_dev_fw_update(aw88261);
+                       if (ret)
+                               return ret;
+               } else {
+                       ret = 0;
+               }
+       }
+
+       aw_dev->prof_cur = aw_dev->prof_index;
+
+       return ret;
+}
+
+static void aw88261_start_pa(struct aw88261 *aw88261)
+{
+       int ret, i;
+
+       for (i = 0; i < AW88261_START_RETRIES; i++) {
+               ret = aw88261_reg_update(aw88261, aw88261->phase_sync);
+               if (ret) {
+                       dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i);
+                       continue;
+               }
+               ret = aw88261_dev_start(aw88261);
+               if (ret) {
+                       dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i);
+                       continue;
+               } else {
+                       dev_info(aw88261->aw_pa->dev, "start success\n");
+                       break;
+               }
+       }
+}
+
+static void aw88261_startup_work(struct work_struct *work)
+{
+       struct aw88261 *aw88261 =
+               container_of(work, struct aw88261, start_work.work);
+
+       mutex_lock(&aw88261->lock);
+       aw88261_start_pa(aw88261);
+       mutex_unlock(&aw88261->lock);
+}
+
+static void aw88261_start(struct aw88261 *aw88261, bool sync_start)
+{
+       if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK)
+               return;
+
+       if (aw88261->aw_pa->status == AW88261_DEV_PW_ON)
+               return;
+
+       if (sync_start == AW88261_SYNC_START)
+               aw88261_start_pa(aw88261);
+       else
+               queue_delayed_work(system_wq,
+                       &aw88261->start_work,
+                       AW88261_START_WORK_DELAY_MS);
+}
+
+static struct snd_soc_dai_driver aw88261_dai[] = {
+       {
+               .name = "aw88261-aif",
+               .id = 1,
+               .playback = {
+                       .stream_name = "Speaker_Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AW88261_RATES,
+                       .formats = AW88261_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Speaker_Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = AW88261_RATES,
+                       .formats = AW88261_FORMATS,
+               },
+       },
+};
+
+static int aw88261_get_fade_in_time(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+       struct aw_device *aw_dev = aw88261->aw_pa;
+
+       ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+       return 0;
+}
+
+static int aw88261_set_fade_in_time(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       int time;
+
+       time = ucontrol->value.integer.value[0];
+
+       if (time < mc->min || time > mc->max)
+               return -EINVAL;
+
+       if (time != aw_dev->fade_in_time) {
+               aw_dev->fade_in_time = time;
+               return 1;
+       }
+
+       return 0;
+}
+
+static int aw88261_get_fade_out_time(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+       struct aw_device *aw_dev = aw88261->aw_pa;
+
+       ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+       return 0;
+}
+
+static int aw88261_set_fade_out_time(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       int time;
+
+       time = ucontrol->value.integer.value[0];
+       if (time < mc->min || time > mc->max)
+               return -EINVAL;
+
+       if (time != aw_dev->fade_out_time) {
+               aw_dev->fade_out_time = time;
+               return 1;
+       }
+
+       return 0;
+}
+
+static int aw88261_dev_set_profile_index(struct aw_device *aw_dev, int index)
+{
+       /* check the index whether is valid */
+       if ((index >= aw_dev->prof_info.count) || (index < 0))
+               return -EINVAL;
+       /* check the index whether change */
+       if (aw_dev->prof_index == index)
+               return -EPERM;
+
+       aw_dev->prof_index = index;
+
+       return 0;
+}
+
+static int aw88261_profile_info(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+       const char *prof_name;
+       char *name;
+       int count;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+
+       count = aw88261->aw_pa->prof_info.count;
+       if (count <= 0) {
+               uinfo->value.enumerated.items = 0;
+               return 0;
+       }
+
+       uinfo->value.enumerated.items = count;
+
+       if (uinfo->value.enumerated.item >= count)
+               uinfo->value.enumerated.item = count - 1;
+
+       name = uinfo->value.enumerated.name;
+       count = uinfo->value.enumerated.item;
+
+       prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count);
+       if (!prof_name) {
+               strscpy(uinfo->value.enumerated.name, "null",
+                                               strlen("null") + 1);
+               return 0;
+       }
+
+       strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));
+
+       return 0;
+}
+
+static int aw88261_profile_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = aw88261->aw_pa->prof_index;
+
+       return 0;
+}
+
+static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+       int ret;
+
+       /* pa stop or stopping just set profile */
+       mutex_lock(&aw88261->lock);
+       ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]);
+       if (ret) {
+               dev_dbg(codec->dev, "profile index does not change");
+               mutex_unlock(&aw88261->lock);
+               return 0;
+       }
+
+       if (aw88261->aw_pa->status) {
+               aw88261_dev_stop(aw88261->aw_pa);
+               aw88261_start(aw88261, AW88261_SYNC_START);
+       }
+
+       mutex_unlock(&aw88261->lock);
+
+       return 1;
+}
+
+static int aw88261_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+       struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc;
+
+       ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+       return 0;
+}
+
+static int aw88261_volume_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+       struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int value;
+
+       value = ucontrol->value.integer.value[0];
+
+       if (value < mc->min || value > mc->max)
+               return -EINVAL;
+
+       if (vol_desc->ctl_volume != value) {
+               vol_desc->ctl_volume = value;
+               aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step;
+
+       return 0;
+}
+
+static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int value;
+
+       value = ucontrol->value.integer.value[0];
+       if (value < mc->min || value > mc->max)
+               return -EINVAL;
+
+       if (aw88261->aw_pa->fade_step != value) {
+               aw88261->aw_pa->fade_step = value;
+               return 1;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new aw88261_controls[] = {
+       SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG,
+               6, AW88261_MUTE_VOL, 0, aw88261_volume_get,
+               aw88261_volume_set),
+       SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0,
+               aw88261_get_fade_step, aw88261_set_fade_step),
+       SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+               aw88261_get_fade_in_time, aw88261_set_fade_in_time),
+       SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+               aw88261_get_fade_out_time, aw88261_set_fade_out_time),
+       AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info,
+               aw88261_profile_get, aw88261_profile_set),
+};
+
+static int aw88261_playback_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+
+       mutex_lock(&aw88261->lock);
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               aw88261_start(aw88261, AW88261_ASYNC_START);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               aw88261_dev_stop(aw88261->aw_pa);
+               break;
+       default:
+               break;
+       }
+       mutex_unlock(&aw88261->lock);
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88261_dapm_widgets[] = {
+        /* playback */
+       SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0,
+                                       aw88261_playback_event,
+                                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+       /* capture */
+       SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_INPUT("ADC Input"),
+};
+
+static const struct snd_soc_dapm_route aw88261_audio_map[] = {
+       {"DAC Output", NULL, "AIF_RX"},
+       {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88261_frcset_check(struct aw88261 *aw88261)
+{
+       unsigned int reg_val;
+       u16 temh, teml, tem;
+       int ret;
+
+       ret = regmap_read(aw88261->regmap, AW88261_EFRH3_REG, &reg_val);
+       if (ret)
+               return ret;
+       temh = ((u16)reg_val & (~AW88261_TEMH_MASK));
+
+       ret = regmap_read(aw88261->regmap, AW88261_EFRL3_REG, &reg_val);
+       if (ret)
+               return ret;
+       teml = ((u16)reg_val & (~AW88261_TEML_MASK));
+
+       if (aw88261->efuse_check == AW88261_EF_OR_CHECK)
+               tem = (temh | teml);
+       else
+               tem = (temh & teml);
+
+       if (tem == AW88261_DEFAULT_CFG)
+               aw88261->frcset_en = AW88261_FRCSET_ENABLE;
+       else
+               aw88261->frcset_en = AW88261_FRCSET_DISABLE;
+
+       dev_dbg(aw88261->aw_pa->dev, "tem is 0x%04x, frcset_en is %d",
+                                               tem, aw88261->frcset_en);
+
+       return ret;
+}
+
+static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg)
+{
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       int ret;
+
+       ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+       if (ret) {
+               dev_err(aw_dev->dev, "aw_dev acf parse failed");
+               return -EINVAL;
+       }
+
+       ret = regmap_write(aw_dev->regmap, AW88261_ID_REG, AW88261_SOFT_RESET_VALUE);
+       if (ret)
+               return ret;
+
+       aw_dev->fade_in_time = AW88261_500_US;
+       aw_dev->fade_out_time = AW88261_500_US;
+       aw_dev->prof_cur = AW88261_INIT_PROFILE;
+       aw_dev->prof_index = AW88261_INIT_PROFILE;
+
+       ret = aw88261_dev_fw_update(aw88261);
+       if (ret) {
+               dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+               return ret;
+       }
+
+       ret = aw88261_frcset_check(aw88261);
+       if (ret) {
+               dev_err(aw_dev->dev, "aw88261_frcset_check ret = %d\n", ret);
+               return ret;
+       }
+
+       aw88261_dev_clear_int_status(aw_dev);
+
+       aw88261_dev_uls_hmute(aw_dev, true);
+
+       aw88261_dev_mute(aw_dev, true);
+
+       aw88261_dev_i2s_tx_enable(aw_dev, false);
+
+       usleep_range(AW88261_1000_US, AW88261_1000_US + 100);
+
+       aw88261_dev_amppd(aw_dev, true);
+
+       aw88261_dev_pwd(aw_dev, true);
+
+       return 0;
+}
+
+static int aw88261_request_firmware_file(struct aw88261 *aw88261)
+{
+       const struct firmware *cont = NULL;
+       int ret;
+
+       aw88261->aw_pa->fw_status = AW88261_DEV_FW_FAILED;
+
+       ret = request_firmware(&cont, AW88261_ACF_FILE, aw88261->aw_pa->dev);
+       if (ret)
+               return dev_err_probe(aw88261->aw_pa->dev, ret,
+                                       "load [%s] failed!", AW88261_ACF_FILE);
+
+       dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n",
+                       AW88261_ACF_FILE, cont ? cont->size : 0);
+
+       aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
+       if (!aw88261->aw_cfg) {
+               release_firmware(cont);
+               return -ENOMEM;
+       }
+       aw88261->aw_cfg->len = (int)cont->size;
+       memcpy(aw88261->aw_cfg->data, cont->data, cont->size);
+       release_firmware(cont);
+
+       ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg);
+       if (ret) {
+               dev_err(aw88261->aw_pa->dev, "load [%s] failed !", AW88261_ACF_FILE);
+               return ret;
+       }
+
+       mutex_lock(&aw88261->lock);
+       /* aw device init */
+       ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
+       if (ret)
+               dev_err(aw88261->aw_pa->dev, "dev init failed");
+       mutex_unlock(&aw88261->lock);
+
+       return ret;
+}
+
+static int aw88261_codec_probe(struct snd_soc_component *component)
+{
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
+       int ret;
+
+       INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work);
+
+       ret = aw88261_request_firmware_file(aw88261);
+       if (ret)
+               return dev_err_probe(aw88261->aw_pa->dev, ret,
+                               "aw88261_request_firmware_file failed\n");
+
+       /* add widgets */
+       ret = snd_soc_dapm_new_controls(dapm, aw88261_dapm_widgets,
+                                                       ARRAY_SIZE(aw88261_dapm_widgets));
+       if (ret)
+               return ret;
+
+       /* add route */
+       ret = snd_soc_dapm_add_routes(dapm, aw88261_audio_map,
+                                                       ARRAY_SIZE(aw88261_audio_map));
+       if (ret)
+               return ret;
+
+       ret = snd_soc_add_component_controls(component, aw88261_controls,
+                                                       ARRAY_SIZE(aw88261_controls));
+
+       return ret;
+}
+
+static void aw88261_codec_remove(struct snd_soc_component *aw_codec)
+{
+       struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec);
+
+       cancel_delayed_work_sync(&aw88261->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88261 = {
+       .probe = aw88261_codec_probe,
+       .remove = aw88261_codec_remove,
+};
+
+static void aw88261_hw_reset(struct aw88261 *aw88261)
+{
+       gpiod_set_value_cansleep(aw88261->reset_gpio, 0);
+       usleep_range(AW88261_1000_US, AW88261_1000_US + 10);
+       gpiod_set_value_cansleep(aw88261->reset_gpio, 1);
+       usleep_range(AW88261_1000_US, AW88261_1000_US + 10);
+}
+
+static void aw88261_parse_channel_dt(struct aw88261 *aw88261)
+{
+       struct aw_device *aw_dev = aw88261->aw_pa;
+       struct device_node *np = aw_dev->dev->of_node;
+       u32 channel_value = AW88261_DEV_DEFAULT_CH;
+       u32 sync_enable = false;
+
+       of_property_read_u32(np, "sound-channel", &channel_value);
+       of_property_read_u32(np, "sync-flag", &sync_enable);
+
+       aw_dev->channel = channel_value;
+       aw88261->phase_sync = sync_enable;
+}
+
+static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct regmap *regmap)
+{
+       struct aw_device *aw_dev;
+       unsigned int chip_id;
+       int ret;
+
+       /* read chip id */
+       ret = regmap_read(regmap, AW88261_ID_REG, &chip_id);
+       if (ret) {
+               dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+               return ret;
+       }
+       if (chip_id != AW88261_CHIP_ID) {
+               dev_err(&i2c->dev, "unsupported device");
+               return -ENXIO;
+       }
+
+       dev_info(&i2c->dev, "chip id = %x\n", chip_id);
+
+       aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+       if (!aw_dev)
+               return -ENOMEM;
+
+       (*aw88261)->aw_pa = aw_dev;
+       aw_dev->i2c = i2c;
+       aw_dev->regmap = regmap;
+       aw_dev->dev = &i2c->dev;
+       aw_dev->chip_id = AW88261_CHIP_ID;
+       aw_dev->acf = NULL;
+       aw_dev->prof_info.prof_desc = NULL;
+       aw_dev->prof_info.count = 0;
+       aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+       aw_dev->channel = 0;
+       aw_dev->fw_status = AW88261_DEV_FW_FAILED;
+       aw_dev->fade_step = AW88261_VOLUME_STEP_DB;
+       aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE;
+       aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL;
+       aw88261_parse_channel_dt(*aw88261);
+
+       return ret;
+}
+
+static int aw88261_i2c_probe(struct i2c_client *i2c)
+{
+       struct aw88261 *aw88261;
+       int ret;
+
+       ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
+       if (!ret)
+               return dev_err_probe(&i2c->dev, ret, "check_functionality failed");
+
+       aw88261 = devm_kzalloc(&i2c->dev, sizeof(*aw88261), GFP_KERNEL);
+       if (!aw88261)
+               return -ENOMEM;
+
+       mutex_init(&aw88261->lock);
+
+       i2c_set_clientdata(i2c, aw88261);
+
+       aw88261->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(aw88261->reset_gpio))
+               dev_info(&i2c->dev, "reset gpio not defined\n");
+       else
+               aw88261_hw_reset(aw88261);
+
+       aw88261->regmap = devm_regmap_init_i2c(i2c, &aw88261_remap_config);
+       if (IS_ERR(aw88261->regmap)) {
+               ret = PTR_ERR(aw88261->regmap);
+               return dev_err_probe(&i2c->dev, ret, "failed to init regmap: %d\n", ret);
+       }
+
+       /* aw pa init */
+       ret = aw88261_init(&aw88261, i2c, aw88261->regmap);
+       if (ret)
+               return ret;
+
+       ret = devm_snd_soc_register_component(&i2c->dev,
+                       &soc_codec_dev_aw88261,
+                       aw88261_dai, ARRAY_SIZE(aw88261_dai));
+       if (ret)
+               dev_err(&i2c->dev, "failed to register aw88261: %d", ret);
+
+       return ret;
+}
+
+static const struct i2c_device_id aw88261_i2c_id[] = {
+       { AW88261_I2C_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id);
+
+static struct i2c_driver aw88261_i2c_driver = {
+       .driver = {
+               .name = AW88261_I2C_NAME,
+       },
+       .probe = aw88261_i2c_probe,
+       .id_table = aw88261_i2c_id,
+};
+module_i2c_driver(aw88261_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88261 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h
new file mode 100644 (file)
index 0000000..4f3dbf4
--- /dev/null
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88261.h  --  AW88261 ALSA SoC Audio driver
+//
+// Copyright (c) 2023 awinic Technology CO., LTD
+//
+// Author: Jimmy Zhang <zhangjianming@awinic.com>
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88261_H__
+#define __AW88261_H__
+
+#define AW88261_ID_REG                 (0x00)
+#define AW88261_SYSST_REG              (0x01)
+#define AW88261_SYSINT_REG             (0x02)
+#define AW88261_SYSINTM_REG            (0x03)
+#define AW88261_SYSCTRL_REG            (0x04)
+#define AW88261_SYSCTRL2_REG           (0x05)
+#define AW88261_I2SCTRL1_REG           (0x06)
+#define AW88261_I2SCTRL2_REG           (0x07)
+#define AW88261_I2SCTRL3_REG           (0x08)
+#define AW88261_DACCFG1_REG            (0x09)
+#define AW88261_DACCFG2_REG            (0x0A)
+#define AW88261_DACCFG3_REG            (0x0B)
+#define AW88261_DACCFG4_REG            (0x0C)
+#define AW88261_DACCFG5_REG            (0x0D)
+#define AW88261_DACCFG6_REG            (0x0E)
+#define AW88261_DACCFG7_REG            (0x0F)
+#define AW88261_DACCFG8_REG            (0x10)
+#define AW88261_PWMCTRL1_REG           (0x11)
+#define AW88261_PWMCTRL2_REG           (0x12)
+#define AW88261_I2SCFG1_REG            (0x13)
+#define AW88261_DBGCTRL_REG            (0x14)
+#define AW88261_DACCFG9_REG            (0x15)
+#define AW88261_DACCFG10_REG           (0x16)
+#define AW88261_DACST_REG              (0x20)
+#define AW88261_VBAT_REG               (0x21)
+#define AW88261_TEMP_REG               (0x22)
+#define AW88261_PVDD_REG               (0x23)
+#define AW88261_ISNDAT_REG             (0x24)
+#define AW88261_VSNDAT_REG             (0x25)
+#define AW88261_I2SINT_REG             (0x26)
+#define AW88261_I2SCAPCNT_REG          (0x27)
+#define AW88261_ANASTA1_REG            (0x28)
+#define AW88261_ANASTA2_REG            (0x29)
+#define AW88261_ANASTA3_REG            (0x2A)
+#define AW88261_TESTDET_REG            (0x2B)
+#define AW88261_DSMCFG1_REG            (0x30)
+#define AW88261_DSMCFG2_REG            (0x31)
+#define AW88261_DSMCFG3_REG            (0x32)
+#define AW88261_DSMCFG4_REG            (0x33)
+#define AW88261_DSMCFG5_REG            (0x34)
+#define AW88261_DSMCFG6_REG            (0x35)
+#define AW88261_DSMCFG7_REG            (0x36)
+#define AW88261_DSMCFG8_REG            (0x37)
+#define AW88261_TESTIN_REG             (0x38)
+#define AW88261_TESTOUT_REG            (0x39)
+#define AW88261_SADCCTRL1_REG          (0x3A)
+#define AW88261_SADCCTRL2_REG          (0x3B)
+#define AW88261_SADCCTRL3_REG          (0x3C)
+#define AW88261_SADCCTRL4_REG          (0x3D)
+#define AW88261_SADCCTRL5_REG          (0x3E)
+#define AW88261_SADCCTRL6_REG          (0x3F)
+#define AW88261_SADCCTRL7_REG          (0x40)
+#define AW88261_VSNTM1_REG             (0x50)
+#define AW88261_VSNTM2_REG             (0x51)
+#define AW88261_ISNCTRL1_REG           (0x52)
+#define AW88261_ISNCTRL2_REG           (0x53)
+#define AW88261_PLLCTRL1_REG           (0x54)
+#define AW88261_PLLCTRL2_REG           (0x55)
+#define AW88261_PLLCTRL3_REG           (0x56)
+#define AW88261_CDACTRL1_REG           (0x57)
+#define AW88261_CDACTRL2_REG           (0x58)
+#define AW88261_DITHERCFG1_REG         (0x59)
+#define AW88261_DITHERCFG2_REG         (0x5A)
+#define AW88261_DITHERCFG3_REG         (0x5B)
+#define AW88261_CPCTRL_REG             (0x5C)
+#define AW88261_BSTCTRL1_REG           (0x60)
+#define AW88261_BSTCTRL2_REG           (0x61)
+#define AW88261_BSTCTRL3_REG           (0x62)
+#define AW88261_BSTCTRL4_REG           (0x63)
+#define AW88261_BSTCTRL5_REG           (0x64)
+#define AW88261_BSTCTRL6_REG           (0x65)
+#define AW88261_BSTCTRL7_REG           (0x66)
+#define AW88261_BSTCTRL8_REG           (0x67)
+#define AW88261_BSTCTRL9_REG           (0x68)
+#define AW88261_TM_REG                 (0x6F)
+#define AW88261_TESTCTRL1_REG          (0x70)
+#define AW88261_TESTCTRL2_REG          (0x71)
+#define AW88261_EFCTRL1_REG            (0x72)
+#define AW88261_EFCTRL2_REG            (0x73)
+#define AW88261_EFWH_REG               (0x74)
+#define AW88261_EFWM2_REG              (0x75)
+#define AW88261_EFWM1_REG              (0x76)
+#define AW88261_EFWL_REG               (0x77)
+#define AW88261_EFRH4_REG              (0x78)
+#define AW88261_EFRH3_REG              (0x79)
+#define AW88261_EFRH2_REG              (0x7A)
+#define AW88261_EFRH1_REG              (0x7B)
+#define AW88261_EFRL4_REG              (0x7C)
+#define AW88261_EFRL3_REG              (0x7D)
+#define AW88261_EFRL2_REG              (0x7E)
+#define AW88261_EFRL1_REG              (0x7F)
+
+#define AW88261_REG_MAX                (0x80)
+#define AW88261_EF_DBMD_MASK           (0xfff7)
+#define AW88261_OR_VALUE               (0x0008)
+
+#define AW88261_TEMH_MASK              (0x83ff)
+#define AW88261_TEML_MASK              (0x83ff)
+#define AW88261_DEFAULT_CFG            (0x0000)
+
+#define AW88261_ICALK_SHIFT            (0)
+#define AW88261_ICALKL_SHIFT           (0)
+#define AW88261_VCALK_SHIFT            (0)
+#define AW88261_VCALKL_SHIFT           (0)
+
+#define AW88261_AMPPD_START_BIT        (1)
+#define AW88261_AMPPD_BITS_LEN         (1)
+#define AW88261_AMPPD_MASK             \
+       (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT))
+
+#define AW88261_UVLS_START_BIT         (14)
+#define AW88261_UVLS_NORMAL            (0)
+#define AW88261_UVLS_NORMAL_VALUE      \
+       (AW88261_UVLS_NORMAL << AW88261_UVLS_START_BIT)
+
+#define AW88261_BSTOCS_START_BIT       (11)
+#define AW88261_BSTOCS_OVER_CURRENT    (1)
+#define AW88261_BSTOCS_OVER_CURRENT_VALUE      \
+       (AW88261_BSTOCS_OVER_CURRENT << AW88261_BSTOCS_START_BIT)
+
+#define AW88261_BSTS_START_BIT         (9)
+#define AW88261_BSTS_FINISHED          (1)
+#define AW88261_BSTS_FINISHED_VALUE    \
+       (AW88261_BSTS_FINISHED << AW88261_BSTS_START_BIT)
+
+#define AW88261_SWS_START_BIT          (8)
+#define AW88261_SWS_SWITCHING          (1)
+#define AW88261_SWS_SWITCHING_VALUE    \
+       (AW88261_SWS_SWITCHING << AW88261_SWS_START_BIT)
+
+#define AW88261_NOCLKS_START_BIT       (5)
+#define AW88261_NOCLKS_NO_CLOCK        (1)
+#define AW88261_NOCLKS_NO_CLOCK_VALUE  \
+       (AW88261_NOCLKS_NO_CLOCK << AW88261_NOCLKS_START_BIT)
+
+#define AW88261_CLKS_START_BIT         (4)
+#define AW88261_CLKS_STABLE            (1)
+#define AW88261_CLKS_STABLE_VALUE      \
+       (AW88261_CLKS_STABLE << AW88261_CLKS_START_BIT)
+
+#define AW88261_OCDS_START_BIT         (3)
+#define AW88261_OCDS_OC                (1)
+#define AW88261_OCDS_OC_VALUE          \
+       (AW88261_OCDS_OC << AW88261_OCDS_START_BIT)
+
+#define AW88261_OTHS_START_BIT         (1)
+#define AW88261_OTHS_OT                (1)
+#define AW88261_OTHS_OT_VALUE          \
+       (AW88261_OTHS_OT << AW88261_OTHS_START_BIT)
+
+#define AW88261_PLLS_START_BIT         (0)
+#define AW88261_PLLS_LOCKED            (1)
+#define AW88261_PLLS_LOCKED_VALUE      \
+       (AW88261_PLLS_LOCKED << AW88261_PLLS_START_BIT)
+
+#define AW88261_BIT_PLL_CHECK \
+               (AW88261_CLKS_STABLE_VALUE | \
+               AW88261_PLLS_LOCKED_VALUE)
+
+#define AW88261_BIT_SYSST_CHECK_MASK \
+               (~(AW88261_UVLS_NORMAL_VALUE | \
+               AW88261_BSTOCS_OVER_CURRENT_VALUE | \
+               AW88261_BSTS_FINISHED_VALUE | \
+               AW88261_SWS_SWITCHING_VALUE | \
+               AW88261_NOCLKS_NO_CLOCK_VALUE | \
+               AW88261_CLKS_STABLE_VALUE | \
+               AW88261_OCDS_OC_VALUE | \
+               AW88261_OTHS_OT_VALUE | \
+               AW88261_PLLS_LOCKED_VALUE))
+
+#define AW88261_BIT_SYSST_CHECK \
+               (AW88261_BSTS_FINISHED_VALUE | \
+               AW88261_SWS_SWITCHING_VALUE | \
+               AW88261_CLKS_STABLE_VALUE | \
+               AW88261_PLLS_LOCKED_VALUE)
+
+#define AW88261_ULS_HMUTE_START_BIT    (14)
+#define AW88261_ULS_HMUTE_BITS_LEN     (1)
+#define AW88261_ULS_HMUTE_MASK         \
+       (~(((1<<AW88261_ULS_HMUTE_BITS_LEN)-1) << AW88261_ULS_HMUTE_START_BIT))
+
+#define AW88261_ULS_HMUTE_DISABLE      (0)
+#define AW88261_ULS_HMUTE_DISABLE_VALUE        \
+       (AW88261_ULS_HMUTE_DISABLE << AW88261_ULS_HMUTE_START_BIT)
+
+#define AW88261_ULS_HMUTE_ENABLE       (1)
+#define AW88261_ULS_HMUTE_ENABLE_VALUE \
+       (AW88261_ULS_HMUTE_ENABLE << AW88261_ULS_HMUTE_START_BIT)
+
+#define AW88261_HMUTE_START_BIT        (8)
+#define AW88261_HMUTE_BITS_LEN         (1)
+#define AW88261_HMUTE_MASK             \
+       (~(((1<<AW88261_HMUTE_BITS_LEN)-1) << AW88261_HMUTE_START_BIT))
+
+#define AW88261_HMUTE_DISABLE          (0)
+#define AW88261_HMUTE_DISABLE_VALUE    \
+       (AW88261_HMUTE_DISABLE << AW88261_HMUTE_START_BIT)
+
+#define AW88261_HMUTE_ENABLE           (1)
+#define AW88261_HMUTE_ENABLE_VALUE     \
+       (AW88261_HMUTE_ENABLE << AW88261_HMUTE_START_BIT)
+
+#define AW88261_AMPPD_START_BIT        (1)
+#define AW88261_AMPPD_BITS_LEN         (1)
+#define AW88261_AMPPD_MASK             \
+       (~(((1<<AW88261_AMPPD_BITS_LEN)-1) << AW88261_AMPPD_START_BIT))
+
+#define AW88261_AMPPD_WORKING          (0)
+#define AW88261_AMPPD_WORKING_VALUE    \
+       (AW88261_AMPPD_WORKING << AW88261_AMPPD_START_BIT)
+
+#define AW88261_AMPPD_POWER_DOWN       (1)
+#define AW88261_AMPPD_POWER_DOWN_VALUE \
+       (AW88261_AMPPD_POWER_DOWN << AW88261_AMPPD_START_BIT)
+
+#define AW88261_PWDN_START_BIT         (0)
+#define AW88261_PWDN_BITS_LEN          (1)
+#define AW88261_PWDN_MASK              \
+       (~(((1<<AW88261_PWDN_BITS_LEN)-1) << AW88261_PWDN_START_BIT))
+
+#define AW88261_PWDN_WORKING           (0)
+#define AW88261_PWDN_WORKING_VALUE     \
+       (AW88261_PWDN_WORKING << AW88261_PWDN_START_BIT)
+
+#define AW88261_PWDN_POWER_DOWN        (1)
+#define AW88261_PWDN_POWER_DOWN_VALUE  \
+       (AW88261_PWDN_POWER_DOWN << AW88261_PWDN_START_BIT)
+
+#define AW88261_MUTE_VOL               (90 * 8)
+#define AW88261_VOLUME_STEP_DB         (6 * 8)
+
+#define AW88261_VOL_6DB_START          (6)
+
+#define AW88261_VOL_START_BIT          (0)
+#define AW88261_VOL_BITS_LEN           (10)
+#define AW88261_VOL_MASK               \
+       (~(((1<<AW88261_VOL_BITS_LEN)-1) << AW88261_VOL_START_BIT))
+
+#define AW88261_VOL_DEFAULT_VALUE      (0)
+
+#define AW88261_I2STXEN_START_BIT      (6)
+#define AW88261_I2STXEN_BITS_LEN       (1)
+#define AW88261_I2STXEN_MASK           \
+       (~(((1<<AW88261_I2STXEN_BITS_LEN)-1) << AW88261_I2STXEN_START_BIT))
+
+#define AW88261_I2STXEN_DISABLE        (0)
+#define AW88261_I2STXEN_DISABLE_VALUE  \
+       (AW88261_I2STXEN_DISABLE << AW88261_I2STXEN_START_BIT)
+
+#define AW88261_I2STXEN_ENABLE         (1)
+#define AW88261_I2STXEN_ENABLE_VALUE   \
+       (AW88261_I2STXEN_ENABLE << AW88261_I2STXEN_START_BIT)
+
+#define AW88261_CCO_MUX_START_BIT      (14)
+#define AW88261_CCO_MUX_BITS_LEN       (1)
+#define AW88261_CCO_MUX_MASK           \
+       (~(((1<<AW88261_CCO_MUX_BITS_LEN)-1) << AW88261_CCO_MUX_START_BIT))
+
+#define AW88261_CCO_MUX_DIVIDED        (0)
+#define AW88261_CCO_MUX_DIVIDED_VALUE  \
+       (AW88261_CCO_MUX_DIVIDED << AW88261_CCO_MUX_START_BIT)
+
+#define AW88261_CCO_MUX_BYPASS         (1)
+#define AW88261_CCO_MUX_BYPASS_VALUE   \
+       (AW88261_CCO_MUX_BYPASS << AW88261_CCO_MUX_START_BIT)
+
+#define AW88261_EF_VSN_GESLP_H_START_BIT       (0)
+#define AW88261_EF_VSN_GESLP_H_BITS_LEN        (10)
+#define AW88261_EF_VSN_GESLP_H_MASK            \
+       (~(((1<<AW88261_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_H_START_BIT))
+
+#define AW88261_EF_VSN_GESLP_L_START_BIT       (0)
+#define AW88261_EF_VSN_GESLP_L_BITS_LEN        (10)
+#define AW88261_EF_VSN_GESLP_L_MASK            \
+       (~(((1<<AW88261_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88261_EF_VSN_GESLP_L_START_BIT))
+
+#define AW88261_FORCE_PWM_START_BIT            (12)
+#define AW88261_FORCE_PWM_BITS_LEN             (1)
+#define AW88261_FORCE_PWM_MASK                 \
+       (~(((1<<AW88261_FORCE_PWM_BITS_LEN)-1) << AW88261_FORCE_PWM_START_BIT))
+
+#define AW88261_FORCE_PWM_FORCEMINUS_PWM       (1)
+#define AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE \
+       (AW88261_FORCE_PWM_FORCEMINUS_PWM << AW88261_FORCE_PWM_START_BIT)
+
+#define AW88261_BST_OS_WIDTH_START_BIT         (0)
+#define AW88261_BST_OS_WIDTH_BITS_LEN          (3)
+#define AW88261_BST_OS_WIDTH_MASK              \
+       (~(((1<<AW88261_BST_OS_WIDTH_BITS_LEN)-1) << AW88261_BST_OS_WIDTH_START_BIT))
+
+#define AW88261_BST_OS_WIDTH_50NS              (4)
+#define AW88261_BST_OS_WIDTH_50NS_VALUE        \
+       (AW88261_BST_OS_WIDTH_50NS << AW88261_BST_OS_WIDTH_START_BIT)
+
+/* BST_LOOPR bit 1:0 (BSTCTRL6 0x65) */
+#define AW88261_BST_LOOPR_START_BIT    (0)
+#define AW88261_BST_LOOPR_BITS_LEN     (2)
+#define AW88261_BST_LOOPR_MASK         \
+       (~(((1<<AW88261_BST_LOOPR_BITS_LEN)-1) << AW88261_BST_LOOPR_START_BIT))
+
+#define AW88261_BST_LOOPR_340K         (2)
+#define AW88261_BST_LOOPR_340K_VALUE   \
+       (AW88261_BST_LOOPR_340K << AW88261_BST_LOOPR_START_BIT)
+
+/* RSQN_DLY bit 15:14 (BSTCTRL7 0x66) */
+#define AW88261_RSQN_DLY_START_BIT     (14)
+#define AW88261_RSQN_DLY_BITS_LEN      (2)
+#define AW88261_RSQN_DLY_MASK          \
+       (~(((1<<AW88261_RSQN_DLY_BITS_LEN)-1) << AW88261_RSQN_DLY_START_BIT))
+
+#define AW88261_RSQN_DLY_35NS          (2)
+#define AW88261_RSQN_DLY_35NS_VALUE    \
+       (AW88261_RSQN_DLY_35NS << AW88261_RSQN_DLY_START_BIT)
+
+/* BURST_SSMODE bit 3 (BSTCTRL8 0x67) */
+#define AW88261_BURST_SSMODE_START_BIT (3)
+#define AW88261_BURST_SSMODE_BITS_LEN  (1)
+#define AW88261_BURST_SSMODE_MASK      \
+       (~(((1<<AW88261_BURST_SSMODE_BITS_LEN)-1) << AW88261_BURST_SSMODE_START_BIT))
+
+#define AW88261_BURST_SSMODE_FAST      (0)
+#define AW88261_BURST_SSMODE_FAST_VALUE        \
+       (AW88261_BURST_SSMODE_FAST << AW88261_BURST_SSMODE_START_BIT)
+
+/* BST_BURST bit 9:7 (BSTCTRL9 0x68) */
+#define AW88261_BST_BURST_START_BIT    (7)
+#define AW88261_BST_BURST_BITS_LEN     (3)
+#define AW88261_BST_BURST_MASK         \
+       (~(((1<<AW88261_BST_BURST_BITS_LEN)-1) << AW88261_BST_BURST_START_BIT))
+
+#define AW88261_BST_BURST_30MA         (2)
+#define AW88261_BST_BURST_30MA_VALUE   \
+       (AW88261_BST_BURST_30MA << AW88261_BST_BURST_START_BIT)
+
+#define AW88261_EF_VSN_GESLP_SIGN_MASK         (~0x0200)
+#define AW88261_EF_VSN_GESLP_NEG               (~0xfc00)
+
+#define AW88261_EF_ISN_GESLP_SIGN_MASK         (~0x0200)
+#define AW88261_EF_ISN_GESLP_NEG               (~0xfc00)
+
+#define AW88261_EF_ISN_GESLP_H_START_BIT       (0)
+#define AW88261_EF_ISN_GESLP_H_BITS_LEN        (10)
+#define AW88261_EF_ISN_GESLP_H_MASK            \
+       (~(((1<<AW88261_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_H_START_BIT))
+
+#define AW88261_EF_ISN_GESLP_L_START_BIT       (0)
+#define AW88261_EF_ISN_GESLP_L_BITS_LEN        (10)
+#define AW88261_EF_ISN_GESLP_L_MASK            \
+       (~(((1<<AW88261_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88261_EF_ISN_GESLP_L_START_BIT))
+
+#define AW88261_CABL_BASE_VALUE                (1000)
+#define AW88261_ICABLK_FACTOR          (1)
+#define AW88261_VCABLK_FACTOR          (1)
+
+#define AW88261_VCAL_FACTOR            (1<<13)
+
+#define AW88261_START_RETRIES          (5)
+#define AW88261_START_WORK_DELAY_MS    (0)
+
+#define AW88261_I2C_NAME               "aw88261_smartpa"
+
+#define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \
+                       SNDRV_PCM_RATE_96000)
+#define AW88261_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | \
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+#define FADE_TIME_MAX                  100000
+#define FADE_TIME_MIN                  0
+
+#define AW88261_DEV_DEFAULT_CH         (0)
+#define AW88261_ACF_FILE               "aw88261_acf.bin"
+#define AW88261_DEV_SYSST_CHECK_MAX    (10)
+#define AW88261_SOFT_RESET_VALUE       (0x55aa)
+#define AW88261_REG_TO_DB              (0x3f)
+#define AW88261_VOL_START_MASK         (0xfc00)
+#define AW88261_INIT_PROFILE           (0)
+
+#define REG_VAL_TO_DB(value)           ((((value) >> AW88261_VOL_6DB_START) * \
+                                       AW88261_VOLUME_STEP_DB) + \
+                                       ((value) & AW88261_REG_TO_DB))
+#define DB_TO_REG_VAL(value)           ((((value) / AW88261_VOLUME_STEP_DB) << \
+                                       AW88261_VOL_6DB_START) + \
+                                       ((value) % AW88261_VOLUME_STEP_DB))
+
+#define AW88261_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .info = profile_info, \
+       .get = profile_get, \
+       .put = profile_set, \
+}
+
+enum {
+       AW88261_SYNC_START = 0,
+       AW88261_ASYNC_START,
+};
+
+enum aw88261_id {
+       AW88261_CHIP_ID = 0x2113,
+};
+
+enum {
+       AW88261_500_US = 500,
+       AW88261_1000_US = 1000,
+       AW88261_2000_US = 2000,
+};
+
+enum {
+       AW88261_DEV_PW_OFF = 0,
+       AW88261_DEV_PW_ON,
+};
+
+enum {
+       AW88261_DEV_FW_FAILED = 0,
+       AW88261_DEV_FW_OK,
+};
+
+enum {
+       AW88261_EF_AND_CHECK = 0,
+       AW88261_EF_OR_CHECK,
+};
+
+enum {
+       AW88261_FRCSET_DISABLE = 0,
+       AW88261_FRCSET_ENABLE,
+};
+
+struct aw88261 {
+       struct aw_device *aw_pa;
+       struct mutex lock;
+       struct gpio_desc *reset_gpio;
+       struct delayed_work start_work;
+       struct regmap *regmap;
+       struct aw_container *aw_cfg;
+
+       int efuse_check;
+       int frcset_en;
+       unsigned int mute_st;
+       unsigned int amppd_st;
+
+       unsigned char phase_sync;
+};
+
+#endif
index 05bcf49da85749ec9fd55f3226b5694910a230fc..8ee1baa0326911d2ae39a5fa047e73a5e7aa7212 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include "aw88395_lib.h"
 #include "aw88395_device.h"
+#include "aw88395_reg.h"
 
 #define AW88395_CRC8_POLYNOMIAL 0x8C
 DECLARE_CRC8_TABLE(aw_crc8_table);
@@ -429,6 +430,53 @@ parse_bin_failed:
        return ret;
 }
 
+static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev,
+                       uint8_t *data, uint32_t data_len, struct aw_prof_desc *prof_desc)
+{
+       struct aw_bin *aw_bin;
+       int ret;
+
+       aw_bin = devm_kzalloc(aw_dev->dev, data_len + sizeof(*aw_bin), GFP_KERNEL);
+       if (!aw_bin)
+               return -ENOMEM;
+
+       aw_bin->info.len = data_len;
+       memcpy(aw_bin->info.data, data, data_len);
+
+       ret = aw_parsing_bin_file(aw_dev, aw_bin);
+       if (ret < 0) {
+               dev_err(aw_dev->dev, "parse bin failed");
+               goto parse_bin_failed;
+       }
+
+       if ((aw_bin->all_bin_parse_num != 1) ||
+               (aw_bin->header_info[0].bin_data_type != DATA_TYPE_REGISTER)) {
+               dev_err(aw_dev->dev, "bin num or type error");
+               goto parse_bin_failed;
+       }
+
+       if (aw_bin->header_info[0].valid_data_len % 4) {
+               dev_err(aw_dev->dev, "bin data len get error!");
+               goto parse_bin_failed;
+       }
+
+       prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data =
+                               data + aw_bin->header_info[0].valid_data_addr;
+       prof_desc->sec_desc[AW88395_DATA_TYPE_REG].len =
+                               aw_bin->header_info[0].valid_data_len;
+       prof_desc->prof_st = AW88395_PROFILE_OK;
+
+       devm_kfree(aw_dev->dev, aw_bin);
+       aw_bin = NULL;
+
+       return 0;
+
+parse_bin_failed:
+       devm_kfree(aw_dev->dev, aw_bin);
+       aw_bin = NULL;
+       return ret;
+}
+
 static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg_hdr *cfg_hdr,
                        struct aw_cfg_dde *cfg_dde, struct aw_prof_desc *scene_prof_desc)
 {
@@ -447,6 +495,9 @@ static int aw_dev_parse_data_by_sec_type(struct aw_device *aw_dev, struct aw_cfg
                return aw_dev_prof_parse_multi_bin(
                                aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,
                                cfg_dde->data_size, scene_prof_desc);
+       case ACF_SEC_TYPE_HDR_REG:
+               return aw_dev_parse_reg_bin_with_hdr(aw_dev, (u8 *)cfg_hdr + cfg_dde->data_offset,
+                               cfg_dde->data_size, scene_prof_desc);
        default:
                dev_err(aw_dev->dev, "%s cfg_dde->data_type = %d\n", __func__, cfg_dde->data_type);
                break;
@@ -527,7 +578,49 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev,
        return 0;
 }
 
-static int aw_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
+static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
+                               struct aw_all_prof_info all_prof_info)
+{
+       struct aw_prof_desc *prof_desc = all_prof_info.prof_desc;
+       struct aw_prof_info *prof_info = &aw_dev->prof_info;
+       int num = 0;
+       int i;
+
+       for (i = 0; i < AW88395_PROFILE_MAX; i++) {
+               if (prof_desc[i].prof_st == AW88395_PROFILE_OK)
+                       prof_info->count++;
+       }
+
+       dev_dbg(aw_dev->dev, "get valid profile:%d", aw_dev->prof_info.count);
+
+       if (!prof_info->count) {
+               dev_err(aw_dev->dev, "no profile data");
+               return -EPERM;
+       }
+
+       prof_info->prof_desc = devm_kcalloc(aw_dev->dev,
+                                       prof_info->count, sizeof(struct aw_prof_desc),
+                                       GFP_KERNEL);
+       if (!prof_info->prof_desc)
+               return -ENOMEM;
+
+       for (i = 0; i < AW88395_PROFILE_MAX; i++) {
+               if (prof_desc[i].prof_st == AW88395_PROFILE_OK) {
+                       if (num >= prof_info->count) {
+                               dev_err(aw_dev->dev, "overflow count[%d]",
+                                               prof_info->count);
+                               return -EINVAL;
+                       }
+                       prof_info->prof_desc[num] = prof_desc[i];
+                       prof_info->prof_desc[num].id = i;
+                       num++;
+               }
+       }
+
+       return 0;
+}
+
+static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev,
                                struct aw_all_prof_info all_prof_info)
 {
        struct aw_prof_desc *prof_desc = all_prof_info.prof_desc;
@@ -606,9 +699,22 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
                        goto exit;
        }
 
-       ret = aw_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
-       if (ret < 0)
-               goto exit;
+       switch (aw_dev->chip_id) {
+       case AW88395_CHIP_ID:
+               ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
+               if (ret < 0)
+                       goto exit;
+               break;
+       case AW88261_CHIP_ID:
+               ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info);
+               if (ret < 0)
+                       goto exit;
+               break;
+       default:
+               dev_err(aw_dev->dev, "valid prof unsupported");
+               ret = -EINVAL;
+               break;
+       }
 
        aw_dev->prof_info.prof_name_list = profile_name;
 
@@ -679,16 +785,37 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain
        struct aw_cfg_dde_v1 *cfg_dde =
                (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);
        unsigned int i;
+       int ret;
 
-       for (i = 0; i < cfg_hdr->ddt_num; ++i) {
-               if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
-                   (aw_dev->chip_id == cfg_dde[i].chip_id) &&
-                   (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
-                   (aw_dev->i2c->addr == cfg_dde[i].dev_addr))
-                       (*scene_num)++;
+       switch (aw_dev->chip_id) {
+       case AW88395_CHIP_ID:
+               for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+                       if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
+                           (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+                           (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
+                           (aw_dev->i2c->addr == cfg_dde[i].dev_addr))
+                               (*scene_num)++;
+               }
+               ret = 0;
+               break;
+       case AW88261_CHIP_ID:
+               for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+                       if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||
+                            (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&
+                           (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+                           (aw_dev->i2c->adapter->nr == cfg_dde[i].dev_bus) &&
+                           (aw_dev->i2c->addr == cfg_dde[i].dev_addr))
+                               (*scene_num)++;
+               }
+               ret = 0;
+               break;
+       default:
+               dev_err(aw_dev->dev, "unsupported device");
+               ret = -EINVAL;
+               break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int aw_get_default_scene_count_v1(struct aw_device *aw_dev,
@@ -699,15 +826,35 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev,
        struct aw_cfg_dde_v1 *cfg_dde =
                (struct aw_cfg_dde_v1 *)(aw_cfg->data + cfg_hdr->hdr_offset);
        unsigned int i;
+       int ret;
 
-       for (i = 0; i < cfg_hdr->ddt_num; ++i) {
-               if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
-                   (aw_dev->chip_id == cfg_dde[i].chip_id) &&
-                   (aw_dev->channel == cfg_dde[i].dev_index))
-                       (*scene_num)++;
+       switch (aw_dev->chip_id) {
+       case AW88395_CHIP_ID:
+               for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+                       if ((cfg_dde[i].data_type == ACF_SEC_TYPE_MULTIPLE_BIN) &&
+                           (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+                           (aw_dev->channel == cfg_dde[i].dev_index))
+                               (*scene_num)++;
+               }
+               ret = 0;
+               break;
+       case AW88261_CHIP_ID:
+               for (i = 0; i < cfg_hdr->ddt_num; ++i) {
+                       if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) ||
+                            (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&
+                           (aw_dev->chip_id == cfg_dde[i].chip_id) &&
+                           (aw_dev->channel == cfg_dde[i].dev_index))
+                               (*scene_num)++;
+               }
+               ret = 0;
+               break;
+       default:
+               dev_err(aw_dev->dev, "unsupported device");
+               ret = -EINVAL;
+               break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int aw_dev_parse_scene_count_v1(struct aw_device *aw_dev,
@@ -756,6 +903,18 @@ static int aw_dev_parse_data_by_sec_type_v1(struct aw_device *aw_dev,
                prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;
                (*cur_scene_id)++;
                break;
+       case ACF_SEC_TYPE_HDR_REG:
+               ret =  aw_dev_parse_reg_bin_with_hdr(aw_dev,
+                               (uint8_t *)prof_hdr + cfg_dde->data_offset,
+                               cfg_dde->data_size, &prof_info->prof_desc[*cur_scene_id]);
+               if (ret < 0) {
+                       dev_err(aw_dev->dev, "parse reg bin with hdr failed");
+                       return ret;
+               }
+               prof_info->prof_desc[*cur_scene_id].prf_str = cfg_dde->dev_profile_str;
+               prof_info->prof_desc[*cur_scene_id].id = cfg_dde->dev_profile;
+               (*cur_scene_id)++;
+               break;
        default:
                dev_err(aw_dev->dev, "unsupported SEC_TYPE [%d]", cfg_dde->data_type);
                return -EINVAL;
index e64f24e971508fdf7cedf80f1ba10cf182453040..e7a7c02efaf3359ba9c4dab82195705ce6a12e8d 100644 (file)
@@ -96,6 +96,7 @@
 
 enum aw88395_id {
        AW88395_CHIP_ID = 0x2049,
+       AW88261_CHIP_ID = 0x2113,
 };
 
 #define AW88395_REG_MAX                (0x7D)
index 04ba7f25012e0cb4a87e171e1d2905ea61422d33..20084c7d3acbe2b417aad84078d96e1e104d64f8 100644 (file)
@@ -1312,7 +1312,7 @@ static struct regmap_config cs35l36_regmap = {
        .precious_reg = cs35l36_precious_reg,
        .volatile_reg = cs35l36_volatile_reg,
        .readable_reg = cs35l36_readable_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static irqreturn_t cs35l36_irq(int irq, void *data)
index 1e4205295a0de56c5c6c038e225e0179dcdf3bba..ac7cc492bcb054056de5eadf358fc58346768463 100644 (file)
@@ -743,7 +743,7 @@ struct regmap_config cs35l41_regmap_i2c = {
        .volatile_reg = cs35l41_volatile_reg,
        .readable_reg = cs35l41_readable_reg,
        .precious_reg = cs35l41_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c);
 
@@ -760,7 +760,7 @@ struct regmap_config cs35l41_regmap_spi = {
        .volatile_reg = cs35l41_volatile_reg,
        .readable_reg = cs35l41_readable_reg,
        .precious_reg = cs35l41_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(cs35l41_regmap_spi);
 
index 066f83c0c7ac29211255efceb72c9d74309a9b44..621af1785979b10da8f5f77ffc89658e4811cefd 100644 (file)
@@ -255,7 +255,7 @@ const struct regmap_config cs35l45_i2c_regmap = {
        .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults),
        .volatile_reg = cs35l45_volatile_reg,
        .readable_reg = cs35l45_readable_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45);
 
@@ -271,7 +271,7 @@ const struct regmap_config cs35l45_spi_regmap = {
        .num_reg_defaults = ARRAY_SIZE(cs35l45_defaults),
        .volatile_reg = cs35l45_volatile_reg,
        .readable_reg = cs35l45_readable_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45);
 
index ed2a41943d9783a1a7d1df964322abe11a21ad9f..9f4f2f4f23f5668c846f2a051eee64c533deb38f 100644 (file)
@@ -26,14 +26,14 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
        if (!cs35l56)
                return -ENOMEM;
 
-       cs35l56->dev = dev;
-       cs35l56->can_hibernate = true;
+       cs35l56->base.dev = dev;
+       cs35l56->base.can_hibernate = true;
 
        i2c_set_clientdata(client, cs35l56);
-       cs35l56->regmap = devm_regmap_init_i2c(client, regmap_config);
-       if (IS_ERR(cs35l56->regmap)) {
-               ret = PTR_ERR(cs35l56->regmap);
-               return dev_err_probe(cs35l56->dev, ret, "Failed to allocate register map\n");
+       cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
+               return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n");
        }
 
        ret = cs35l56_common_probe(cs35l56);
@@ -42,7 +42,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
 
        ret = cs35l56_init(cs35l56);
        if (ret == 0)
-               ret = cs35l56_irq_request(cs35l56, client->irq);
+               ret = cs35l56_irq_request(&cs35l56->base, client->irq);
        if (ret < 0)
                cs35l56_remove(cs35l56);
 
@@ -62,10 +62,19 @@ static const struct i2c_device_id cs35l56_id_i2c[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
+       { "CSC355C", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);
+#endif
+
 static struct i2c_driver cs35l56_i2c_driver = {
        .driver = {
                .name           = "cs35l56",
                .pm = &cs35l56_pm_ops_i2c_spi,
+               .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match),
        },
        .id_table       = cs35l56_id_i2c,
        .probe          = cs35l56_i2c_probe,
index 2cde78605ba95e979c238d4bfe760ca356a16329..b433266b784467f4e71416c5cba9bb85683ddc10 100644 (file)
@@ -166,13 +166,13 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
        struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
        int ret;
 
-       pm_runtime_get_noresume(cs35l56->dev);
+       pm_runtime_get_noresume(cs35l56->base.dev);
 
-       regcache_cache_only(cs35l56->regmap, false);
+       regcache_cache_only(cs35l56->base.regmap, false);
 
        ret = cs35l56_init(cs35l56);
        if (ret < 0) {
-               regcache_cache_only(cs35l56->regmap, true);
+               regcache_cache_only(cs35l56->base.regmap, true);
                goto out;
        }
 
@@ -180,15 +180,15 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
         * cs35l56_init can return with !init_done if it triggered
         * a soft reset.
         */
-       if (cs35l56->init_done) {
+       if (cs35l56->base.init_done) {
                /* Enable SoundWire interrupts */
                sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1,
                                CS35L56_SDW_INT_MASK_CODEC_IRQ);
        }
 
 out:
-       pm_runtime_mark_last_busy(cs35l56->dev);
-       pm_runtime_put_autosuspend(cs35l56->dev);
+       pm_runtime_mark_last_busy(cs35l56->base.dev);
+       pm_runtime_put_autosuspend(cs35l56->base.dev);
 }
 
 static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
@@ -198,7 +198,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
 
        /* SoundWire core holds our pm_runtime when calling this function. */
 
-       dev_dbg(cs35l56->dev, "int control_port=%#x\n", status->control_port);
+       dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port);
 
        if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0)
                return 0;
@@ -207,7 +207,7 @@ static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
         * Prevent bus manager suspending and possibly issuing a
         * bus-reset before the queued work has run.
         */
-       pm_runtime_get_noresume(cs35l56->dev);
+       pm_runtime_get_noresume(cs35l56->base.dev);
 
        /*
         * Mask and clear until it has been handled. The read of GEN_INT_STAT_1
@@ -230,14 +230,14 @@ static void cs35l56_sdw_irq_work(struct work_struct *work)
                                                       struct cs35l56_private,
                                                       sdw_irq_work);
 
-       cs35l56_irq(-1, cs35l56);
+       cs35l56_irq(-1, &cs35l56->base);
 
        /* unmask interrupts */
        if (!cs35l56->sdw_irq_no_unmask)
                sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1,
                                CS35L56_SDW_INT_MASK_CODEC_IRQ);
 
-       pm_runtime_put_autosuspend(cs35l56->dev);
+       pm_runtime_put_autosuspend(cs35l56->base.dev);
 }
 
 static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
@@ -246,7 +246,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
        struct sdw_slave_prop *prop = &peripheral->prop;
        struct sdw_dpn_prop *ports;
 
-       ports = devm_kcalloc(cs35l56->dev, 2, sizeof(*ports), GFP_KERNEL);
+       ports = devm_kcalloc(cs35l56->base.dev, 2, sizeof(*ports), GFP_KERNEL);
        if (!ports)
                return -ENOMEM;
 
@@ -279,17 +279,17 @@ static int cs35l56_sdw_update_status(struct sdw_slave *peripheral,
 
        switch (status) {
        case SDW_SLAVE_ATTACHED:
-               dev_dbg(cs35l56->dev, "%s: ATTACHED\n", __func__);
+               dev_dbg(cs35l56->base.dev, "%s: ATTACHED\n", __func__);
                if (cs35l56->sdw_attached)
                        break;
 
-               if (!cs35l56->init_done || cs35l56->soft_resetting)
+               if (!cs35l56->base.init_done || cs35l56->soft_resetting)
                        cs35l56_sdw_init(peripheral);
 
                cs35l56->sdw_attached = true;
                break;
        case SDW_SLAVE_UNATTACHED:
-               dev_dbg(cs35l56->dev, "%s: UNATTACHED\n", __func__);
+               dev_dbg(cs35l56->base.dev, "%s: UNATTACHED\n", __func__);
                cs35l56->sdw_attached = false;
                break;
        default:
@@ -305,7 +305,7 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
        unsigned int curr_scale_reg, next_scale_reg;
        int curr_scale, next_scale, ret;
 
-       if (!cs35l56->init_done)
+       if (!cs35l56->base.init_done)
                return 0;
 
        if (peripheral->bus->params.curr_bank) {
@@ -324,13 +324,13 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
         */
        curr_scale = sdw_read_no_pm(peripheral, curr_scale_reg);
        if (curr_scale < 0) {
-               dev_err(cs35l56->dev, "Failed to read current clock scale: %d\n", curr_scale);
+               dev_err(cs35l56->base.dev, "Failed to read current clock scale: %d\n", curr_scale);
                return curr_scale;
        }
 
        next_scale = sdw_read_no_pm(peripheral, next_scale_reg);
        if (next_scale < 0) {
-               dev_err(cs35l56->dev, "Failed to read next clock scale: %d\n", next_scale);
+               dev_err(cs35l56->base.dev, "Failed to read next clock scale: %d\n", next_scale);
                return next_scale;
        }
 
@@ -338,7 +338,8 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
                next_scale = cs35l56->old_sdw_clock_scale;
                ret = sdw_write_no_pm(peripheral, next_scale_reg, next_scale);
                if (ret < 0) {
-                       dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret);
+                       dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n",
+                               ret);
                        return ret;
                }
        }
@@ -346,11 +347,11 @@ static int cs35l56_a1_kick_divider(struct cs35l56_private *cs35l56,
        cs35l56->old_sdw_clock_scale = curr_scale;
        ret = sdw_write_no_pm(peripheral, curr_scale_reg, CS35L56_SDW_INVALID_BUS_SCALE);
        if (ret < 0) {
-               dev_err(cs35l56->dev, "Failed to modify current clock scale: %d\n", ret);
+               dev_err(cs35l56->base.dev, "Failed to modify current clock scale: %d\n", ret);
                return ret;
        }
 
-       dev_dbg(cs35l56->dev, "Next bus scale: %#x\n", next_scale);
+       dev_dbg(cs35l56->base.dev, "Next bus scale: %#x\n", next_scale);
 
        return 0;
 }
@@ -362,9 +363,10 @@ static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral,
        int sclk;
 
        sclk = params->curr_dr_freq / 2;
-       dev_dbg(cs35l56->dev, "%s: sclk=%u c=%u r=%u\n", __func__, sclk, params->col, params->row);
+       dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n",
+               __func__, sclk, params->col, params->row);
 
-       if (cs35l56->rev < 0xb0)
+       if (cs35l56->base.rev < 0xb0)
                return cs35l56_a1_kick_divider(cs35l56, peripheral);
 
        return 0;
@@ -376,7 +378,7 @@ static int __maybe_unused cs35l56_sdw_clk_stop(struct sdw_slave *peripheral,
 {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
 
-       dev_dbg(cs35l56->dev, "%s: mode:%d type:%d\n", __func__, mode, type);
+       dev_dbg(cs35l56->base.dev, "%s: mode:%d type:%d\n", __func__, mode, type);
 
        return 0;
 }
@@ -397,10 +399,10 @@ static int __maybe_unused cs35l56_sdw_handle_unattach(struct cs35l56_private *cs
 
        if (peripheral->unattach_request) {
                /* Cannot access registers until bus is re-initialized. */
-               dev_dbg(cs35l56->dev, "Wait for initialization_complete\n");
+               dev_dbg(cs35l56->base.dev, "Wait for initialization_complete\n");
                if (!wait_for_completion_timeout(&peripheral->initialization_complete,
                                                 msecs_to_jiffies(5000))) {
-                       dev_err(cs35l56->dev, "initialization_complete timed out\n");
+                       dev_err(cs35l56->base.dev, "initialization_complete timed out\n");
                        return -ETIMEDOUT;
                }
 
@@ -419,10 +421,10 @@ static int __maybe_unused cs35l56_sdw_runtime_suspend(struct device *dev)
 {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
 
-       if (!cs35l56->init_done)
+       if (!cs35l56->base.init_done)
                return 0;
 
-       return cs35l56_runtime_suspend(dev);
+       return cs35l56_runtime_suspend_common(&cs35l56->base);
 }
 
 static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
@@ -432,14 +434,14 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
 
        dev_dbg(dev, "Runtime resume\n");
 
-       if (!cs35l56->init_done)
+       if (!cs35l56->base.init_done)
                return 0;
 
        ret = cs35l56_sdw_handle_unattach(cs35l56);
        if (ret < 0)
                return ret;
 
-       ret = cs35l56_runtime_resume_common(cs35l56);
+       ret = cs35l56_runtime_resume_common(&cs35l56->base, true);
        if (ret)
                return ret;
 
@@ -454,7 +456,7 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
 {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
 
-       if (!cs35l56->init_done)
+       if (!cs35l56->base.init_done)
                return 0;
 
        /*
@@ -493,21 +495,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
        if (!cs35l56)
                return -ENOMEM;
 
-       cs35l56->dev = dev;
+       cs35l56->base.dev = dev;
        cs35l56->sdw_peripheral = peripheral;
        INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work);
 
        dev_set_drvdata(dev, cs35l56);
 
-       cs35l56->regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw,
+       cs35l56->base.regmap = devm_regmap_init(dev, &cs35l56_regmap_bus_sdw,
                                           peripheral, &cs35l56_regmap_sdw);
-       if (IS_ERR(cs35l56->regmap)) {
-               ret = PTR_ERR(cs35l56->regmap);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
                return dev_err_probe(dev, ret, "Failed to allocate register map\n");
        }
 
        /* Start in cache-only until device is enumerated */
-       regcache_cache_only(cs35l56->regmap, true);
+       regcache_cache_only(cs35l56->base.regmap, true);
 
        ret = cs35l56_common_probe(cs35l56);
        if (ret != 0)
index 60da8c75b7b9e519060965a551479e21cc306efd..ae373f335ea8dbdf5c2c321b96def7dfb0f0e7b0 100644 (file)
 
 #include "cs35l56.h"
 
+static const struct reg_sequence cs35l56_patch[] = {
+       /* These are not reset by a soft-reset, so patch to defaults. */
+       { CS35L56_MAIN_RENDER_USER_MUTE,        0x00000000 },
+       { CS35L56_MAIN_RENDER_USER_VOLUME,      0x00000000 },
+       { CS35L56_MAIN_POSTURE_NUMBER,          0x00000000 },
+};
+
+int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
+{
+       return regmap_register_patch(cs35l56_base->regmap, cs35l56_patch,
+                                    ARRAY_SIZE(cs35l56_patch));
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
+
 static const struct reg_default cs35l56_reg_defaults[] = {
        { CS35L56_ASP1_ENABLES1,                0x00000000 },
        { CS35L56_ASP1_CONTROL1,                0x00000028 },
@@ -35,9 +49,9 @@ static const struct reg_default cs35l56_reg_defaults[] = {
        { CS35L56_IRQ1_MASK_8,                  0xfc000fff },
        { CS35L56_IRQ1_MASK_18,                 0x1f7df0ff },
        { CS35L56_IRQ1_MASK_20,                 0x15c00000 },
-       /* CS35L56_MAIN_RENDER_USER_MUTE - soft register, no default    */
-       /* CS35L56_MAIN_RENDER_USER_VOLUME - soft register, no default  */
-       /* CS35L56_MAIN_POSTURE_NUMBER - soft register, no default      */
+       { CS35L56_MAIN_RENDER_USER_MUTE,        0x00000000 },
+       { CS35L56_MAIN_RENDER_USER_VOLUME,      0x00000000 },
+       { CS35L56_MAIN_POSTURE_NUMBER,          0x00000000 },
 };
 
 static bool cs35l56_is_dsp_memory(unsigned int reg)
@@ -181,33 +195,463 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
        }
 }
 
-static const u32 cs35l56_firmware_registers[] = {
-       CS35L56_MAIN_RENDER_USER_MUTE,
-       CS35L56_MAIN_RENDER_USER_VOLUME,
-       CS35L56_MAIN_POSTURE_NUMBER,
+int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command)
+{
+       unsigned int val;
+       int ret;
+
+       regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
+       ret = regmap_read_poll_timeout(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+                                      val, (val == 0),
+                                      CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
+       if (ret) {
+               dev_warn(cs35l56_base->dev, "MBOX command %#x failed: %d\n", command, ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base)
+{
+       int ret;
+       unsigned int reg;
+       unsigned int val;
+
+       ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_SHUTDOWN);
+       if (ret)
+               return ret;
+
+       if (cs35l56_base->rev < CS35L56_REVID_B0)
+               reg = CS35L56_DSP1_PM_CUR_STATE_A1;
+       else
+               reg = CS35L56_DSP1_PM_CUR_STATE;
+
+       ret = regmap_read_poll_timeout(cs35l56_base->regmap,  reg,
+                                      val, (val == CS35L56_HALO_STATE_SHUTDOWN),
+                                      CS35L56_HALO_STATE_POLL_US,
+                                      CS35L56_HALO_STATE_TIMEOUT_US);
+       if (ret < 0)
+               dev_err(cs35l56_base->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
+                       val, ret);
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
+{
+       unsigned int reg;
+       unsigned int val;
+       int ret;
+
+       if (cs35l56_base->rev < CS35L56_REVID_B0)
+               reg = CS35L56_DSP1_HALO_STATE_A1;
+       else
+               reg = CS35L56_DSP1_HALO_STATE;
+
+       ret = regmap_read_poll_timeout(cs35l56_base->regmap, reg,
+                                      val,
+                                      (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
+                                      CS35L56_HALO_STATE_POLL_US,
+                                      CS35L56_HALO_STATE_TIMEOUT_US);
+
+       if ((ret < 0) && (ret != -ETIMEDOUT)) {
+               dev_err(cs35l56_base->dev, "Failed to read HALO_STATE: %d\n", ret);
+               return ret;
+       }
+
+       if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
+               dev_err(cs35l56_base->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
+               return -EIO;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED);
+
+void cs35l56_wait_control_port_ready(void)
+{
+       /* Wait for control port to be ready (datasheet tIRS). */
+       usleep_range(CS35L56_CONTROL_PORT_READY_US, 2 * CS35L56_CONTROL_PORT_READY_US);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, SND_SOC_CS35L56_SHARED);
+
+void cs35l56_wait_min_reset_pulse(void)
+{
+       /* Satisfy minimum reset pulse width spec */
+       usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED);
+
+static const struct reg_sequence cs35l56_system_reset_seq[] = {
+       REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
 };
 
-void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap)
+void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
+{
+       /*
+        * Must enter cache-only first so there can't be any more register
+        * accesses other than the controlled system reset sequence below.
+        */
+       regcache_cache_only(cs35l56_base->regmap, true);
+       regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+                                       cs35l56_system_reset_seq,
+                                       ARRAY_SIZE(cs35l56_system_reset_seq));
+
+       /* On SoundWire the registers won't be accessible until it re-enumerates. */
+       if (is_soundwire)
+               return;
+
+       cs35l56_wait_control_port_ready();
+       regcache_cache_only(cs35l56_base->regmap, false);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
+{
+       int ret;
+
+       if (!irq)
+               return 0;
+
+       ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
+                                       IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+                                       "cs35l56", cs35l56_base);
+       if (!ret)
+               cs35l56_base->irq = irq;
+       else
+               dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED);
+
+irqreturn_t cs35l56_irq(int irq, void *data)
+{
+       struct cs35l56_base *cs35l56_base = data;
+       unsigned int status1 = 0, status8 = 0, status20 = 0;
+       unsigned int mask1, mask8, mask20;
+       unsigned int val;
+       int rv;
+
+       irqreturn_t ret = IRQ_NONE;
+
+       if (!cs35l56_base->init_done)
+               return IRQ_NONE;
+
+       mutex_lock(&cs35l56_base->irq_lock);
+
+       rv = pm_runtime_resume_and_get(cs35l56_base->dev);
+       if (rv < 0) {
+               dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
+               goto err_unlock;
+       }
+
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
+       if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
+               dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
+               goto err;
+       }
+
+       /* Ack interrupts */
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, &status1);
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1, &mask1);
+       status1 &= ~mask1;
+       regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_1, status1);
+
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, &status8);
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8, &mask8);
+       status8 &= ~mask8;
+       regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_8, status8);
+
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_20, &status20);
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, &mask20);
+       status20 &= ~mask20;
+       /* We don't want EINT20 but they default to unmasked: force mask */
+       regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+
+       dev_dbg(cs35l56_base->dev, "%s: %#x %#x\n", __func__, status1, status8);
+
+       /* Check to see if unmasked bits are active */
+       if (!status1 && !status8 && !status20)
+               goto err;
+
+       if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
+               dev_crit(cs35l56_base->dev, "Amp short error\n");
+
+       if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
+               dev_crit(cs35l56_base->dev, "Overtemp error\n");
+
+       ret = IRQ_HANDLED;
+
+err:
+       pm_runtime_put(cs35l56_base->dev);
+err_unlock:
+       mutex_unlock(&cs35l56_base->irq_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
+{
+       unsigned int val;
+       int ret;
+
+       /* Nothing to re-patch if we haven't done any patching yet. */
+       if (!cs35l56_base->fw_patched)
+               return false;
+
+       /*
+        * If we have control of RESET we will have asserted it so the firmware
+        * will need re-patching.
+        */
+       if (cs35l56_base->reset_gpio)
+               return true;
+
+       /*
+        * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
+        * can't be used here to test for memory retention.
+        * Assume that tuning must be re-loaded.
+        */
+       if (cs35l56_base->secured)
+               return true;
+
+       ret = pm_runtime_resume_and_get(cs35l56_base->dev);
+       if (ret) {
+               dev_err(cs35l56_base->dev, "Failed to runtime_get: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_PROTECTION_STATUS, &val);
+       if (ret)
+               dev_err(cs35l56_base->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+       else
+               ret = !!(val & CS35L56_FIRMWARE_MISSING);
+
+       pm_runtime_put_autosuspend(cs35l56_base->dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED);
+
+static const struct reg_sequence cs35l56_hibernate_seq[] = {
+       /* This must be the last register access */
+       REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW),
+};
+
+static const struct reg_sequence cs35l56_hibernate_wake_seq[] = {
+       REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP),
+};
+
+int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base)
 {
-       int i;
        unsigned int val;
+       int ret;
+
+       if (!cs35l56_base->init_done)
+               return 0;
 
-       for (i = 0; i < ARRAY_SIZE(cs35l56_firmware_registers); i++) {
-               regmap_read(regmap, cs35l56_firmware_registers[i], &val);
-               dev_dbg(dev, "%s: %d: %#x: %#x\n", __func__,
-                       i, cs35l56_firmware_registers[i], val);
+       /* Firmware must have entered a power-save state */
+       ret = regmap_read_poll_timeout(cs35l56_base->regmap,
+                                      CS35L56_TRANSDUCER_ACTUAL_PS,
+                                      val, (val >= CS35L56_PS3),
+                                      CS35L56_PS3_POLL_US,
+                                      CS35L56_PS3_TIMEOUT_US);
+       if (ret)
+               dev_warn(cs35l56_base->dev, "PS3 wait failed: %d\n", ret);
+
+       /* Clear BOOT_DONE so it can be used to detect a reboot */
+       regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
+
+       if (!cs35l56_base->can_hibernate) {
+               regcache_cache_only(cs35l56_base->regmap, true);
+               dev_dbg(cs35l56_base->dev, "Suspended: no hibernate");
+
+               return 0;
        }
+
+       /*
+        * Enable auto-hibernate. If it is woken by some other wake source
+        * it will automatically return to hibernate.
+        */
+       cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
+
+       /*
+        * Must enter cache-only first so there can't be any more register
+        * accesses other than the controlled hibernate sequence below.
+        */
+       regcache_cache_only(cs35l56_base->regmap, true);
+
+       regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+                                       cs35l56_hibernate_seq,
+                                       ARRAY_SIZE(cs35l56_hibernate_seq));
+
+       dev_dbg(cs35l56_base->dev, "Suspended: hibernate");
+
+       return 0;
 }
-EXPORT_SYMBOL_NS_GPL(cs35l56_reread_firmware_registers, SND_SOC_CS35L56_SHARED);
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire)
+{
+       unsigned int val;
+       int ret;
+
+       if (!cs35l56_base->init_done)
+               return 0;
+
+       if (!cs35l56_base->can_hibernate)
+               goto out_sync;
+
+       if (!is_soundwire) {
+               /*
+                * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C.
+                * Must be done before releasing cache-only.
+                */
+               regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
+                                               cs35l56_hibernate_wake_seq,
+                                               ARRAY_SIZE(cs35l56_hibernate_wake_seq));
 
-const struct cs_dsp_region cs35l56_dsp1_regions[] = {
+               cs35l56_wait_control_port_ready();
+       }
+
+out_sync:
+       regcache_cache_only(cs35l56_base->regmap, false);
+
+       ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
+       if (ret) {
+               dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret);
+               goto err;
+       }
+
+       ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+       if (ret)
+               goto err;
+
+       /* BOOT_DONE will be 1 if the amp reset */
+       regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_EINT_4, &val);
+       if (val & CS35L56_OTP_BOOT_DONE_MASK) {
+               dev_dbg(cs35l56_base->dev, "Registers reset in suspend\n");
+               regcache_mark_dirty(cs35l56_base->regmap);
+       }
+
+       regcache_sync(cs35l56_base->regmap);
+
+       dev_dbg(cs35l56_base->dev, "Resumed");
+
+       return 0;
+
+err:
+       regmap_write(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+                    CS35L56_MBOX_CMD_HIBERNATE_NOW);
+
+       regcache_cache_only(cs35l56_base->regmap, true);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED);
+
+static const struct cs_dsp_region cs35l56_dsp1_regions[] = {
        { .type = WMFW_HALO_PM_PACKED,  .base = CS35L56_DSP1_PMEM_0 },
        { .type = WMFW_HALO_XM_PACKED,  .base = CS35L56_DSP1_XMEM_PACKED_0 },
        { .type = WMFW_HALO_YM_PACKED,  .base = CS35L56_DSP1_YMEM_PACKED_0 },
        { .type = WMFW_ADSP2_XM,        .base = CS35L56_DSP1_XMEM_UNPACKED24_0 },
        { .type = WMFW_ADSP2_YM,        .base = CS35L56_DSP1_YMEM_UNPACKED24_0 },
 };
-EXPORT_SYMBOL_NS_GPL(cs35l56_dsp1_regions, SND_SOC_CS35L56_SHARED);
+
+void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp)
+{
+       cs_dsp->num = 1;
+       cs_dsp->type = WMFW_HALO;
+       cs_dsp->rev = 0;
+       cs_dsp->dev = cs35l56_base->dev;
+       cs_dsp->regmap = cs35l56_base->regmap;
+       cs_dsp->base = CS35L56_DSP1_CORE_BASE;
+       cs_dsp->base_sysinfo = CS35L56_DSP1_SYS_INFO_ID;
+       cs_dsp->mem = cs35l56_dsp1_regions;
+       cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions);
+       cs_dsp->no_core_startstop = true;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED);
+
+int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
+{
+       int ret;
+       unsigned int devid, revid, otpid, secured;
+
+       /*
+        * If the system is not using a reset_gpio then issue a
+        * dummy read to force a wakeup.
+        */
+       if (!cs35l56_base->reset_gpio)
+               regmap_read(cs35l56_base->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
+
+       cs35l56_wait_control_port_ready();
+
+       /*
+        * The HALO_STATE register is in different locations on Ax and B0
+        * devices so the REVID needs to be determined before waiting for the
+        * firmware to boot.
+        */
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_REVID, &revid);
+       if (ret < 0) {
+               dev_err(cs35l56_base->dev, "Get Revision ID failed\n");
+               return ret;
+       }
+       cs35l56_base->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
+
+       ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_DEVID, &devid);
+       if (ret < 0) {
+               dev_err(cs35l56_base->dev, "Get Device ID failed\n");
+               return ret;
+       }
+       devid &= CS35L56_DEVID_MASK;
+
+       switch (devid) {
+       case 0x35A56:
+               break;
+       default:
+               dev_err(cs35l56_base->dev, "Unknown device %x\n", devid);
+               return ret;
+       }
+
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
+       if (ret) {
+               dev_err(cs35l56_base->dev, "Get Secure status failed\n");
+               return ret;
+       }
+
+       /* When any bus is restricted treat the device as secured */
+       if (secured & CS35L56_RESTRICTED_MASK)
+               cs35l56_base->secured = true;
+
+       ret = regmap_read(cs35l56_base->regmap, CS35L56_OTPID, &otpid);
+       if (ret < 0) {
+               dev_err(cs35l56_base->dev, "Get OTP ID failed\n");
+               return ret;
+       }
+
+       dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
+                cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid);
+
+       /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
+       regmap_write(cs35l56_base->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
+       regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_1,
+                          CS35L56_AMP_SHORT_ERR_EINT1_MASK,
+                          0);
+       regmap_update_bits(cs35l56_base->regmap, CS35L56_IRQ1_MASK_8,
+                          CS35L56_TEMP_ERR_EINT1_MASK,
+                          0);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED);
 
 static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = {
        [0x0C] = 128000,
@@ -319,7 +763,7 @@ struct regmap_config cs35l56_regmap_i2c = {
        .volatile_reg = cs35l56_volatile_reg,
        .readable_reg = cs35l56_readable_reg,
        .precious_reg = cs35l56_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED);
 
@@ -336,7 +780,7 @@ struct regmap_config cs35l56_regmap_spi = {
        .volatile_reg = cs35l56_volatile_reg,
        .readable_reg = cs35l56_readable_reg,
        .precious_reg = cs35l56_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED);
 
@@ -352,7 +796,7 @@ struct regmap_config cs35l56_regmap_sdw = {
        .volatile_reg = cs35l56_volatile_reg,
        .readable_reg = cs35l56_readable_reg,
        .precious_reg = cs35l56_precious_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED);
 
index 996aab10500eeb9894633076d8b9d998d4eae75a..9962703915e1f146d682af2b05a2175014dcee9a 100644 (file)
@@ -25,13 +25,13 @@ static int cs35l56_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        spi_set_drvdata(spi, cs35l56);
-       cs35l56->regmap = devm_regmap_init_spi(spi, regmap_config);
-       if (IS_ERR(cs35l56->regmap)) {
-               ret = PTR_ERR(cs35l56->regmap);
+       cs35l56->base.regmap = devm_regmap_init_spi(spi, regmap_config);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
                return dev_err_probe(&spi->dev, ret, "Failed to allocate register map\n");
        }
 
-       cs35l56->dev = &spi->dev;
+       cs35l56->base.dev = &spi->dev;
 
        ret = cs35l56_common_probe(cs35l56);
        if (ret != 0)
@@ -39,7 +39,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)
 
        ret = cs35l56_init(cs35l56);
        if (ret == 0)
-               ret = cs35l56_irq_request(cs35l56, spi->irq);
+               ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
        if (ret < 0)
                cs35l56_remove(cs35l56);
 
@@ -59,10 +59,19 @@ static const struct spi_device_id cs35l56_id_spi[] = {
 };
 MODULE_DEVICE_TABLE(spi, cs35l56_id_spi);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
+       { "CSC355C", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);
+#endif
+
 static struct spi_driver cs35l56_spi_driver = {
        .driver = {
                .name           = "cs35l56",
                .pm = &cs35l56_pm_ops_i2c_spi,
+               .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match),
        },
        .id_table       = cs35l56_id_spi,
        .probe          = cs35l56_spi_probe,
index c03f9d3c9a136b07e4895846414858063d4dc946..600b79c62ec48a5dec9d843cb036477c7867f20a 100644 (file)
@@ -5,7 +5,6 @@
 // Copyright (C) 2023 Cirrus Logic, Inc. and
 //                    Cirrus Logic International Semiconductor Ltd.
 
-#include <linux/acpi.h>
 #include <linux/completion.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event);
 
-static int cs35l56_mbox_send(struct cs35l56_private *cs35l56, unsigned int command)
-{
-       unsigned int val;
-       int ret;
-
-       regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
-       ret = regmap_read_poll_timeout(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
-                                      val, (val == 0),
-                                      CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
-       if (ret) {
-               dev_warn(cs35l56->dev, "MBOX command %#x failed: %d\n", command, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
 static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56)
 {
        /* Wait for patching to complete */
@@ -174,25 +156,25 @@ static int cs35l56_play_event(struct snd_soc_dapm_widget *w,
        unsigned int val;
        int ret;
 
-       dev_dbg(cs35l56->dev, "play: %d\n", event);
+       dev_dbg(cs35l56->base.dev, "play: %d\n", event);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                /* Don't wait for ACK, we check in POST_PMU that it completed */
-               return regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+               return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
                                    CS35L56_MBOX_CMD_AUDIO_PLAY);
        case SND_SOC_DAPM_POST_PMU:
                /* Wait for firmware to enter PS0 power state */
-               ret = regmap_read_poll_timeout(cs35l56->regmap,
+               ret = regmap_read_poll_timeout(cs35l56->base.regmap,
                                               CS35L56_TRANSDUCER_ACTUAL_PS,
                                               val, (val == CS35L56_PS0),
                                               CS35L56_PS0_POLL_US,
                                               CS35L56_PS0_TIMEOUT_US);
                if (ret)
-                       dev_err(cs35l56->dev, "PS0 wait failed: %d\n", ret);
+                       dev_err(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
                return ret;
        case SND_SOC_DAPM_POST_PMD:
-               return cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_PAUSE);
+               return cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
        default:
                return 0;
        }
@@ -310,109 +292,23 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
 
-       dev_dbg(cs35l56->dev, "%s: %d\n", __func__, event);
+       dev_dbg(cs35l56->base.dev, "%s: %d\n", __func__, event);
 
        return wm_adsp_event(w, kcontrol, event);
 }
 
-irqreturn_t cs35l56_irq(int irq, void *data)
-{
-       struct cs35l56_private *cs35l56 = data;
-       unsigned int status1 = 0, status8 = 0, status20 = 0;
-       unsigned int mask1, mask8, mask20;
-       unsigned int val;
-       int rv;
-
-       irqreturn_t ret = IRQ_NONE;
-
-       if (!cs35l56->init_done)
-               return IRQ_NONE;
-
-       mutex_lock(&cs35l56->irq_lock);
-
-       rv = pm_runtime_resume_and_get(cs35l56->dev);
-       if (rv < 0) {
-               dev_err(cs35l56->dev, "irq: failed to get pm_runtime: %d\n", rv);
-               goto err_unlock;
-       }
-
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_STATUS, &val);
-       if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
-               dev_dbg(cs35l56->dev, "Spurious IRQ: no pending interrupt\n");
-               goto err;
-       }
-
-       /* Ack interrupts */
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_1, &status1);
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_1, &mask1);
-       status1 &= ~mask1;
-       regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_1, status1);
-
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_8, &status8);
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_8, &mask8);
-       status8 &= ~mask8;
-       regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_8, status8);
-
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_20, &status20);
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_20, &mask20);
-       status20 &= ~mask20;
-       /* We don't want EINT20 but they default to unmasked: force mask */
-       regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
-
-       dev_dbg(cs35l56->dev, "%s: %#x %#x\n", __func__, status1, status8);
-
-       /* Check to see if unmasked bits are active */
-       if (!status1 && !status8 && !status20)
-               goto err;
-
-       if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
-               dev_crit(cs35l56->dev, "Amp short error\n");
-
-       if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
-               dev_crit(cs35l56->dev, "Overtemp error\n");
-
-       ret = IRQ_HANDLED;
-
-err:
-       pm_runtime_put(cs35l56->dev);
-err_unlock:
-       mutex_unlock(&cs35l56->irq_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE);
-
-int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq)
-{
-       int ret;
-
-       if (!irq)
-               return 0;
-
-       ret = devm_request_threaded_irq(cs35l56->dev, irq, NULL, cs35l56_irq,
-                                       IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
-                                       "cs35l56", cs35l56);
-       if (!ret)
-               cs35l56->irq = irq;
-       else
-               dev_err(cs35l56->dev, "Failed to get IRQ: %d\n", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_CORE);
-
 static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
        unsigned int val;
 
-       dev_dbg(cs35l56->dev, "%s: %#x\n", __func__, fmt);
+       dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);
 
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
        case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
-               dev_err(cs35l56->dev, "Unsupported clock source mode\n");
+               dev_err(cs35l56->base.dev, "Unsupported clock source mode\n");
                return -EINVAL;
        }
 
@@ -426,7 +322,7 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
                cs35l56->tdm_mode = false;
                break;
        default:
-               dev_err(cs35l56->dev, "Unsupported DAI format\n");
+               dev_err(cs35l56->base.dev, "Unsupported DAI format\n");
                return -EINVAL;
        }
 
@@ -443,40 +339,29 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
        case SND_SOC_DAIFMT_NB_NF:
                break;
        default:
-               dev_err(cs35l56->dev, "Invalid clock invert\n");
+               dev_err(cs35l56->base.dev, "Invalid clock invert\n");
                return -EINVAL;
        }
 
-       regmap_update_bits(cs35l56->regmap,
+       regmap_update_bits(cs35l56->base.regmap,
                           CS35L56_ASP1_CONTROL2,
                           CS35L56_ASP_FMT_MASK |
                           CS35L56_ASP_BCLK_INV_MASK | CS35L56_ASP_FSYNC_INV_MASK,
                           val);
 
        /* Hi-Z DOUT in unused slots and when all TX are disabled */
-       regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL3,
+       regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
                           CS35L56_ASP1_DOUT_HIZ_CTRL_MASK,
                           CS35L56_ASP_UNUSED_HIZ_OFF_HIZ);
 
        return 0;
 }
 
-static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
-                                          unsigned int reg, unsigned long mask)
+static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask)
 {
-       unsigned int reg_val, channel_shift;
+       unsigned int channel_shift;
        int bit_num;
 
-       /* Init all slots to 63 */
-       switch (reg) {
-       case CS35L56_ASP1_FRAME_CONTROL1:
-               reg_val = 0x3f3f3f3f;
-               break;
-       case CS35L56_ASP1_FRAME_CONTROL5:
-               reg_val = 0x3f3f3f;
-               break;
-       }
-
        /* Enable consecutive TX1..TXn for each of the slots set in mask */
        channel_shift = 0;
        for_each_set_bit(bit_num, &mask, 32) {
@@ -485,7 +370,7 @@ static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
                channel_shift += 8;
        }
 
-       regmap_write(cs35l56->regmap, reg, reg_val);
+       return reg_val;
 }
 
 static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
@@ -494,20 +379,20 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
 
        if ((slots == 0) || (slot_width == 0)) {
-               dev_dbg(cs35l56->dev, "tdm config cleared\n");
+               dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
                cs35l56->asp_slot_width = 0;
                cs35l56->asp_slot_count = 0;
                return 0;
        }
 
        if (slot_width > (CS35L56_ASP_RX_WIDTH_MASK >> CS35L56_ASP_RX_WIDTH_SHIFT)) {
-               dev_err(cs35l56->dev, "tdm invalid slot width %d\n", slot_width);
+               dev_err(cs35l56->base.dev, "tdm invalid slot width %d\n", slot_width);
                return -EINVAL;
        }
 
        /* More than 32 slots would give an unsupportable BCLK frequency */
        if (slots > 32) {
-               dev_err(cs35l56->dev, "tdm invalid slot count %d\n", slots);
+               dev_err(cs35l56->base.dev, "tdm invalid slot count %d\n", slots);
                return -EINVAL;
        }
 
@@ -521,10 +406,13 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
        if (rx_mask == 0)
                rx_mask = 0xf;  // ASPTX1..TX4 in slots 0..3
 
-       cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask);
-       cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask);
+       /* Default unused slots to 63 */
+       regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1,
+                    cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask));
+       regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5,
+                    cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask));
 
-       dev_dbg(cs35l56->dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
+       dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
                cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask);
 
        return 0;
@@ -544,7 +432,8 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
        else
                asp_width = asp_wl;
 
-       dev_dbg(cs35l56->dev, "%s: wl=%d, width=%d, rate=%d", __func__, asp_wl, asp_width, rate);
+       dev_dbg(cs35l56->base.dev, "%s: wl=%d, width=%d, rate=%d",
+               __func__, asp_wl, asp_width, rate);
 
        if (!cs35l56->sysclk_set) {
                unsigned int slots = cs35l56->asp_slot_count;
@@ -562,26 +451,26 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
                bclk_freq = asp_width * slots * rate;
                freq_id = cs35l56_get_bclk_freq_id(bclk_freq);
                if (freq_id < 0) {
-                       dev_err(cs35l56->dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
+                       dev_err(cs35l56->base.dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
                        return -EINVAL;
                }
 
-               regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
+               regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
                                   CS35L56_ASP_BCLK_FREQ_MASK,
                                   freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
+               regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
                                   CS35L56_ASP_RX_WIDTH_MASK, asp_width <<
                                   CS35L56_ASP_RX_WIDTH_SHIFT);
-               regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL5,
+               regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL5,
                                   CS35L56_ASP_RX_WL_MASK, asp_wl);
        } else {
-               regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
+               regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
                                   CS35L56_ASP_TX_WIDTH_MASK, asp_width <<
                                   CS35L56_ASP_TX_WIDTH_SHIFT);
-               regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL1,
+               regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL1,
                                   CS35L56_ASP_TX_WL_MASK, asp_wl);
        }
 
@@ -603,7 +492,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
        if (freq_id < 0)
                return freq_id;
 
-       regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
+       regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
                           CS35L56_ASP_BCLK_FREQ_MASK,
                           freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
        cs35l56->sysclk_set = true;
@@ -646,9 +535,9 @@ static int cs35l56_sdw_dai_hw_params(struct snd_pcm_substream *substream,
        struct sdw_port_config pconfig;
        int ret;
 
-       dev_dbg(cs35l56->dev, "%s: rate %d\n", __func__, params_rate(params));
+       dev_dbg(cs35l56->base.dev, "%s: rate %d\n", __func__, params_rate(params));
 
-       if (!cs35l56->init_done)
+       if (!cs35l56->base.init_done)
                return -ENODEV;
 
        if (!sdw_stream)
@@ -761,85 +650,31 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
        }
 };
 
-static int cs35l56_wait_for_firmware_boot(struct cs35l56_private *cs35l56)
-{
-       unsigned int reg;
-       unsigned int val;
-       int ret;
-
-       if (cs35l56->rev < CS35L56_REVID_B0)
-               reg = CS35L56_DSP1_HALO_STATE_A1;
-       else
-               reg = CS35L56_DSP1_HALO_STATE;
-
-       ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
-                                      val,
-                                      (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
-                                      CS35L56_HALO_STATE_POLL_US,
-                                      CS35L56_HALO_STATE_TIMEOUT_US);
-
-       if ((ret < 0) && (ret != -ETIMEDOUT)) {
-               dev_err(cs35l56->dev, "Failed to read HALO_STATE: %d\n", ret);
-               return ret;
-       }
-
-       if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
-               dev_err(cs35l56->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static inline void cs35l56_wait_min_reset_pulse(void)
-{
-       /* Satisfy minimum reset pulse width spec */
-       usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
-}
-
-static const struct reg_sequence cs35l56_system_reset_seq[] = {
-       REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
-};
-
-static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
-{
-       cs35l56->soft_resetting = true;
-
-       /*
-        * Must enter cache-only first so there can't be any more register
-        * accesses other than the controlled system reset sequence below.
-        */
-       regcache_cache_only(cs35l56->regmap, true);
-       regmap_multi_reg_write_bypassed(cs35l56->regmap,
-                                       cs35l56_system_reset_seq,
-                                       ARRAY_SIZE(cs35l56_system_reset_seq));
-
-       /* On SoundWire the registers won't be accessible until it re-enumerates. */
-       if (cs35l56->sdw_peripheral)
-               return;
-
-       usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
-       regcache_cache_only(cs35l56->regmap, false);
-}
-
 static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
 {
        int ret;
 
        /* Use wm_adsp to load and apply the firmware patch and coefficient files */
-       ret = wm_adsp_power_up(&cs35l56->dsp);
+       ret = wm_adsp_power_up(&cs35l56->dsp, true);
        if (ret)
-               dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
+               dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
        else
-               cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT);
+               cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
 }
 
 static void cs35l56_patch(struct cs35l56_private *cs35l56)
 {
-       unsigned int reg;
-       unsigned int val;
+       unsigned int firmware_missing;
        int ret;
 
+       ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing);
+       if (ret) {
+               dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
+               return;
+       }
+
+       firmware_missing &= CS35L56_FIRMWARE_MISSING;
+
        /*
         * Disable SoundWire interrupts to prevent race with IRQ work.
         * Setting sdw_irq_no_unmask prevents the handler re-enabling
@@ -854,35 +689,27 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
                flush_work(&cs35l56->sdw_irq_work);
        }
 
-       ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_SHUTDOWN);
+       ret = cs35l56_firmware_shutdown(&cs35l56->base);
        if (ret)
                goto err;
 
-       if (cs35l56->rev < CS35L56_REVID_B0)
-               reg = CS35L56_DSP1_PM_CUR_STATE_A1;
-       else
-               reg = CS35L56_DSP1_PM_CUR_STATE;
-
-       ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
-                                      val, (val == CS35L56_HALO_STATE_SHUTDOWN),
-                                      CS35L56_HALO_STATE_POLL_US,
-                                      CS35L56_HALO_STATE_TIMEOUT_US);
-       if (ret < 0)
-               dev_err(cs35l56->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
-                       val, ret);
-
-       /* Use wm_adsp to load and apply the firmware patch and coefficient files */
-       ret = wm_adsp_power_up(&cs35l56->dsp);
+       /*
+        * Use wm_adsp to load and apply the firmware patch and coefficient files,
+        * but only if firmware is missing. If firmware is already patched just
+        * power-up wm_adsp without downloading firmware.
+        */
+       ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing);
        if (ret) {
-               dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
+               dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
                goto err;
        }
 
-       mutex_lock(&cs35l56->irq_lock);
+       mutex_lock(&cs35l56->base.irq_lock);
 
        init_completion(&cs35l56->init_completion);
 
-       cs35l56_system_reset(cs35l56);
+       cs35l56->soft_resetting = true;
+       cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
 
        if (cs35l56->sdw_peripheral) {
                /*
@@ -892,18 +719,20 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56)
                 */
                if (!wait_for_completion_timeout(&cs35l56->init_completion,
                                                 msecs_to_jiffies(5000))) {
-                       dev_err(cs35l56->dev, "%s: init_completion timed out (SDW)\n", __func__);
+                       dev_err(cs35l56->base.dev, "%s: init_completion timed out (SDW)\n",
+                               __func__);
                        goto err_unlock;
                }
        } else if (cs35l56_init(cs35l56)) {
                goto err_unlock;
        }
 
-       regmap_clear_bits(cs35l56->regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING);
-       cs35l56->fw_patched = true;
+       regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS,
+                         CS35L56_FIRMWARE_MISSING);
+       cs35l56->base.fw_patched = true;
 
 err_unlock:
-       mutex_unlock(&cs35l56->irq_lock);
+       mutex_unlock(&cs35l56->base.irq_lock);
 err:
        /* Re-enable SoundWire interrupts */
        if (cs35l56->sdw_peripheral) {
@@ -919,10 +748,10 @@ static void cs35l56_dsp_work(struct work_struct *work)
                                                       struct cs35l56_private,
                                                       dsp_work);
 
-       if (!cs35l56->init_done)
+       if (!cs35l56->base.init_done)
                return;
 
-       pm_runtime_get_sync(cs35l56->dev);
+       pm_runtime_get_sync(cs35l56->base.dev);
 
        /*
         * When the device is running in secure mode the firmware files can
@@ -930,13 +759,13 @@ static void cs35l56_dsp_work(struct work_struct *work)
         * shutdown the firmware to apply them and can use the lower cost
         * reinit sequence instead.
         */
-       if (cs35l56->secured)
+       if (cs35l56->base.secured)
                cs35l56_secure_patch(cs35l56);
        else
                cs35l56_patch(cs35l56);
 
-       pm_runtime_mark_last_busy(cs35l56->dev);
-       pm_runtime_put_autosuspend(cs35l56->dev);
+       pm_runtime_mark_last_busy(cs35l56->base.dev);
+       pm_runtime_put_autosuspend(cs35l56->base.dev);
 }
 
 static int cs35l56_component_probe(struct snd_soc_component *component)
@@ -948,16 +777,16 @@ static int cs35l56_component_probe(struct snd_soc_component *component)
 
        if (!wait_for_completion_timeout(&cs35l56->init_completion,
                                         msecs_to_jiffies(5000))) {
-               dev_err(cs35l56->dev, "%s: init_completion timed out\n", __func__);
+               dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__);
                return -ENODEV;
        }
 
        cs35l56->component = component;
        wm_adsp2_component_probe(&cs35l56->dsp, component);
 
-       debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->init_done);
-       debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->can_hibernate);
-       debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->fw_patched);
+       debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done);
+       debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
+       debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
 
        queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
 
@@ -1009,171 +838,18 @@ static const struct snd_soc_component_driver soc_component_dev_cs35l56 = {
        .suspend_bias_off = 1, /* see cs35l56_system_resume() */
 };
 
-static const struct reg_sequence cs35l56_hibernate_seq[] = {
-       /* This must be the last register access */
-       REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW),
-};
-
-static const struct reg_sequence cs35l56_hibernate_wake_seq[] = {
-       REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP),
-};
-
-int cs35l56_runtime_suspend(struct device *dev)
+static int __maybe_unused cs35l56_runtime_suspend_i2c_spi(struct device *dev)
 {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
-       unsigned int val;
-       int ret;
-
-       if (!cs35l56->init_done)
-               return 0;
-
-       /* Firmware must have entered a power-save state */
-       ret = regmap_read_poll_timeout(cs35l56->regmap,
-                                      CS35L56_TRANSDUCER_ACTUAL_PS,
-                                      val, (val >= CS35L56_PS3),
-                                      CS35L56_PS3_POLL_US,
-                                      CS35L56_PS3_TIMEOUT_US);
-       if (ret)
-               dev_warn(cs35l56->dev, "PS3 wait failed: %d\n", ret);
-
-       /* Clear BOOT_DONE so it can be used to detect a reboot */
-       regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
-
-       if (!cs35l56->can_hibernate) {
-               regcache_cache_only(cs35l56->regmap, true);
-               dev_dbg(dev, "Suspended: no hibernate");
 
-               return 0;
-       }
-
-       /*
-        * Enable auto-hibernate. If it is woken by some other wake source
-        * it will automatically return to hibernate.
-        */
-       cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
-
-       /*
-        * Must enter cache-only first so there can't be any more register
-        * accesses other than the controlled hibernate sequence below.
-        */
-       regcache_cache_only(cs35l56->regmap, true);
-
-       regmap_multi_reg_write_bypassed(cs35l56->regmap,
-                                       cs35l56_hibernate_seq,
-                                       ARRAY_SIZE(cs35l56_hibernate_seq));
-
-       dev_dbg(dev, "Suspended: hibernate");
-
-       return 0;
+       return cs35l56_runtime_suspend_common(&cs35l56->base);
 }
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend, SND_SOC_CS35L56_CORE);
 
 static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev)
 {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
 
-       if (!cs35l56->init_done)
-               return 0;
-
-       return cs35l56_runtime_resume_common(cs35l56);
-}
-
-int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
-{
-       unsigned int val;
-       int ret;
-
-       if (!cs35l56->can_hibernate)
-               goto out_sync;
-
-       if (!cs35l56->sdw_peripheral) {
-               /*
-                * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C.
-                * Must be done before releasing cache-only.
-                */
-               regmap_multi_reg_write_bypassed(cs35l56->regmap,
-                                               cs35l56_hibernate_wake_seq,
-                                               ARRAY_SIZE(cs35l56_hibernate_wake_seq));
-
-               usleep_range(CS35L56_CONTROL_PORT_READY_US,
-                            CS35L56_CONTROL_PORT_READY_US + 400);
-       }
-
-out_sync:
-       regcache_cache_only(cs35l56->regmap, false);
-
-       ret = cs35l56_wait_for_firmware_boot(cs35l56);
-       if (ret) {
-               dev_err(cs35l56->dev, "Hibernate wake failed: %d\n", ret);
-               goto err;
-       }
-
-       ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
-       if (ret)
-               goto err;
-
-       /* BOOT_DONE will be 1 if the amp reset */
-       regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_4, &val);
-       if (val & CS35L56_OTP_BOOT_DONE_MASK) {
-               dev_dbg(cs35l56->dev, "Registers reset in suspend\n");
-               regcache_mark_dirty(cs35l56->regmap);
-       }
-
-       regcache_sync(cs35l56->regmap);
-
-       dev_dbg(cs35l56->dev, "Resumed");
-
-       return 0;
-
-err:
-       regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
-                    CS35L56_MBOX_CMD_HIBERNATE_NOW);
-
-       regcache_cache_only(cs35l56->regmap, true);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE);
-
-static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56)
-{
-       unsigned int val;
-       int ret;
-
-       /* Nothing to re-patch if we haven't done any patching yet. */
-       if (!cs35l56->fw_patched)
-               return false;
-
-       /*
-        * If we have control of RESET we will have asserted it so the firmware
-        * will need re-patching.
-        */
-       if (cs35l56->reset_gpio)
-               return true;
-
-       /*
-        * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
-        * can't be used here to test for memory retention.
-        * Assume that tuning must be re-loaded.
-        */
-       if (cs35l56->secured)
-               return true;
-
-       ret = pm_runtime_resume_and_get(cs35l56->dev);
-       if (ret) {
-               dev_err(cs35l56->dev, "Failed to runtime_get: %d\n", ret);
-               return ret;
-       }
-
-       ret = regmap_read(cs35l56->regmap, CS35L56_PROTECTION_STATUS, &val);
-       if (ret)
-               dev_err(cs35l56->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
-       else
-               ret = !!(val & CS35L56_FIRMWARE_MISSING);
-
-       pm_runtime_put_autosuspend(cs35l56->dev);
-
-       return ret;
+       return cs35l56_runtime_resume_common(&cs35l56->base, false);
 }
 
 int cs35l56_system_suspend(struct device *dev)
@@ -1191,8 +867,8 @@ int cs35l56_system_suspend(struct device *dev)
         * clear it. Prevent this race by temporarily disabling the parent irq
         * until we reach _no_irq.
         */
-       if (cs35l56->irq)
-               disable_irq(cs35l56->irq);
+       if (cs35l56->base.irq)
+               disable_irq(cs35l56->base.irq);
 
        return pm_runtime_force_suspend(dev);
 }
@@ -1209,8 +885,8 @@ int cs35l56_system_suspend_late(struct device *dev)
         * RESET is usually shared by all amps so it must not be asserted until
         * all driver instances have done their suspend() stage.
         */
-       if (cs35l56->reset_gpio) {
-               gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+       if (cs35l56->base.reset_gpio) {
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
                cs35l56_wait_min_reset_pulse();
        }
 
@@ -1227,8 +903,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev)
        dev_dbg(dev, "system_suspend_no_irq\n");
 
        /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
-       if (cs35l56->irq)
-               enable_irq(cs35l56->irq);
+       if (cs35l56->base.irq)
+               enable_irq(cs35l56->base.irq);
 
        return 0;
 }
@@ -1247,8 +923,8 @@ int cs35l56_system_resume_no_irq(struct device *dev)
         * clear it, until it has fully resumed. Prevent this race by temporarily
         * disabling the parent irq until we complete resume().
         */
-       if (cs35l56->irq)
-               disable_irq(cs35l56->irq);
+       if (cs35l56->base.irq)
+               disable_irq(cs35l56->base.irq);
 
        return 0;
 }
@@ -1262,8 +938,8 @@ int cs35l56_system_resume_early(struct device *dev)
        dev_dbg(dev, "system_resume_early\n");
 
        /* Ensure a spec-compliant RESET pulse. */
-       if (cs35l56->reset_gpio) {
-               gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+       if (cs35l56->base.reset_gpio) {
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
                cs35l56_wait_min_reset_pulse();
        }
 
@@ -1275,7 +951,7 @@ int cs35l56_system_resume_early(struct device *dev)
        }
 
        /* Release shared RESET before drivers start resume(). */
-       gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
 
        return 0;
 }
@@ -1288,10 +964,16 @@ int cs35l56_system_resume(struct device *dev)
 
        dev_dbg(dev, "system_resume\n");
 
+       /*
+        * We might have done a hard reset or the CS35L56 was power-cycled
+        * so wait for control port to be ready.
+        */
+       cs35l56_wait_control_port_ready();
+
        /* Undo pm_runtime_force_suspend() before re-enabling the irq */
        ret = pm_runtime_force_resume(dev);
-       if (cs35l56->irq)
-               enable_irq(cs35l56->irq);
+       if (cs35l56->base.irq)
+               enable_irq(cs35l56->base.irq);
 
        if (ret)
                return ret;
@@ -1300,12 +982,13 @@ int cs35l56_system_resume(struct device *dev)
        if (!cs35l56->component)
                return 0;
 
-       ret = cs35l56_is_fw_reload_needed(cs35l56);
-       dev_dbg(cs35l56->dev, "fw_reload_needed: %d\n", ret);
+       ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
+       dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
        if (ret < 1)
                return ret;
 
-       cs35l56->fw_patched = false;
+       cs35l56->base.fw_patched = false;
+       wm_adsp_power_down(&cs35l56->dsp);
        queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
 
        /*
@@ -1329,51 +1012,38 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56)
        INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work);
 
        dsp = &cs35l56->dsp;
+       cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
        dsp->part = "cs35l56";
-       dsp->cs_dsp.num = 1;
-       dsp->cs_dsp.type = WMFW_HALO;
-       dsp->cs_dsp.rev = 0;
        dsp->fw = 12;
-       dsp->cs_dsp.dev = cs35l56->dev;
-       dsp->cs_dsp.regmap = cs35l56->regmap;
-       dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE;
-       dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID;
-       dsp->cs_dsp.mem = cs35l56_dsp1_regions;
-       dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l56_dsp1_regions);
-       dsp->cs_dsp.no_core_startstop = true;
        dsp->wmfw_optional = true;
 
-       dev_dbg(cs35l56->dev, "DSP system name: '%s'\n", dsp->system_name);
+       dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name);
 
        ret = wm_halo_init(dsp);
        if (ret != 0) {
-               dev_err(cs35l56->dev, "wm_halo_init failed\n");
+               dev_err(cs35l56->base.dev, "wm_halo_init failed\n");
                return ret;
        }
 
        return 0;
 }
 
-static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56)
+static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
 {
-       acpi_handle handle = ACPI_HANDLE(cs35l56->dev);
-       const char *sub;
+       struct device *dev = cs35l56->base.dev;
+       const char *prop;
+       int ret;
 
-       /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
-       if (!handle)
+       ret = device_property_read_string(dev, "cirrus,firmware-uid", &prop);
+       /* If bad sw node property, return 0 and fallback to legacy firmware path */
+       if (ret < 0)
                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);
-       }
+       cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
+       if (cs35l56->dsp.system_name == NULL)
+               return -ENOMEM;
 
-       cs35l56->dsp.system_name = sub;
-       dev_dbg(cs35l56->dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name);
+       dev_dbg(dev, "Firmware UID: %s\n", cs35l56->dsp.system_name);
 
        return 0;
 }
@@ -1383,62 +1053,65 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
        int ret;
 
        init_completion(&cs35l56->init_completion);
-       mutex_init(&cs35l56->irq_lock);
+       mutex_init(&cs35l56->base.irq_lock);
 
-       dev_set_drvdata(cs35l56->dev, cs35l56);
+       dev_set_drvdata(cs35l56->base.dev, cs35l56);
 
        cs35l56_fill_supply_names(cs35l56->supplies);
-       ret = devm_regulator_bulk_get(cs35l56->dev, ARRAY_SIZE(cs35l56->supplies),
+       ret = devm_regulator_bulk_get(cs35l56->base.dev, ARRAY_SIZE(cs35l56->supplies),
                                      cs35l56->supplies);
        if (ret != 0)
-               return dev_err_probe(cs35l56->dev, ret, "Failed to request supplies\n");
+               return dev_err_probe(cs35l56->base.dev, ret, "Failed to request supplies\n");
 
        /* Reset could be controlled by the BIOS or shared by multiple amps */
-       cs35l56->reset_gpio = devm_gpiod_get_optional(cs35l56->dev, "reset", GPIOD_OUT_LOW);
-       if (IS_ERR(cs35l56->reset_gpio)) {
-               ret = PTR_ERR(cs35l56->reset_gpio);
+       cs35l56->base.reset_gpio = devm_gpiod_get_optional(cs35l56->base.dev, "reset",
+                                                          GPIOD_OUT_LOW);
+       if (IS_ERR(cs35l56->base.reset_gpio)) {
+               ret = PTR_ERR(cs35l56->base.reset_gpio);
                /*
                 * If RESET is shared the first amp to probe will grab the reset
                 * line and reset all the amps
                 */
                if (ret != -EBUSY)
-                       return dev_err_probe(cs35l56->dev, ret, "Failed to get reset GPIO\n");
+                       return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
 
-               dev_info(cs35l56->dev, "Reset GPIO busy, assume shared reset\n");
-               cs35l56->reset_gpio = NULL;
+               dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
+               cs35l56->base.reset_gpio = NULL;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
        if (ret != 0)
-               return dev_err_probe(cs35l56->dev, ret, "Failed to enable supplies\n");
+               return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n");
 
-       if (cs35l56->reset_gpio) {
+       if (cs35l56->base.reset_gpio) {
+               /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
                cs35l56_wait_min_reset_pulse();
-               gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
        }
 
-       ret = cs35l56_acpi_get_name(cs35l56);
+       ret = cs35l56_get_firmware_uid(cs35l56);
        if (ret != 0)
                goto err;
 
        ret = cs35l56_dsp_init(cs35l56);
        if (ret < 0) {
-               dev_err_probe(cs35l56->dev, ret, "DSP init failed\n");
+               dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n");
                goto err;
        }
 
-       ret = devm_snd_soc_register_component(cs35l56->dev,
+       ret = devm_snd_soc_register_component(cs35l56->base.dev,
                                              &soc_component_dev_cs35l56,
                                              cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
        if (ret < 0) {
-               dev_err_probe(cs35l56->dev, ret, "Register codec failed\n");
+               dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
                goto err;
        }
 
        return 0;
 
 err:
-       gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
        regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
 
        return ret;
@@ -1448,7 +1121,6 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE);
 int cs35l56_init(struct cs35l56_private *cs35l56)
 {
        int ret;
-       unsigned int devid, revid, otpid, secured;
 
        /*
         * Check whether the actions associated with soft reset or one time
@@ -1457,96 +1129,31 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
        if (cs35l56->soft_resetting)
                goto post_soft_reset;
 
-       if (cs35l56->init_done)
+       if (cs35l56->base.init_done)
                return 0;
 
-       pm_runtime_set_autosuspend_delay(cs35l56->dev, 100);
-       pm_runtime_use_autosuspend(cs35l56->dev);
-       pm_runtime_set_active(cs35l56->dev);
-       pm_runtime_enable(cs35l56->dev);
-
-       /*
-        * If the system is not using a reset_gpio then issue a
-        * dummy read to force a wakeup.
-        */
-       if (!cs35l56->reset_gpio)
-               regmap_read(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
-
-       /* Wait for control port to be ready (datasheet tIRS). */
-       usleep_range(CS35L56_CONTROL_PORT_READY_US,
-                    CS35L56_CONTROL_PORT_READY_US + 400);
-
-       /*
-        * The HALO_STATE register is in different locations on Ax and B0
-        * devices so the REVID needs to be determined before waiting for the
-        * firmware to boot.
-        */
-       ret = regmap_read(cs35l56->regmap, CS35L56_REVID, &revid);
-       if (ret < 0) {
-               dev_err(cs35l56->dev, "Get Revision ID failed\n");
-               return ret;
-       }
-       cs35l56->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
-
-       ret = cs35l56_wait_for_firmware_boot(cs35l56);
-       if (ret)
-               return ret;
-
-       ret = regmap_read(cs35l56->regmap, CS35L56_DEVID, &devid);
-       if (ret < 0) {
-               dev_err(cs35l56->dev, "Get Device ID failed\n");
-               return ret;
-       }
-       devid &= CS35L56_DEVID_MASK;
+       pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 100);
+       pm_runtime_use_autosuspend(cs35l56->base.dev);
+       pm_runtime_set_active(cs35l56->base.dev);
+       pm_runtime_enable(cs35l56->base.dev);
 
-       switch (devid) {
-       case 0x35A56:
-               break;
-       default:
-               dev_err(cs35l56->dev, "Unknown device %x\n", devid);
-               return ret;
-       }
-
-       ret = regmap_read(cs35l56->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
-       if (ret) {
-               dev_err(cs35l56->dev, "Get Secure status failed\n");
-               return ret;
-       }
-
-       /* When any bus is restricted treat the device as secured */
-       if (secured & CS35L56_RESTRICTED_MASK)
-               cs35l56->secured = true;
-
-       ret = regmap_read(cs35l56->regmap, CS35L56_OTPID, &otpid);
-       if (ret < 0) {
-               dev_err(cs35l56->dev, "Get OTP ID failed\n");
+       ret = cs35l56_hw_init(&cs35l56->base);
+       if (ret < 0)
                return ret;
-       }
-
-       dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
-                cs35l56->secured ? "s" : "", cs35l56->rev, otpid);
 
        /* Populate the DSP information with the revision and security state */
-       cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x",
-                                          cs35l56->secured ? "s" : "", cs35l56->rev);
+       cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x",
+                                          cs35l56->base.secured ? "s" : "", cs35l56->base.rev);
        if (!cs35l56->dsp.part)
                return -ENOMEM;
 
-       /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
-       regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
-       regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1,
-                          CS35L56_AMP_SHORT_ERR_EINT1_MASK,
-                          0);
-       regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_8,
-                          CS35L56_TEMP_ERR_EINT1_MASK,
-                          0);
-
-       if (!cs35l56->reset_gpio) {
-               dev_dbg(cs35l56->dev, "No reset gpio: using soft reset\n");
-               cs35l56_system_reset(cs35l56);
+       if (!cs35l56->base.reset_gpio) {
+               dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
+               cs35l56->soft_resetting = true;
+               cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
                if (cs35l56->sdw_peripheral) {
                        /* Keep alive while we wait for re-enumeration */
-                       pm_runtime_get_noresume(cs35l56->dev);
+                       pm_runtime_get_noresume(cs35l56->base.dev);
                        return 0;
                }
        }
@@ -1556,29 +1163,30 @@ post_soft_reset:
                cs35l56->soft_resetting = false;
 
                /* Done re-enumerating after one-time init so release the keep-alive */
-               if (cs35l56->sdw_peripheral && !cs35l56->init_done)
-                       pm_runtime_put_noidle(cs35l56->dev);
+               if (cs35l56->sdw_peripheral && !cs35l56->base.init_done)
+                       pm_runtime_put_noidle(cs35l56->base.dev);
 
-               regcache_mark_dirty(cs35l56->regmap);
-               ret = cs35l56_wait_for_firmware_boot(cs35l56);
+               regcache_mark_dirty(cs35l56->base.regmap);
+               ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
                if (ret)
                        return ret;
 
-               dev_dbg(cs35l56->dev, "Firmware rebooted after soft reset\n");
+               dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n");
        }
 
        /* Disable auto-hibernate so that runtime_pm has control */
-       ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
        if (ret)
                return ret;
 
-       /* Populate soft registers in the regmap cache */
-       cs35l56_reread_firmware_registers(cs35l56->dev, cs35l56->regmap);
+       ret = cs35l56_set_patch(&cs35l56->base);
+       if (ret)
+               return ret;
 
        /* Registers could be dirty after soft reset or SoundWire enumeration */
-       regcache_sync(cs35l56->regmap);
+       regcache_sync(cs35l56->base.regmap);
 
-       cs35l56->init_done = true;
+       cs35l56->base.init_done = true;
        complete(&cs35l56->init_completion);
 
        return 0;
@@ -1587,32 +1195,30 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE);
 
 void cs35l56_remove(struct cs35l56_private *cs35l56)
 {
-       cs35l56->init_done = false;
+       cs35l56->base.init_done = false;
 
        /*
         * WAKE IRQs unmask if CS35L56 hibernates so free the handler to
         * prevent it racing with remove().
         */
-       if (cs35l56->irq)
-               devm_free_irq(cs35l56->dev, cs35l56->irq, cs35l56);
+       if (cs35l56->base.irq)
+               devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base);
 
        flush_workqueue(cs35l56->dsp_wq);
        destroy_workqueue(cs35l56->dsp_wq);
 
-       pm_runtime_suspend(cs35l56->dev);
-       pm_runtime_disable(cs35l56->dev);
-
-       regcache_cache_only(cs35l56->regmap, true);
+       pm_runtime_suspend(cs35l56->base.dev);
+       pm_runtime_disable(cs35l56->base.dev);
 
-       kfree(cs35l56->dsp.system_name);
+       regcache_cache_only(cs35l56->base.regmap, true);
 
-       gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
        regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
 }
 EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE);
 
 const struct dev_pm_ops cs35l56_pm_ops_i2c_spi = {
-       SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend, cs35l56_runtime_resume_i2c_spi, NULL)
+       SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend_i2c_spi, cs35l56_runtime_resume_i2c_spi, NULL)
        SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend, cs35l56_system_resume)
        LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
        NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_no_irq, cs35l56_system_resume_no_irq)
index 1f7894662fcbfb260bdd37033c498a4b7f65a312..8159c3e217d936c02baf88c5659a99e4f3159ddd 100644 (file)
@@ -32,26 +32,17 @@ struct sdw_slave;
 
 struct cs35l56_private {
        struct wm_adsp dsp; /* must be first member */
+       struct cs35l56_base base;
        struct work_struct dsp_work;
        struct workqueue_struct *dsp_wq;
-       struct mutex irq_lock;
        struct snd_soc_component *component;
-       struct device *dev;
-       struct regmap *regmap;
        struct regulator_bulk_data supplies[CS35L56_NUM_BULK_SUPPLIES];
-       int irq;
        struct sdw_slave *sdw_peripheral;
-       u8 rev;
        struct work_struct sdw_irq_work;
-       bool secured;
        bool sdw_irq_no_unmask;
        bool soft_resetting;
-       bool init_done;
        bool sdw_attached;
-       bool fw_patched;
-       bool can_hibernate;
        struct completion init_completion;
-       struct gpio_desc *reset_gpio;
 
        u32 rx_mask;
        u32 tx_mask;
@@ -64,8 +55,6 @@ struct cs35l56_private {
 
 extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
 
-int cs35l56_runtime_suspend(struct device *dev);
-int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56);
 int cs35l56_system_suspend(struct device *dev);
 int cs35l56_system_suspend_late(struct device *dev);
 int cs35l56_system_suspend_no_irq(struct device *dev);
@@ -73,7 +62,7 @@ int cs35l56_system_resume_no_irq(struct device *dev);
 int cs35l56_system_resume_early(struct device *dev);
 int cs35l56_system_resume(struct device *dev);
 irqreturn_t cs35l56_irq(int irq, void *data);
-int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq);
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
 int cs35l56_common_probe(struct cs35l56_private *cs35l56);
 int cs35l56_init(struct cs35l56_private *cs35l56);
 void cs35l56_remove(struct cs35l56_private *cs35l56);
index 0cfc5ab36a13cb5e4699b2e1b169dc311d3314b0..1ed1e60d8e536893621b079492c7c47a5a1d6e15 100644 (file)
@@ -564,7 +564,7 @@ static const struct regmap_config cs4265_regmap = {
        .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
        .readable_reg = cs4265_readable_register,
        .volatile_reg = cs4265_volatile_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int cs4265_i2c_probe(struct i2c_client *i2c_client)
index ab32f15e3b441a12e61dc8eec80f9c06e308bf25..3df567214952dba754c1a43682c59dffd753977f 100644 (file)
@@ -636,7 +636,7 @@ static const struct regmap_config cs4270_regmap = {
        .max_register =         CS4270_LASTREG,
        .reg_defaults =         cs4270_reg_defaults,
        .num_reg_defaults =     ARRAY_SIZE(cs4270_reg_defaults),
-       .cache_type =           REGCACHE_RBTREE,
+       .cache_type =           REGCACHE_MAPLE,
        .write_flag_mask =      CS4270_I2C_INCR,
 
        .readable_reg =         cs4270_reg_is_readable,
index e7db7bcd0296b3ff95274e326f80b3bc3fa95faa..5ed2ef83dcdb730db79cd67c5e353adf32c58ee6 100644 (file)
@@ -19,7 +19,7 @@ static struct i2c_device_id cs42l51_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
 
-const struct of_device_id cs42l51_of_match[] = {
+static const struct of_device_id cs42l51_of_match[] = {
        { .compatible = "cirrus,cs42l51", },
        { }
 };
index a7079ae0ca09d52aa1bfe6082c07de89c671214c..e4827b8c2bde45c8f9ca48f41174e5a0ae7aacca 100644 (file)
@@ -703,7 +703,7 @@ const struct regmap_config cs42l51_regmap = {
        .volatile_reg = cs42l51_volatile_reg,
        .writeable_reg = cs42l51_writeable_reg,
        .max_register = CS42L51_CHARGE_FREQ,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(cs42l51_regmap);
 
index 1f1ded0ff0ac2ab0087e680be1c665dfeda7c29b..4fc8a6ae8d92ca8f7beff11c5503f61e0be9f131 100644 (file)
@@ -1084,7 +1084,7 @@ static const struct regmap_config cs42l52_regmap = {
        .num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
        .readable_reg = cs42l52_readable_register,
        .volatile_reg = cs42l52_volatile_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int cs42l52_i2c_probe(struct i2c_client *i2c_client)
index 4c646e8d72aaf55f1c8b2fd7de0b163247942589..1714857594fbea99e015b2cebbdf74ada6bdd374 100644 (file)
@@ -1125,7 +1125,7 @@ static const struct regmap_config cs42l56_regmap = {
        .num_reg_defaults = ARRAY_SIZE(cs42l56_reg_defaults),
        .readable_reg = cs42l56_readable_register,
        .volatile_reg = cs42l56_volatile_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int cs42l56_handle_of_data(struct i2c_client *i2c_client,
index 4558ec38a7acebad0e332b1bb2c8c24b4c99c22c..9c44b6283b8f96b2dbe8f45c3bae5a09ba874b14 100644 (file)
@@ -458,7 +458,7 @@ const struct regmap_config cs42xx8_regmap_config = {
        .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
        .volatile_reg = cs42xx8_volatile_register,
        .writeable_reg = cs42xx8_writeable_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
 
index 8365dd0ebe2a176ed0073ceeacd8d146040808f1..ef08e51901b57162083d7f46697da742f0a85e4b 100644 (file)
@@ -271,7 +271,7 @@ static const struct regmap_config cs4349_regmap = {
        .num_reg_defaults       = ARRAY_SIZE(cs4349_reg_defaults),
        .readable_reg           = cs4349_readable_register,
        .writeable_reg          = cs4349_writeable_register,
-       .cache_type             = REGCACHE_RBTREE,
+       .cache_type             = REGCACHE_MAPLE,
 };
 
 static int cs4349_i2c_probe(struct i2c_client *client)
index a6538dab663977c32fa97dc99440b5602771886d..1245e1a4f2a57254f7ae566f6ad9225415db4305 100644 (file)
@@ -1143,6 +1143,10 @@ static int cs47l15_set_fll(struct snd_soc_component *component, int fll_id,
        }
 }
 
+static const struct snd_soc_dai_ops cs47l15_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver cs47l15_dai[] = {
        {
                .name = "cs47l15-aif1",
@@ -1219,7 +1223,7 @@ static struct snd_soc_dai_driver cs47l15_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &cs47l15_dai_ops,
        },
        {
                .name = "cs47l15-dsp-trace",
index a07b621d463ef2ddec4905d8a3e11d9e843fb9f4..cfa1d34f6ebd8db818d48ecea708f7d71b0b173b 100644 (file)
@@ -957,6 +957,10 @@ static int cs47l24_set_fll(struct snd_soc_component *component, int fll_id,
 #define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                         SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const struct snd_soc_dai_ops cs47l24_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver cs47l24_dai[] = {
        {
                .name = "cs47l24-aif1",
@@ -1033,7 +1037,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
                        .rates = CS47L24_RATES,
                        .formats = CS47L24_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &cs47l24_dai_ops,
        },
        {
                .name = "cs47l24-dsp-voicectrl",
@@ -1054,7 +1058,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = {
                        .rates = CS47L24_RATES,
                        .formats = CS47L24_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &cs47l24_dai_ops,
        },
        {
                .name = "cs47l24-dsp-trace",
index c05c80c16c84da3aaa6c7b5a2b1b17c73d6d29d2..a953f2ede1eed8e46b98b76c50d89a9bef8cd5d2 100644 (file)
@@ -1348,6 +1348,10 @@ static int cs47l35_set_fll(struct snd_soc_component *component, int fll_id,
        }
 }
 
+static const struct snd_soc_dai_ops cs47l35_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver cs47l35_dai[] = {
        {
                .name = "cs47l35-aif1",
@@ -1462,7 +1466,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = &snd_soc_new_compress,
+               .ops = &cs47l35_dai_ops,
        },
        {
                .name = "cs47l35-dsp-voicectrl",
@@ -1483,7 +1487,7 @@ static struct snd_soc_dai_driver cs47l35_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = &snd_soc_new_compress,
+               .ops = &cs47l35_dai_ops,
        },
        {
                .name = "cs47l35-dsp-trace",
index dd7997a53e70157887f49418a0dc3497939ccc8b..8276854818595946e19ea752df88f0e5effdaf9d 100644 (file)
@@ -2249,6 +2249,10 @@ static int cs47l85_set_fll(struct snd_soc_component *component, int fll_id,
        }
 }
 
+static const struct snd_soc_dai_ops cs47l85_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver cs47l85_dai[] = {
        {
                .name = "cs47l85-aif1",
@@ -2404,7 +2408,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = &snd_soc_new_compress,
+               .ops = &cs47l85_dai_ops,
        },
        {
                .name = "cs47l85-dsp-voicectrl",
@@ -2425,7 +2429,7 @@ static struct snd_soc_dai_driver cs47l85_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = &snd_soc_new_compress,
+               .ops = &cs47l85_dai_ops,
        },
        {
                .name = "cs47l85-dsp-trace",
index cdd5e7e20b5d5f8f47eca9246f99df7b8f51cef5..2c9a5372cf51b80dfdbdac0fbc3c2cf432bdabb1 100644 (file)
@@ -2168,6 +2168,10 @@ static int cs47l90_set_fll(struct snd_soc_component *component, int fll_id,
        }
 }
 
+static const struct snd_soc_dai_ops cs47l90_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver cs47l90_dai[] = {
        {
                .name = "cs47l90-aif1",
@@ -2323,7 +2327,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = &snd_soc_new_compress,
+               .ops = &cs47l90_dai_ops,
        },
        {
                .name = "cs47l90-dsp-voicectrl",
@@ -2344,7 +2348,7 @@ static struct snd_soc_dai_driver cs47l90_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = &snd_soc_new_compress,
+               .ops = &cs47l90_dai_ops,
        },
        {
                .name = "cs47l90-dsp-trace",
index bc4d311d47782c37aa7e0eb5b418be613328d6a3..352deeaff1ca9f817ff180868818bac32421dccb 100644 (file)
@@ -1690,6 +1690,10 @@ static int cs47l92_set_fll(struct snd_soc_component *component, int fll_id,
        }
 }
 
+static const struct snd_soc_dai_ops cs47l92_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver cs47l92_dai[] = {
        {
                .name = "cs47l92-aif1",
@@ -1823,7 +1827,7 @@ static struct snd_soc_dai_driver cs47l92_dai[] = {
                        .rates = MADERA_RATES,
                        .formats = MADERA_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &cs47l92_dai_ops,
        },
        {
                .name = "cs47l92-dsp-trace",
index 082231088a265849b9e92560d256764201140a80..f8b12808401569d9cd0d45b7341477b28774f7c4 100644 (file)
@@ -1546,6 +1546,14 @@ static int cx2072x_dsp_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops cx2072x_dai_ops2 = {
+       .probe          = cx2072x_dsp_dai_probe,
+       .set_sysclk     = cx2072x_set_dai_sysclk,
+       .set_fmt        = cx2072x_set_dai_fmt,
+       .hw_params      = cx2072x_hw_params,
+       .set_bclk_ratio = cx2072x_set_dai_bclk_ratio,
+};
+
 #define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
@@ -1572,7 +1580,6 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
        { /* plabayck only, return echo reference to Conexant DSP chip */
                .name = "cx2072x-dsp",
                .id     = CX2072X_DAI_DSP,
-               .probe = cx2072x_dsp_dai_probe,
                .playback = {
                        .stream_name = "DSP Playback",
                        .channels_min = 2,
@@ -1580,7 +1587,7 @@ static struct snd_soc_dai_driver soc_codec_cx2072x_dai[] = {
                        .rates = CX2072X_RATES_DSP,
                        .formats = CX2072X_FORMATS,
                },
-               .ops = &cx2072x_dai_ops,
+               .ops = &cx2072x_dai_ops2,
        },
        { /* plabayck only, return echo reference through I2S TX */
                .name = "cx2072x-aec",
index 65e497b455d34a003af1c9043fa4c25ed4876829..a8f347f1affbdc44d63aa3612850e5fc6f4795c7 100644 (file)
@@ -27,9 +27,9 @@
  * MCLK/LRCK ratios, but we also add ratio 400, which is commonly used on
  * Intel Cherry Trail platforms (19.2MHz MCLK, 48kHz LRCK).
  */
-#define NR_SUPPORTED_MCLK_LRCK_RATIOS 6
+#define NR_SUPPORTED_MCLK_LRCK_RATIOS ARRAY_SIZE(supported_mclk_lrck_ratios)
 static const unsigned int supported_mclk_lrck_ratios[] = {
-       256, 384, 400, 512, 768, 1024
+       256, 384, 400, 500, 512, 768, 1024
 };
 
 struct es8316_priv {
@@ -494,6 +494,7 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
                bclk_divider /= 20;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
                wordlen = ES8316_SERDATA2_LEN_24;
                bclk_divider /= 24;
                break;
index 7cb5b57ae655d7f5e58ddf8cd5e9920ae578f45a..6c263086c44d2f1df6a8d777620eb76f52f1abad 100644 (file)
@@ -38,6 +38,11 @@ struct es8326_priv {
        u8 interrupt_clk;
        bool jd_inverted;
        unsigned int sysclk;
+
+       bool calibrated;
+       int version;
+       int hp;
+       int jack_remove_retry;
 };
 
 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
@@ -121,33 +126,12 @@ static const struct snd_soc_dapm_widget es8326_dapm_widgets[] = {
        /* Analog Power Supply*/
        SND_SOC_DAPM_DAC("Right DAC", NULL, ES8326_ANA_PDN, 0, 1),
        SND_SOC_DAPM_DAC("Left DAC", NULL, ES8326_ANA_PDN, 1, 1),
-       SND_SOC_DAPM_SUPPLY("Analog Power", ES8326_ANA_PDN, 7, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("IBias Power", ES8326_ANA_PDN, 6, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("ADC Vref", ES8326_ANA_PDN, 5, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("DAC Vref", ES8326_ANA_PDN, 4, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("Vref Power", ES8326_ANA_PDN, 3, 1, NULL, 0),
        SND_SOC_DAPM_SUPPLY("MICBIAS1", ES8326_ANA_MICBIAS, 2, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("MICBIAS2", ES8326_ANA_MICBIAS, 3, 0, NULL, 0),
 
        SND_SOC_DAPM_PGA("LHPMIX", ES8326_DAC2HPMIX, 7, 0, NULL, 0),
        SND_SOC_DAPM_PGA("RHPMIX", ES8326_DAC2HPMIX, 3, 0, NULL, 0),
 
-       /* Headphone Charge Pump and Output */
-       SND_SOC_DAPM_SUPPLY("HPOR Cal", ES8326_HP_CAL, 7, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("HPOL Cal", ES8326_HP_CAL, 3, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("Headphone Charge Pump", ES8326_HP_DRIVER,
-                           3, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("Headphone Driver Bias", ES8326_HP_DRIVER,
-                           2, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("Headphone LDO", ES8326_HP_DRIVER,
-                           1, 1, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("Headphone Reference", ES8326_HP_DRIVER,
-                           0, 1, NULL, 0),
-       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOR Supply", ES8326_HP_CAL,
-                        ES8326_HPOR_SHIFT, 7, 7, 0),
-       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPOL Supply", ES8326_HP_CAL,
-                        0, 7, 7, 0),
-
        SND_SOC_DAPM_OUTPUT("HPOL"),
        SND_SOC_DAPM_OUTPUT("HPOR"),
 };
@@ -166,52 +150,35 @@ static const struct snd_soc_dapm_route es8326_dapm_routes[] = {
        {"I2S OUT", NULL, "ADC L"},
        {"I2S OUT", NULL, "ADC R"},
 
-       {"I2S OUT", NULL, "Analog Power"},
-       {"I2S OUT", NULL, "ADC Vref"},
-       {"I2S OUT", NULL, "Vref Power"},
-       {"I2S OUT", NULL, "IBias Power"},
-       {"I2S IN", NULL, "Analog Power"},
-       {"I2S IN", NULL, "DAC Vref"},
-       {"I2S IN", NULL, "Vref Power"},
-       {"I2S IN", NULL, "IBias Power"},
-
        {"Right DAC", NULL, "I2S IN"},
        {"Left DAC", NULL, "I2S IN"},
 
        {"LHPMIX", NULL, "Left DAC"},
        {"RHPMIX", NULL, "Right DAC"},
 
-       {"HPOR", NULL, "HPOR Cal"},
-       {"HPOL", NULL, "HPOL Cal"},
-       {"HPOR", NULL, "HPOR Supply"},
-       {"HPOL", NULL, "HPOL Supply"},
-       {"HPOL", NULL, "Headphone Charge Pump"},
-       {"HPOR", NULL, "Headphone Charge Pump"},
-       {"HPOL", NULL, "Headphone Driver Bias"},
-       {"HPOR", NULL, "Headphone Driver Bias"},
-       {"HPOL", NULL, "Headphone LDO"},
-       {"HPOR", NULL, "Headphone LDO"},
-       {"HPOL", NULL, "Headphone Reference"},
-       {"HPOR", NULL, "Headphone Reference"},
-
        {"HPOL", NULL, "LHPMIX"},
        {"HPOR", NULL, "RHPMIX"},
 };
 
-static const struct regmap_range es8326_volatile_ranges[] = {
-       regmap_reg_range(ES8326_HP_DETECT, ES8326_HP_DETECT),
-};
-
-static const struct regmap_access_table es8326_volatile_table = {
-       .yes_ranges = es8326_volatile_ranges,
-       .n_yes_ranges = ARRAY_SIZE(es8326_volatile_ranges),
-};
+static bool es8326_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ES8326_HPL_OFFSET_INI:
+       case ES8326_HPR_OFFSET_INI:
+       case ES8326_HPDET_STA:
+       case ES8326_CTIA_OMTP_STA:
+       case ES8326_CSM_MUTE_STA:
+               return true;
+       default:
+               return false;
+       }
+}
 
 static const struct regmap_config es8326_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
        .max_register = 0xff,
-       .volatile_table = &es8326_volatile_table,
+       .volatile_reg = es8326_volatile_register,
        .cache_type = REGCACHE_RBTREE,
 };
 
@@ -419,6 +386,38 @@ static int es8326_pcm_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction)
+{
+       struct snd_soc_component *component = dai->component;
+       struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
+       unsigned int offset_l, offset_r;
+
+       if (mute) {
+               regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+               regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
+                               ES8326_MUTE_MASK, ES8326_MUTE);
+               regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xf0);
+       } else {
+               if (!es8326->calibrated) {
+                       regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_FORCE_CAL);
+                       msleep(30);
+                       regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+                       regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l);
+                       regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r);
+                       regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+                       regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l);
+                       regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
+                       es8326->calibrated = true;
+               }
+               regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa0);
+               regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80);
+               regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_ON);
+               regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE,
+                               ES8326_MUTE_MASK, ~(ES8326_MUTE));
+       }
+       return 0;
+}
+
 static int es8326_set_bias_level(struct snd_soc_component *codec,
                                 enum snd_soc_bias_level level)
 {
@@ -430,15 +429,17 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
                ret = clk_prepare_enable(es8326->mclk);
                if (ret)
                        return ret;
-               regmap_write(es8326->regmap, ES8326_RESET, ES8326_PWRUP_SEQ_EN);
-               regmap_write(es8326->regmap, ES8326_INTOUT_IO, 0x45);
+
+               regmap_write(es8326->regmap, ES8326_RESET, 0x9f);
+               msleep(20);
+               regmap_update_bits(es8326->regmap, ES8326_DAC_DSM, 0x01, 0x00);
+               regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
                regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
                            (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
-               regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
-               regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
-               regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x02);
+               regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
                regmap_write(es8326->regmap, ES8326_PGA_PDN, 0x40);
-               regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0xAA);
+               regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x00);
+               regmap_update_bits(es8326->regmap,  ES8326_CLK_CTL, 0x20, 0x20);
                regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
                break;
        case SND_SOC_BIAS_PREPARE:
@@ -447,15 +448,10 @@ static int es8326_set_bias_level(struct snd_soc_component *codec,
                break;
        case SND_SOC_BIAS_OFF:
                clk_disable_unprepare(es8326->mclk);
-               regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x11);
-               regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_OFF);
-               regmap_write(es8326->regmap, ES8326_PGA_PDN, 0xF8);
+               regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
                regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x00);
-               regmap_write(es8326->regmap, ES8326_INT_SOURCE, 0x08);
+               regmap_update_bits(es8326->regmap, ES8326_CLK_CTL, 0x20, 0x00);
                regmap_write(es8326->regmap, ES8326_SDINOUT1_IO, ES8326_IO_INPUT);
-               regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
-               regmap_write(es8326->regmap, ES8326_RESET,
-                            ES8326_CODEC_RESET | ES8326_PWRUP_SEQ_EN);
                break;
        }
 
@@ -469,6 +465,8 @@ static const struct snd_soc_dai_ops es8326_ops = {
        .hw_params = es8326_pcm_hw_params,
        .set_fmt = es8326_set_dai_fmt,
        .set_sysclk = es8326_set_dai_sysclk,
+       .mute_stream = es8326_mute,
+       .no_capture_mute = 1,
 };
 
 static struct snd_soc_dai_driver es8326_dai = {
@@ -532,13 +530,14 @@ static void es8326_jack_button_handler(struct work_struct *work)
                return;
 
        mutex_lock(&es8326->lock);
-       iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+       iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
        switch (iface) {
        case 0x93:
                /* pause button detected */
                cur_button = SND_JACK_BTN_0;
                break;
        case 0x6f:
+       case 0x4b:
                /* button volume up */
                cur_button = SND_JACK_BTN_1;
                break;
@@ -547,6 +546,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
                cur_button = SND_JACK_BTN_2;
                break;
        case 0x1e:
+       case 0xe2:
                /* button released or not pressed */
                cur_button = 0;
                break;
@@ -556,20 +556,20 @@ static void es8326_jack_button_handler(struct work_struct *work)
 
        if ((prev_button == cur_button) && (cur_button != 0)) {
                press_count++;
-               if (press_count > 10) {
-                       /* report a press every 500ms */
+               if (press_count > 3) {
+                       /* report a press every 120ms */
                        snd_soc_jack_report(es8326->jack, cur_button,
                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2);
                        press_count = 0;
                }
                button_to_report = cur_button;
                queue_delayed_work(system_wq, &es8326->button_press_work,
-                                  msecs_to_jiffies(50));
+                                  msecs_to_jiffies(35));
        } else if (prev_button != cur_button) {
                /* mismatch, detect again */
                prev_button = cur_button;
                queue_delayed_work(system_wq, &es8326->button_press_work,
-                                  msecs_to_jiffies(50));
+                                  msecs_to_jiffies(35));
        } else {
                /* released or no pressed */
                if (button_to_report != 0) {
@@ -591,34 +591,98 @@ static void es8326_jack_detect_handler(struct work_struct *work)
        unsigned int iface;
 
        mutex_lock(&es8326->lock);
-       iface = snd_soc_component_read(comp, ES8326_HP_DETECT);
+       iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
        dev_dbg(comp->dev, "gpio flag %#04x", iface);
+
+       if (es8326->jack_remove_retry == 1) {
+               if (iface & ES8326_HPINSERT_FLAG)
+                       es8326->jack_remove_retry = 2;
+               else
+                       es8326->jack_remove_retry = 0;
+
+               dev_dbg(comp->dev, "remove event check, set HPJACK_POL normal, cnt = %d\n",
+                               es8326->jack_remove_retry);
+               /*
+                * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
+                */
+               regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
+                                       ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
+                                       ~es8326->jack_pol : es8326->jack_pol));
+               goto exit;
+       }
+
        if ((iface & ES8326_HPINSERT_FLAG) == 0) {
                /* Jack unplugged or spurious IRQ */
-               dev_dbg(comp->dev, "No headset detected");
+               dev_dbg(comp->dev, "No headset detected\n");
+               es8326_disable_micbias(es8326->component);
                if (es8326->jack->status & SND_JACK_HEADPHONE) {
+                       dev_dbg(comp->dev, "Report hp remove event\n");
                        snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
-                       snd_soc_component_write(comp, ES8326_ADC1_SRC, es8326->mic2_src);
-                       es8326_disable_micbias(comp);
+                       /* mute adc when mic path switch */
+                       regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33);
+                       regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44);
+                       regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66);
+                       es8326->hp = 0;
+               }
+               regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+               /*
+                * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event
+                */
+               if (es8326->jack_remove_retry == 0) {
+                       es8326->jack_remove_retry = 1;
+                       dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n",
+                                       es8326->jack_remove_retry);
+                       regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
+                                       ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
+                                       es8326->jack_pol : ~es8326->jack_pol));
+
+               } else {
+                       es8326->jack_remove_retry = 0;
                }
        } else if ((iface & ES8326_HPINSERT_FLAG) == ES8326_HPINSERT_FLAG) {
+               es8326->jack_remove_retry = 0;
+               if (es8326->hp == 0) {
+                       dev_dbg(comp->dev, "First insert, start OMTP/CTIA type check\n");
+                       /*
+                        * set auto-check mode, then restart jack_detect_work after 100ms.
+                        * Don't report jack status.
+                        */
+                       regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x01);
+                       usleep_range(50000, 70000);
+                       regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE, 0x03, 0x00);
+                       queue_delayed_work(system_wq, &es8326->jack_detect_work,
+                                       msecs_to_jiffies(100));
+                       es8326->hp = 1;
+                       goto exit;
+               }
                if (es8326->jack->status & SND_JACK_HEADSET) {
                        /* detect button */
+                       dev_dbg(comp->dev, "button pressed\n");
                        queue_delayed_work(system_wq, &es8326->button_press_work, 10);
+                       goto exit;
+               }
+               if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
+                       dev_dbg(comp->dev, "Headphone detected\n");
+                       snd_soc_jack_report(es8326->jack,
+                                       SND_JACK_HEADPHONE, SND_JACK_HEADSET);
                } else {
-                       if ((iface & ES8326_HPBUTTON_FLAG) == 0x00) {
-                               dev_dbg(comp->dev, "Headset detected");
-                               snd_soc_jack_report(es8326->jack,
-                                                   SND_JACK_HEADSET, SND_JACK_HEADSET);
-                               snd_soc_component_write(comp,
-                                                       ES8326_ADC1_SRC, es8326->mic1_src);
-                       } else {
-                               dev_dbg(comp->dev, "Headphone detected");
-                               snd_soc_jack_report(es8326->jack,
-                                                   SND_JACK_HEADPHONE, SND_JACK_HEADSET);
-                       }
+                       dev_dbg(comp->dev, "Headset detected\n");
+                       snd_soc_jack_report(es8326->jack,
+                                       SND_JACK_HEADSET, SND_JACK_HEADSET);
+
+                       regmap_write(es8326->regmap, ES8326_ADC_SCALE, 0x33);
+                       regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+                                       0x08, 0x08);
+                       regmap_update_bits(es8326->regmap, ES8326_PGAGAIN,
+                                       0x80, 0x80);
+                       regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x00);
+                       regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x00);
+                       regmap_update_bits(es8326->regmap, ES8326_PGA_PDN,
+                                       0x08, 0x00);
+                       usleep_range(10000, 15000);
                }
        }
+exit:
        mutex_unlock(&es8326->lock);
 }
 
@@ -637,51 +701,138 @@ static irqreturn_t es8326_irq(int irq, void *dev_id)
                                   msecs_to_jiffies(10));
        else
                queue_delayed_work(system_wq, &es8326->jack_detect_work,
-                                  msecs_to_jiffies(300));
+                                  msecs_to_jiffies(600));
 
 out:
        return IRQ_HANDLED;
 }
 
-static int es8326_resume(struct snd_soc_component *component)
+static int es8326_calibrate(struct snd_soc_component *component)
 {
        struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
        unsigned int reg;
+       unsigned int offset_l, offset_r;
+
+       regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
+       es8326->version = reg;
+
+       if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) {
+               dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n");
+               regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0);
+               regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x01);
+               regmap_write(es8326->regmap, ES8326_CLK_DLL, 0x30);
+               regmap_write(es8326->regmap, ES8326_CLK_MUX, 0xed);
+               regmap_write(es8326->regmap, ES8326_CLK_TRI, 0xc1);
+               regmap_write(es8326->regmap, ES8326_DAC_MUTE, 0x03);
+               regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7f);
+               regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x33);
+               regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x88);
+               regmap_write(es8326->regmap, ES8326_HP_VOL, 0x80);
+               regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+               regmap_write(es8326->regmap, ES8326_RESET, 0xc0);
+               usleep_range(15000, 20000);
+
+               regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, ES8326_HP_OFF);
+               regmap_read(es8326->regmap, ES8326_CSM_MUTE_STA, &reg);
+               if ((reg & 0xf0) != 0x40)
+                       msleep(50);
+
+               regmap_write(es8326->regmap, ES8326_HP_CAL, 0xd4);
+               msleep(200);
+               regmap_write(es8326->regmap, ES8326_HP_CAL, 0x4d);
+               msleep(200);
+               regmap_write(es8326->regmap, ES8326_HP_CAL, ES8326_HP_OFF);
+               regmap_read(es8326->regmap, ES8326_HPL_OFFSET_INI, &offset_l);
+               regmap_read(es8326->regmap, ES8326_HPR_OFFSET_INI, &offset_r);
+               regmap_write(es8326->regmap, ES8326_HP_OFFSET_CAL, 0x8c);
+               regmap_write(es8326->regmap, ES8326_HPL_OFFSET_INI, offset_l);
+               regmap_write(es8326->regmap, ES8326_HPR_OFFSET_INI, offset_r);
+               regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
+
+               es8326->calibrated = true;
+       }
+
+       return 0;
+}
+
+static int es8326_resume(struct snd_soc_component *component)
+{
+       struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
 
        regcache_cache_only(es8326->regmap, false);
        regcache_sync(es8326->regmap);
 
+       /* reset internal clock state */
+       regmap_write(es8326->regmap, ES8326_RESET, 0x1f);
+       regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
+       usleep_range(10000, 15000);
+       regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
+       /* set headphone default type and detect pin */
+       regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x81);
+       regmap_write(es8326->regmap, ES8326_CLK_RESAMPLE, 0x05);
+
+       /* set internal oscillator as clock source of headpone cp */
+       regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x84);
        regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_ON);
-       /* Two channel ADC */
-       regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x02);
+       /* clock manager reset release */
+       regmap_write(es8326->regmap, ES8326_RESET, 0x17);
+       /* set headphone detection as half scan mode */
+       regmap_write(es8326->regmap, ES8326_HP_MISC, 0x08);
+       regmap_write(es8326->regmap, ES8326_PULLUP_CTL, 0x00);
+
+       /* enable headphone driver */
+       regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa7);
+       usleep_range(2000, 5000);
+       regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xab);
+       usleep_range(2000, 5000);
+       regmap_write(es8326->regmap, ES8326_HP_DRIVER_REF, 0xbb);
+       usleep_range(2000, 5000);
+       regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xa1);
+
        regmap_write(es8326->regmap, ES8326_CLK_INV, 0x00);
-       regmap_write(es8326->regmap, ES8326_CLK_DIV_CPC, 0x1F);
-       regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xC8);
-       regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x88);
-       regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x20);
+       regmap_write(es8326->regmap, ES8326_CLK_VMIDS1, 0xc4);
+       regmap_write(es8326->regmap, ES8326_CLK_VMIDS2, 0x81);
+       regmap_write(es8326->regmap, ES8326_CLK_CAL_TIME, 0x00);
+       /* calibrate for B version */
+       es8326_calibrate(component);
+       /* turn off headphone out */
+       regmap_write(es8326->regmap, ES8326_HP_CAL, 0x00);
+       /* set ADC and DAC in low power mode */
+       regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
+
+       /* force micbias on */
+       regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0x4f);
        regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x08);
-       regmap_write(es8326->regmap, ES8326_DAC2HPMIX, 0x22);
-       regmap_write(es8326->regmap, ES8326_ADC1_SRC, es8326->mic1_src);
-       regmap_write(es8326->regmap, ES8326_ADC2_SRC, es8326->mic2_src);
-       regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0x88);
-       regmap_write(es8326->regmap, ES8326_HP_DET,
-                    ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol);
-       regmap_write(es8326->regmap, ES8326_INT_SOURCE, es8326->interrupt_src);
-       regmap_write(es8326->regmap, ES8326_INTOUT_IO, es8326->interrupt_clk);
+       regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
+       /* select vdda as micbias source */
+       regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x23);
+       /* set dac dsmclip = 1 */
+       regmap_write(es8326->regmap, ES8326_DAC_DSM, 0x08);
+       regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15);
+
+       regmap_write(es8326->regmap, ES8326_INT_SOURCE,
+                   (ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
+       regmap_write(es8326->regmap, ES8326_INTOUT_IO,
+                    es8326->interrupt_clk);
+       regmap_write(es8326->regmap, ES8326_SDINOUT1_IO,
+                   (ES8326_IO_DMIC_CLK << ES8326_SDINOUT1_SHIFT));
+       regmap_write(es8326->regmap, ES8326_SDINOUT23_IO, ES8326_IO_INPUT);
+
+       regmap_write(es8326->regmap, ES8326_ANA_PDN, 0x3b);
        regmap_write(es8326->regmap, ES8326_RESET, ES8326_CSM_ON);
-       snd_soc_component_update_bits(component, ES8326_PGAGAIN,
-                                     ES8326_MIC_SEL_MASK, ES8326_MIC1_SEL);
+       regmap_update_bits(es8326->regmap, ES8326_PGAGAIN, ES8326_MIC_SEL_MASK,
+                          ES8326_MIC1_SEL);
 
-       regmap_read(es8326->regmap, ES8326_CHIP_VERSION, &reg);
-       if ((reg & ES8326_VERSION_B) == 1) {
-               regmap_write(es8326->regmap, ES8326_ANA_MICBIAS, 0xDD);
-               regmap_write(es8326->regmap, ES8326_ANA_VSEL, 0x7F);
-               regmap_write(es8326->regmap, ES8326_VMIDLOW, 0x0F);
-               /* enable button detect */
-               regmap_write(es8326->regmap, ES8326_HP_DRIVER, 0xA0);
-       }
+       regmap_update_bits(es8326->regmap, ES8326_DAC_MUTE, ES8326_MUTE_MASK,
+                          ES8326_MUTE);
 
-       es8326_irq(es8326->irq, es8326);
+       regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 |
+                       ((es8326->version == ES8326_VERSION_B) ?
+                       (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) :
+                       (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04)));
+
+       es8326->jack_remove_retry = 0;
+       es8326->hp = 0;
        return 0;
 }
 
@@ -691,11 +842,15 @@ static int es8326_suspend(struct snd_soc_component *component)
 
        cancel_delayed_work_sync(&es8326->jack_detect_work);
        es8326_disable_micbias(component);
-
+       es8326->calibrated = false;
        regmap_write(es8326->regmap, ES8326_CLK_CTL, ES8326_CLK_OFF);
        regcache_cache_only(es8326->regmap, true);
        regcache_mark_dirty(es8326->regmap);
 
+       /* reset register value to default */
+       regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x01);
+       usleep_range(1000, 3000);
+       regmap_write(es8326->regmap, ES8326_CSM_I2C_STA, 0x00);
        return 0;
 }
 
@@ -725,7 +880,7 @@ static int es8326_probe(struct snd_soc_component *component)
        ret = device_property_read_u8(component->dev, "everest,jack-pol", &es8326->jack_pol);
        if (ret != 0) {
                dev_dbg(component->dev, "jack-pol return %d", ret);
-               es8326->jack_pol = ES8326_HP_DET_BUTTON_POL | ES8326_HP_TYPE_OMTP;
+               es8326->jack_pol = ES8326_HP_TYPE_AUTO;
        }
        dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
 
@@ -756,7 +911,7 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component,
 
        mutex_lock(&es8326->lock);
        if (es8326->jd_inverted)
-               snd_soc_component_update_bits(component, ES8326_HP_DET,
+               snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
                                              ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
        es8326->jack = jack;
 
index 8e5ffe5ee10da3b6cbdbccea3ac726e46c9ac38f..90a08351d6acd043b42a6ebed574591a3defc6a0 100644 (file)
@@ -9,8 +9,6 @@
 #ifndef _ES8326_H
 #define _ES8326_H
 
-#define CONFIG_HHTECH_MINIPMP  1
-
 /* ES8326 register space */
 #define ES8326_RESET           0x00
 #define ES8326_CLK_CTL         0x01
 #define ES8326_DRC_RECOVERY    0x53
 #define ES8326_DRC_WINSIZE     0x54
 #define ES8326_HPJACK_TIMER    0x56
-#define ES8326_HP_DET          0x57
+#define ES8326_HPDET_TYPE      0x57
 #define ES8326_INT_SOURCE      0x58
 #define ES8326_INTOUT_IO       0x59
 #define ES8326_SDINOUT1_IO     0x5A
 #define ES8326_SDINOUT23_IO    0x5B
 #define ES8326_JACK_PULSE      0x5C
 
+#define ES8326_HP_MISC         0xF7
+#define ES8326_CTIA_OMTP_STA   0xF8
 #define ES8326_PULLUP_CTL      0xF9
-#define ES8326_HP_DETECT       0xFB
+#define ES8326_CSM_I2C_STA     0xFA
+#define ES8326_HPDET_STA       0xFB
+#define ES8326_CSM_MUTE_STA    0xFC
 #define ES8326_CHIP_ID1                0xFD
 #define ES8326_CHIP_ID2                0xFE
 #define ES8326_CHIP_VERSION    0xFF
@@ -94,6 +96,8 @@
 #define        ES8326_PWRUP_SEQ_EN     (1 << 5)
 #define ES8326_CODEC_RESET (0x0f << 0)
 #define ES8326_CSM_OFF (0 << 7)
+#define ES8326_MUTE_MASK (3 << 0)
+#define ES8326_MUTE (3 << 0)
 
 /* ES8326_CLK_CTL */
 #define ES8326_CLK_ON (0x7f << 0)
 #define ES8326_MIC2_SEL (1 << 5)
 
 /* ES8326_HP_CAL */
-#define ES8326_HPOR_SHIFT 4
+#define ES8326_HP_OFF 0
+#define ES8326_HP_FORCE_CAL ((1 << 7) | (1 << 3))
+#define ES8326_HP_ON ((7 << 4) | (7 << 0))
 
 /* ES8326_ADC1_SRC */
 #define ES8326_ADC1_SHIFT 0
 #define ES8326_ADC3_SHIFT 0
 #define ES8326_ADC4_SHIFT 3
 
-/* ES8326_HP_DET */
+/* ES8326_HPDET_TYPE */
 #define ES8326_HP_DET_SRC_PIN27 (1 << 5)
 #define ES8326_HP_DET_SRC_PIN9 (1 << 4)
 #define ES8326_HP_DET_JACK_POL (1 << 3)
 #define ES8326_HP_TYPE_AUTO    (1 << 0)
 #define ES8326_HP_TYPE_AUTO_INV        (0 << 0)
 
+/* ES8326_INT_SOURCE */
+#define ES8326_INT_SRC_DAC_MOZ (1 << 0)
+#define ES8326_INT_SRC_ADC_MOZ (1 << 1)
+#define ES8326_INT_SRC_BUTTON (1 << 2)
+#define ES8326_INT_SRC_PIN9 (1 << 3)
+#define ES8326_INT_SRC_PIN27 (1 << 4)
+
 /* ES8326_SDINOUT1_IO */
 #define ES8326_IO_INPUT        (0 << 0)
 #define ES8326_IO_SDIN_SLOT0 (1 << 0)
 #define ES8326_SDINOUT2_SHIFT 4
 #define ES8326_SDINOUT3_SHIFT 0
 
-/* ES8326_HP_DETECT */
+/* ES8326_HPDET_STA */
 #define ES8326_HPINSERT_FLAG (1 << 1)
 #define ES8326_HPBUTTON_FLAG (1 << 0)
 
 /* ES8326_CHIP_VERSION 0xFF */
-#define ES8326_VERSION_B (1 << 0)
+#define ES8326_VERSION (1 << 0)
+#define ES8326_VERSION_B (3 << 0)
 
 #endif
index d21f69f0534228de38d98d923c33d4b0c3c3bd90..13689e718d36fee41152fe688ea043f7aa333a31 100644 (file)
@@ -723,24 +723,6 @@ static u64 hdmi_codec_formats =
        SND_SOC_POSSIBLE_DAIFMT_LEFT_J  |
        SND_SOC_POSSIBLE_DAIFMT_AC97;
 
-static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
-       .startup        = hdmi_codec_startup,
-       .shutdown       = hdmi_codec_shutdown,
-       .hw_params      = hdmi_codec_hw_params,
-       .prepare        = hdmi_codec_prepare,
-       .set_fmt        = hdmi_codec_i2s_set_fmt,
-       .mute_stream    = hdmi_codec_mute,
-       .auto_selectable_formats        = &hdmi_codec_formats,
-       .num_auto_selectable_formats    = 1,
-};
-
-static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
-       .startup        = hdmi_codec_startup,
-       .shutdown       = hdmi_codec_shutdown,
-       .hw_params      = hdmi_codec_hw_params,
-       .mute_stream    = hdmi_codec_mute,
-};
-
 #define HDMI_RATES     (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
                         SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
                         SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
@@ -921,10 +903,31 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
+       .probe                          = hdmi_dai_probe,
+       .startup                        = hdmi_codec_startup,
+       .shutdown                       = hdmi_codec_shutdown,
+       .hw_params                      = hdmi_codec_hw_params,
+       .prepare                        = hdmi_codec_prepare,
+       .set_fmt                        = hdmi_codec_i2s_set_fmt,
+       .mute_stream                    = hdmi_codec_mute,
+       .pcm_new                        = hdmi_codec_pcm_new,
+       .auto_selectable_formats        = &hdmi_codec_formats,
+       .num_auto_selectable_formats    = 1,
+};
+
+static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
+       .probe          = hdmi_dai_spdif_probe,
+       .startup        = hdmi_codec_startup,
+       .shutdown       = hdmi_codec_shutdown,
+       .hw_params      = hdmi_codec_hw_params,
+       .mute_stream    = hdmi_codec_mute,
+       .pcm_new        = hdmi_codec_pcm_new,
+};
+
 static const struct snd_soc_dai_driver hdmi_i2s_dai = {
        .name = "i2s-hifi",
        .id = DAI_ID_I2S,
-       .probe = hdmi_dai_probe,
        .playback = {
                .stream_name = "I2S Playback",
                .channels_min = 2,
@@ -942,13 +945,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
                .sig_bits = 24,
        },
        .ops = &hdmi_codec_i2s_dai_ops,
-       .pcm_new = hdmi_codec_pcm_new,
 };
 
 static const struct snd_soc_dai_driver hdmi_spdif_dai = {
        .name = "spdif-hifi",
        .id = DAI_ID_SPDIF,
-       .probe = hdmi_dai_spdif_probe,
        .playback = {
                .stream_name = "SPDIF Playback",
                .channels_min = 2,
@@ -964,7 +965,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
                .formats = SPDIF_FORMATS,
        },
        .ops = &hdmi_codec_spdif_dai_ops,
-       .pcm_new = hdmi_codec_pcm_new,
 };
 
 static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
index 7c25acf6ff0dedff6070c870c85984b7b83e2f10..d1cea93bdb59846d5fc6c995818f54a5c76ff196 100644 (file)
@@ -301,7 +301,7 @@ static const struct regmap_config jz4740_codec_regmap_config = {
 
        .reg_defaults = jz4740_codec_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(jz4740_codec_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int jz4740_codec_probe(struct platform_device *pdev)
index 685ca95ef4a91495415314d10db94c3545f5362f..29197d34ec099dfaa77ad2f4f93b19c9067f9dee 100644 (file)
@@ -3537,25 +3537,25 @@ static int rx_macro_probe(struct platform_device *pdev)
 
        rx->macro = devm_clk_get_optional(dev, "macro");
        if (IS_ERR(rx->macro))
-               return PTR_ERR(rx->macro);
+               return dev_err_probe(dev, PTR_ERR(rx->macro), "unable to get macro clock\n");
 
        rx->dcodec = devm_clk_get_optional(dev, "dcodec");
        if (IS_ERR(rx->dcodec))
-               return PTR_ERR(rx->dcodec);
+               return dev_err_probe(dev, PTR_ERR(rx->dcodec), "unable to get dcodec clock\n");
 
        rx->mclk = devm_clk_get(dev, "mclk");
        if (IS_ERR(rx->mclk))
-               return PTR_ERR(rx->mclk);
+               return dev_err_probe(dev, PTR_ERR(rx->mclk), "unable to get mclk clock\n");
 
        if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
                rx->npl = devm_clk_get(dev, "npl");
                if (IS_ERR(rx->npl))
-                       return PTR_ERR(rx->npl);
+                       return dev_err_probe(dev, PTR_ERR(rx->npl), "unable to get npl clock\n");
        }
 
        rx->fsgen = devm_clk_get(dev, "fsgen");
        if (IS_ERR(rx->fsgen))
-               return PTR_ERR(rx->fsgen);
+               return dev_err_probe(dev, PTR_ERR(rx->fsgen), "unable to get fsgen clock\n");
 
        rx->pds = lpass_macro_pds_init(dev);
        if (IS_ERR(rx->pds))
index de978c3d70b7bb5940d535a6687276be968464c4..3e33418898e8260710c11b751ae6f52dc7ff0665 100644 (file)
@@ -1967,25 +1967,25 @@ static int tx_macro_probe(struct platform_device *pdev)
 
        tx->macro = devm_clk_get_optional(dev, "macro");
        if (IS_ERR(tx->macro))
-               return PTR_ERR(tx->macro);
+               return dev_err_probe(dev, PTR_ERR(tx->macro), "unable to get macro clock\n");
 
        tx->dcodec = devm_clk_get_optional(dev, "dcodec");
        if (IS_ERR(tx->dcodec))
-               return PTR_ERR(tx->dcodec);
+               return dev_err_probe(dev, PTR_ERR(tx->dcodec), "unable to get dcodec clock\n");
 
        tx->mclk = devm_clk_get(dev, "mclk");
        if (IS_ERR(tx->mclk))
-               return PTR_ERR(tx->mclk);
+               return dev_err_probe(dev, PTR_ERR(tx->mclk), "unable to get mclk clock\n");
 
        if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
                tx->npl = devm_clk_get(dev, "npl");
                if (IS_ERR(tx->npl))
-                       return PTR_ERR(tx->npl);
+                       return dev_err_probe(dev, PTR_ERR(tx->npl), "unable to get npl clock\n");
        }
 
        tx->fsgen = devm_clk_get(dev, "fsgen");
        if (IS_ERR(tx->fsgen))
-               return PTR_ERR(tx->fsgen);
+               return dev_err_probe(dev, PTR_ERR(tx->fsgen), "unable to get fsgen clock\n");
 
        tx->pds = lpass_macro_pds_init(dev);
        if (IS_ERR(tx->pds))
index 74724448da50bea65537fc52d0685725c8c627ad..b71ef03c4aef024b257a0d6ffea50cc556521458 100644 (file)
@@ -1457,15 +1457,15 @@ static int va_macro_probe(struct platform_device *pdev)
 
        va->macro = devm_clk_get_optional(dev, "macro");
        if (IS_ERR(va->macro))
-               return PTR_ERR(va->macro);
+               return dev_err_probe(dev, PTR_ERR(va->macro), "unable to get macro clock\n");
 
        va->dcodec = devm_clk_get_optional(dev, "dcodec");
        if (IS_ERR(va->dcodec))
-               return PTR_ERR(va->dcodec);
+               return dev_err_probe(dev, PTR_ERR(va->dcodec), "unable to get dcodec clock\n");
 
        va->mclk = devm_clk_get(dev, "mclk");
        if (IS_ERR(va->mclk))
-               return PTR_ERR(va->mclk);
+               return dev_err_probe(dev, PTR_ERR(va->mclk), "unable to get mclk clock\n");
 
        va->pds = lpass_macro_pds_init(dev);
        if (IS_ERR(va->pds))
index 8ba7dc89daaaa80bf8853101da0d930dac6de80e..ec6859ec0d38eca2e0db949e4cb1f87710a0c488 100644 (file)
@@ -2396,25 +2396,25 @@ static int wsa_macro_probe(struct platform_device *pdev)
 
        wsa->macro = devm_clk_get_optional(dev, "macro");
        if (IS_ERR(wsa->macro))
-               return PTR_ERR(wsa->macro);
+               return dev_err_probe(dev, PTR_ERR(wsa->macro), "unable to get macro clock\n");
 
        wsa->dcodec = devm_clk_get_optional(dev, "dcodec");
        if (IS_ERR(wsa->dcodec))
-               return PTR_ERR(wsa->dcodec);
+               return dev_err_probe(dev, PTR_ERR(wsa->dcodec), "unable to get dcodec clock\n");
 
        wsa->mclk = devm_clk_get(dev, "mclk");
        if (IS_ERR(wsa->mclk))
-               return PTR_ERR(wsa->mclk);
+               return dev_err_probe(dev, PTR_ERR(wsa->mclk), "unable to get mclk clock\n");
 
        if (flags & LPASS_MACRO_FLAG_HAS_NPL_CLOCK) {
                wsa->npl = devm_clk_get(dev, "npl");
                if (IS_ERR(wsa->npl))
-                       return PTR_ERR(wsa->npl);
+                       return dev_err_probe(dev, PTR_ERR(wsa->npl), "unable to get npl clock\n");
        }
 
        wsa->fsgen = devm_clk_get(dev, "fsgen");
        if (IS_ERR(wsa->fsgen))
-               return PTR_ERR(wsa->fsgen);
+               return dev_err_probe(dev, PTR_ERR(wsa->fsgen), "unable to get fsgen clock\n");
 
        base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
index b5c69bba0e4888fa21e55e0430893196cb5a3a51..a2cca3436c68ef14e6f2897cb53408a1be431c89 100644 (file)
@@ -160,35 +160,24 @@ static int max98363_io_init(struct sdw_slave *slave)
        struct max98363_priv *max98363 = dev_get_drvdata(dev);
        int ret, reg;
 
-       if (max98363->first_hw_init) {
-               regcache_cache_only(max98363->regmap, false);
+       regcache_cache_only(max98363->regmap, false);
+       if (max98363->first_hw_init)
                regcache_cache_bypass(max98363->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!max98363->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(dev, 3000);
-               pm_runtime_use_autosuspend(dev);
-
+       if (!max98363->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(dev);
-
-               pm_runtime_enable(dev);
-       }
-
        pm_runtime_get_noresume(dev);
 
        ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, &reg);
-       if (!ret) {
+       if (!ret)
                dev_info(dev, "Revision ID: %X\n", reg);
-               return ret;
-       }
+       else
+               goto out;
 
        if (max98363->first_hw_init) {
                regcache_cache_bypass(max98363->regmap, false);
@@ -198,10 +187,11 @@ static int max98363_io_init(struct sdw_slave *slave)
        max98363->first_hw_init = true;
        max98363->hw_init = true;
 
+out:
        pm_runtime_mark_last_busy(dev);
        pm_runtime_put_autosuspend(dev);
 
-       return 0;
+       return ret;
 }
 
 #define MAX98363_RATES SNDRV_PCM_RATE_8000_192000
@@ -409,6 +399,8 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
        max98363->regmap = regmap;
        max98363->slave = slave;
 
+       regcache_cache_only(max98363->regmap, true);
+
        max98363->hw_init = false;
        max98363->first_hw_init = false;
 
@@ -416,10 +408,26 @@ static int max98363_init(struct sdw_slave *slave, struct regmap *regmap)
        ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363,
                                              max98363_dai,
                                              ARRAY_SIZE(max98363_dai));
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+       return 0;
 }
 
 static int max98363_sdw_probe(struct sdw_slave *slave,
index df92242af960ee65af7e952bc0d68b8c76cb2981..b5cb951af57040b93a9ea9f01538c1bf23f599a9 100644 (file)
@@ -361,28 +361,17 @@ static int max98373_io_init(struct sdw_slave *slave)
        struct device *dev = &slave->dev;
        struct max98373_priv *max98373 = dev_get_drvdata(dev);
 
-       if (max98373->first_hw_init) {
-               regcache_cache_only(max98373->regmap, false);
+       regcache_cache_only(max98373->regmap, false);
+       if (max98373->first_hw_init)
                regcache_cache_bypass(max98373->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!max98373->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(dev, 3000);
-               pm_runtime_use_autosuspend(dev);
-
+       if (!max98373->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(dev);
-
-               pm_runtime_enable(dev);
-       }
-
        pm_runtime_get_noresume(dev);
 
        /* Software Reset */
@@ -753,6 +742,8 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
        max98373->regmap = regmap;
        max98373->slave = slave;
 
+       regcache_cache_only(max98373->regmap, true);
+
        max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
        max98373->cache = devm_kcalloc(dev, max98373->cache_num,
                                       sizeof(*max98373->cache),
@@ -773,10 +764,27 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
        ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98373_sdw,
                                              max98373_sdw_dai,
                                              ARRAY_SIZE(max98373_sdw_dai));
-       if (ret < 0)
+       if (ret < 0) {
                dev_err(dev, "Failed to register codec: %d\n", ret);
+               return ret;
+       }
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       return 0;
 }
 
 static int max98373_update_status(struct sdw_slave *slave,
@@ -834,10 +842,7 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
 
 static int max98373_sdw_remove(struct sdw_slave *slave)
 {
-       struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
-
-       if (max98373->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index bdc508e23e59a3d0f374918c23b320236c43e373..922ce0dc4e609d0100357c6081f11058c9d4583c 100644 (file)
@@ -528,7 +528,8 @@ static int max98926_i2c_probe(struct i2c_client *i2c)
                                "Failed to allocate regmap: %d\n", ret);
                goto err_out;
        }
-       if (of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
+       if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode") ||
+           of_property_read_bool(i2c->dev.of_node, "interleave-mode"))
                max98926->interleave_mode = true;
 
        if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) {
index 0aaf2e6ae78d6a1719e103c498d6aa0597aaa0dd..776f23d38ac5053b092a8526dfa421e4d9e77011 100644 (file)
@@ -162,10 +162,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0021_PCM_MASTER_MODE,
-               MAX98927_PCM_MASTER_MODE_MASK,
-               mode);
+       regmap_update_bits(max98927->regmap, MAX98927_R0021_PCM_MASTER_MODE,
+                          MAX98927_PCM_MASTER_MODE_MASK, mode);
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
@@ -178,10 +176,8 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0020_PCM_MODE_CFG,
-               MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
-               invert);
+       regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+                          MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE, invert);
 
        /* interface format */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -207,36 +203,31 @@ static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
        if (!use_pdm) {
                /* pcm channel configuration */
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R0018_PCM_RX_EN_A,
-                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
-                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
+               regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+                                  MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+                                  MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
 
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R0020_PCM_MODE_CFG,
-                       MAX98927_PCM_MODE_CFG_FORMAT_MASK,
-                       format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
+                                  MAX98927_R0020_PCM_MODE_CFG,
+                                  MAX98927_PCM_MODE_CFG_FORMAT_MASK,
+                                  format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
 
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R003B_SPK_SRC_SEL,
-                       MAX98927_SPK_SRC_MASK, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL,
+                                  MAX98927_SPK_SRC_MASK, 0);
 
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R0035_PDM_RX_CTRL,
-                       MAX98927_PDM_RX_EN_MASK, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL,
+                                  MAX98927_PDM_RX_EN_MASK, 0);
        } else {
                /* pdm channel configuration */
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R0035_PDM_RX_CTRL,
-                       MAX98927_PDM_RX_EN_MASK, 1);
+               regmap_update_bits(max98927->regmap, MAX98927_R0035_PDM_RX_CTRL,
+                                  MAX98927_PDM_RX_EN_MASK, 1);
 
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R003B_SPK_SRC_SEL,
-                       MAX98927_SPK_SRC_MASK, 3);
+               regmap_update_bits(max98927->regmap, MAX98927_R003B_SPK_SRC_SEL,
+                                  MAX98927_SPK_SRC_MASK, 3);
 
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R0018_PCM_RX_EN_A,
-                       MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+                                  MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+                                  0);
        }
        return 0;
 }
@@ -283,9 +274,9 @@ static int max98927_set_clock(struct max98927_priv *max98927,
                        return -EINVAL;
                }
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R0021_PCM_MASTER_MODE,
-                       MAX98927_PCM_MASTER_MODE_MCLK_MASK,
-                       i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
+                                  MAX98927_R0021_PCM_MASTER_MODE,
+                                  MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+                                  i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
        }
 
        if (!max98927->tdm_mode) {
@@ -298,9 +289,8 @@ static int max98927_set_clock(struct max98927_priv *max98927,
                }
 
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R0022_PCM_CLK_SETUP,
-                       MAX98927_PCM_CLK_SETUP_BSEL_MASK,
-                       value);
+                                  MAX98927_R0022_PCM_CLK_SETUP,
+                                  MAX98927_PCM_CLK_SETUP_BSEL_MASK, value);
        }
        return 0;
 }
@@ -333,9 +323,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
 
        max98927->ch_size = snd_pcm_format_width(params_format(params));
 
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0020_PCM_MODE_CFG,
-               MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+       regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+                          MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
 
        dev_dbg(component->dev, "format supported %d",
                params_format(params));
@@ -375,27 +364,24 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
                goto err;
        }
        /* set DAI_SR to correct LRCLK frequency */
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0023_PCM_SR_SETUP1,
-               MAX98927_PCM_SR_SET1_SR_MASK,
-               sampling_rate);
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0024_PCM_SR_SETUP2,
-               MAX98927_PCM_SR_SET2_SR_MASK,
-               sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+       regmap_update_bits(max98927->regmap, MAX98927_R0023_PCM_SR_SETUP1,
+                          MAX98927_PCM_SR_SET1_SR_MASK, sampling_rate);
+       regmap_update_bits(max98927->regmap, MAX98927_R0024_PCM_SR_SETUP2,
+                          MAX98927_PCM_SR_SET2_SR_MASK,
+                          sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
 
        /* set sampling rate of IV */
        if (max98927->interleave_mode &&
            sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R0024_PCM_SR_SETUP2,
-                       MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
-                       sampling_rate - 3);
+                                  MAX98927_R0024_PCM_SR_SETUP2,
+                                  MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+                                  sampling_rate - 3);
        else
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R0024_PCM_SR_SETUP2,
-                       MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
-                       sampling_rate);
+                                  MAX98927_R0024_PCM_SR_SETUP2,
+                                  MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+                                  sampling_rate);
        return max98927_set_clock(max98927, params);
 err:
        return -EINVAL;
@@ -420,10 +406,8 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0022_PCM_CLK_SETUP,
-               MAX98927_PCM_CLK_SETUP_BSEL_MASK,
-               bsel);
+       regmap_update_bits(max98927->regmap, MAX98927_R0022_PCM_CLK_SETUP,
+                          MAX98927_PCM_CLK_SETUP_BSEL_MASK, bsel);
 
        /* Channel size configuration */
        switch (slot_width) {
@@ -442,33 +426,26 @@ static int max98927_dai_tdm_slot(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
-       regmap_update_bits(max98927->regmap,
-               MAX98927_R0020_PCM_MODE_CFG,
-               MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+       regmap_update_bits(max98927->regmap, MAX98927_R0020_PCM_MODE_CFG,
+                          MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
 
        /* Rx slot configuration */
-       regmap_write(max98927->regmap,
-               MAX98927_R0018_PCM_RX_EN_A,
-               rx_mask & 0xFF);
-       regmap_write(max98927->regmap,
-               MAX98927_R0019_PCM_RX_EN_B,
-               (rx_mask & 0xFF00) >> 8);
+       regmap_write(max98927->regmap, MAX98927_R0018_PCM_RX_EN_A,
+                    rx_mask & 0xFF);
+       regmap_write(max98927->regmap, MAX98927_R0019_PCM_RX_EN_B,
+                    (rx_mask & 0xFF00) >> 8);
 
        /* Tx slot configuration */
-       regmap_write(max98927->regmap,
-               MAX98927_R001A_PCM_TX_EN_A,
-               tx_mask & 0xFF);
-       regmap_write(max98927->regmap,
-               MAX98927_R001B_PCM_TX_EN_B,
-               (tx_mask & 0xFF00) >> 8);
+       regmap_write(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+                    tx_mask & 0xFF);
+       regmap_write(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+                    (tx_mask & 0xFF00) >> 8);
 
        /* Tx slot Hi-Z configuration */
-       regmap_write(max98927->regmap,
-               MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
-               ~tx_mask & 0xFF);
-       regmap_write(max98927->regmap,
-               MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
-               (~tx_mask & 0xFF00) >> 8);
+       regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+                    ~tx_mask & 0xFF);
+       regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+                    (~tx_mask & 0xFF00) >> 8);
 
        return 0;
 }
@@ -506,20 +483,16 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w,
                max98927->tdm_mode = false;
                break;
        case SND_SOC_DAPM_POST_PMU:
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R003A_AMP_EN,
-                       MAX98927_AMP_EN_MASK, 1);
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R00FF_GLOBAL_SHDN,
-                       MAX98927_GLOBAL_EN_MASK, 1);
+               regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN,
+                                  MAX98927_AMP_EN_MASK, 1);
+               regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN,
+                                  MAX98927_GLOBAL_EN_MASK, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R00FF_GLOBAL_SHDN,
-                       MAX98927_GLOBAL_EN_MASK, 0);
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R003A_AMP_EN,
-                       MAX98927_AMP_EN_MASK, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R00FF_GLOBAL_SHDN,
+                                  MAX98927_GLOBAL_EN_MASK, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R003A_AMP_EN,
+                                  MAX98927_AMP_EN_MASK, 0);
                break;
        default:
                return 0;
@@ -532,8 +505,8 @@ static const char * const max98927_switch_text[] = {
 
 static const struct soc_enum dai_sel_enum =
        SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
-               MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
-               3, max98927_switch_text);
+                       MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT, 3,
+                       max98927_switch_text);
 
 static const struct snd_kcontrol_new max98927_dai_controls =
        SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
@@ -543,17 +516,17 @@ static const struct snd_kcontrol_new max98927_vi_control =
 
 static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
        SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
-               0, 0, max98927_dac_event,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+                          0, 0, max98927_dac_event,
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
-               &max98927_dai_controls),
+                        &max98927_dai_controls),
        SND_SOC_DAPM_OUTPUT("BE_OUT"),
        SND_SOC_DAPM_AIF_OUT("Voltage Sense", "HiFi Capture",  0,
-               MAX98927_R003E_MEAS_EN, 0, 0),
+                            MAX98927_R003E_MEAS_EN, 0, 0),
        SND_SOC_DAPM_AIF_OUT("Current Sense", "HiFi Capture",  0,
-               MAX98927_R003E_MEAS_EN, 1, 0),
+                            MAX98927_R003E_MEAS_EN, 1, 0),
        SND_SOC_DAPM_SWITCH("VI Sense", SND_SOC_NOPM, 0, 0,
-               &max98927_vi_control),
+                           &max98927_vi_control),
        SND_SOC_DAPM_SIGGEN("VMON"),
        SND_SOC_DAPM_SIGGEN("IMON"),
 };
@@ -623,20 +596,19 @@ static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
                max98927_current_limit_text);
 
 static const struct snd_kcontrol_new max98927_snd_controls[] = {
-       SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
-               0, 6, 0,
-               max98927_spk_tlv),
+       SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN, 0, 6, 0,
+                      max98927_spk_tlv),
        SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
-               0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
-               max98927_digital_tlv),
+                      0, (1 << MAX98927_AMP_VOL_WIDTH) - 1, 0,
+                      max98927_digital_tlv),
        SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
-               MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
+                  MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
        SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
-               MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
-       SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
-               MAX98927_DRE_EN_SHIFT, 1, 0),
+                  MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
+       SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL, MAX98927_DRE_EN_SHIFT,
+                  1, 0),
        SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
-               MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+                  MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
        SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
        SOC_ENUM("Current Limit", max98927_current_limit),
 };
@@ -682,117 +654,82 @@ static int max98927_probe(struct snd_soc_component *component)
        max98927->component = component;
 
        /* Software Reset */
-       regmap_write(max98927->regmap,
-               MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+       regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
+                    MAX98927_SOFT_RESET);
 
        /* IV default slot configuration */
-       regmap_write(max98927->regmap,
-               MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
-               0xFF);
-       regmap_write(max98927->regmap,
-               MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
-               0xFF);
-       regmap_write(max98927->regmap,
-               MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
-               0x80);
-       regmap_write(max98927->regmap,
-               MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
-               0x1);
+       regmap_write(max98927->regmap, MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0xFF);
+       regmap_write(max98927->regmap, MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0xFF);
+       regmap_write(max98927->regmap, MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+                    0x80);
+       regmap_write(max98927->regmap, MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+                    0x1);
        /* Set inital volume (+13dB) */
-       regmap_write(max98927->regmap,
-               MAX98927_R0036_AMP_VOL_CTRL,
-               0x38);
-       regmap_write(max98927->regmap,
-               MAX98927_R003C_SPK_GAIN,
-               0x05);
+       regmap_write(max98927->regmap, MAX98927_R0036_AMP_VOL_CTRL, 0x38);
+       regmap_write(max98927->regmap, MAX98927_R003C_SPK_GAIN, 0x05);
        /* Enable DC blocker */
-       regmap_write(max98927->regmap,
-               MAX98927_R0037_AMP_DSP_CFG,
-               0x03);
+       regmap_write(max98927->regmap, MAX98927_R0037_AMP_DSP_CFG, 0x03);
        /* Enable IMON VMON DC blocker */
-       regmap_write(max98927->regmap,
-               MAX98927_R003F_MEAS_DSP_CFG,
-               0xF7);
+       regmap_write(max98927->regmap, MAX98927_R003F_MEAS_DSP_CFG, 0xF7);
        /* Boost Output Voltage & Current limit */
-       regmap_write(max98927->regmap,
-               MAX98927_R0040_BOOST_CTRL0,
-               0x1C);
-       regmap_write(max98927->regmap,
-               MAX98927_R0042_BOOST_CTRL1,
-               0x3E);
+       regmap_write(max98927->regmap, MAX98927_R0040_BOOST_CTRL0, 0x1C);
+       regmap_write(max98927->regmap, MAX98927_R0042_BOOST_CTRL1, 0x3E);
        /* Measurement ADC config */
-       regmap_write(max98927->regmap,
-               MAX98927_R0043_MEAS_ADC_CFG,
-               0x04);
-       regmap_write(max98927->regmap,
-               MAX98927_R0044_MEAS_ADC_BASE_MSB,
-               0x00);
-       regmap_write(max98927->regmap,
-               MAX98927_R0045_MEAS_ADC_BASE_LSB,
-               0x24);
+       regmap_write(max98927->regmap, MAX98927_R0043_MEAS_ADC_CFG, 0x04);
+       regmap_write(max98927->regmap, MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00);
+       regmap_write(max98927->regmap, MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x24);
        /* Brownout Level */
-       regmap_write(max98927->regmap,
-               MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
-               0x06);
+       regmap_write(max98927->regmap, MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+                    0x06);
        /* Envelope Tracking configuration */
-       regmap_write(max98927->regmap,
-               MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
-               0x08);
-       regmap_write(max98927->regmap,
-               MAX98927_R0086_ENV_TRACK_CTRL,
-               0x01);
-       regmap_write(max98927->regmap,
-               MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
-               0x10);
+       regmap_write(max98927->regmap, MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+                    0x08);
+       regmap_write(max98927->regmap, MAX98927_R0086_ENV_TRACK_CTRL, 0x01);
+       regmap_write(max98927->regmap, MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+                    0x10);
 
        /* voltage, current slot configuration */
-       regmap_write(max98927->regmap,
-               MAX98927_R001E_PCM_TX_CH_SRC_A,
-               (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
-               max98927->v_l_slot)&0xFF);
+       regmap_write(max98927->regmap, MAX98927_R001E_PCM_TX_CH_SRC_A,
+                    (max98927->i_l_slot << MAX98927_PCM_TX_CH_SRC_A_I_SHIFT | max98927->v_l_slot) & 0xFF);
 
        if (max98927->v_l_slot < 8) {
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
-                       1 << max98927->v_l_slot, 0);
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R001A_PCM_TX_EN_A,
-                       1 << max98927->v_l_slot,
-                       1 << max98927->v_l_slot);
+                                  MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+                                  1 << max98927->v_l_slot, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+                                  1 << max98927->v_l_slot,
+                                  1 << max98927->v_l_slot);
        } else {
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
-                       1 << (max98927->v_l_slot - 8), 0);
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R001B_PCM_TX_EN_B,
-                       1 << (max98927->v_l_slot - 8),
-                       1 << (max98927->v_l_slot - 8));
+                                  MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+                                  1 << (max98927->v_l_slot - 8), 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+                                  1 << (max98927->v_l_slot - 8),
+                                  1 << (max98927->v_l_slot - 8));
        }
 
        if (max98927->i_l_slot < 8) {
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
-                       1 << max98927->i_l_slot, 0);
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R001A_PCM_TX_EN_A,
-                       1 << max98927->i_l_slot,
-                       1 << max98927->i_l_slot);
+                                  MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+                                  1 << max98927->i_l_slot, 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R001A_PCM_TX_EN_A,
+                                  1 << max98927->i_l_slot,
+                                  1 << max98927->i_l_slot);
        } else {
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
-                       1 << (max98927->i_l_slot - 8), 0);
-               regmap_update_bits(max98927->regmap,
-                       MAX98927_R001B_PCM_TX_EN_B,
-                       1 << (max98927->i_l_slot - 8),
-                       1 << (max98927->i_l_slot - 8));
+                                  MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+                                  1 << (max98927->i_l_slot - 8), 0);
+               regmap_update_bits(max98927->regmap, MAX98927_R001B_PCM_TX_EN_B,
+                                  1 << (max98927->i_l_slot - 8),
+                                  1 << (max98927->i_l_slot - 8));
        }
 
        /* Set interleave mode */
        if (max98927->interleave_mode)
                regmap_update_bits(max98927->regmap,
-                       MAX98927_R001F_PCM_TX_CH_SRC_B,
-                       MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
-                       MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
+                                  MAX98927_R001F_PCM_TX_CH_SRC_B,
+                                  MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+                                  MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
        return 0;
 }
 
@@ -809,8 +746,8 @@ static int max98927_resume(struct device *dev)
 {
        struct max98927_priv *max98927 = dev_get_drvdata(dev);
 
-       regmap_write(max98927->regmap,
-               MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+       regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
+                    MAX98927_SOFT_RESET);
        regcache_cache_only(max98927->regmap, false);
        regcache_sync(max98927->regmap);
        return 0;
@@ -869,9 +806,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
        int reg = 0;
        struct max98927_priv *max98927 = NULL;
 
-       max98927 = devm_kzalloc(&i2c->dev,
-               sizeof(*max98927), GFP_KERNEL);
-
+       max98927 = devm_kzalloc(&i2c->dev, sizeof(*max98927), GFP_KERNEL);
        if (!max98927) {
                ret = -ENOMEM;
                return ret;
@@ -879,14 +814,14 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
        i2c_set_clientdata(i2c, max98927);
 
        /* update interleave mode info */
-       if (!of_property_read_u32(i2c->dev.of_node,
-               "interleave_mode", &value)) {
-               if (value > 0)
-                       max98927->interleave_mode = true;
-               else
-                       max98927->interleave_mode = false;
-       } else
-               max98927->interleave_mode = false;
+       if (of_property_read_bool(i2c->dev.of_node, "maxim,interleave-mode")) {
+               max98927->interleave_mode = true;
+       } else {
+               if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode",
+                                         &value))
+                       if (value > 0)
+                               max98927->interleave_mode = true;
+       }
 
        /* regmap initialization */
        max98927->regmap
@@ -897,9 +832,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
                        "Failed to allocate regmap: %d\n", ret);
                return ret;
        }
-       
-       max98927->reset_gpio 
-               = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_HIGH);
+
+       max98927->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset",
+                                                      GPIOD_OUT_HIGH);
        if (IS_ERR(max98927->reset_gpio)) {
                ret = PTR_ERR(max98927->reset_gpio);
                return dev_err_probe(&i2c->dev, ret, "failed to request GPIO reset pin");
@@ -912,8 +847,7 @@ static int max98927_i2c_probe(struct i2c_client *i2c)
        }
 
        /* Check Revision ID */
-       ret = regmap_read(max98927->regmap,
-               MAX98927_R01FF_REV_ID, &reg);
+       ret = regmap_read(max98927->regmap, MAX98927_R01FF_REV_ID, &reg);
        if (ret < 0) {
                dev_err(&i2c->dev,
                        "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
@@ -938,9 +872,8 @@ static void max98927_i2c_remove(struct i2c_client *i2c)
 {
        struct max98927_priv *max98927 = i2c_get_clientdata(i2c);
 
-       if (max98927->reset_gpio) {
+       if (max98927->reset_gpio)
                gpiod_set_value_cansleep(max98927->reset_gpio, 1);
-       }
 }
 
 static const struct i2c_device_id max98927_i2c_id[] = {
index cec90cf920ff75713202b9f113aab83ba6883a6e..9ca38181297559b9124655f3ae42ce2011a5d465 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 #include <linux/types.h>
-#include <linux/clk.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -1198,12 +1197,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       priv->mclk = devm_clk_get(dev, "mclk");
-       if (IS_ERR(priv->mclk)) {
-               dev_err(dev, "failed to get mclk\n");
-               return PTR_ERR(priv->mclk);
-       }
-
        for (i = 0; i < ARRAY_SIZE(supply_names); i++)
                priv->supplies[i].supply = supply_names[i];
 
@@ -1214,55 +1207,48 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = clk_prepare_enable(priv->mclk);
-       if (ret < 0) {
-               dev_err(dev, "failed to enable mclk %d\n", ret);
-               return ret;
-       }
-
        irq = platform_get_irq_byname(pdev, "mbhc_switch_int");
-       if (irq < 0) {
-               ret = irq;
-               goto err_disable_clk;
-       }
+       if (irq < 0)
+               return irq;
 
        ret = devm_request_threaded_irq(dev, irq, NULL,
                               pm8916_mbhc_switch_irq_handler,
                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
                               IRQF_ONESHOT,
                               "mbhc switch irq", priv);
-       if (ret)
+       if (ret) {
                dev_err(dev, "cannot request mbhc switch irq\n");
+               return ret;
+       }
 
        if (priv->mbhc_btn_enabled) {
                irq = platform_get_irq_byname(pdev, "mbhc_but_press_det");
-               if (irq < 0) {
-                       ret = irq;
-                       goto err_disable_clk;
-               }
+               if (irq < 0)
+                       return irq;
 
                ret = devm_request_threaded_irq(dev, irq, NULL,
                                       mbhc_btn_press_irq_handler,
                                       IRQF_TRIGGER_RISING |
                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                       "mbhc btn press irq", priv);
-               if (ret)
+               if (ret) {
                        dev_err(dev, "cannot request mbhc button press irq\n");
+                       return ret;
+               }
 
                irq = platform_get_irq_byname(pdev, "mbhc_but_rel_det");
-               if (irq < 0) {
-                       ret = irq;
-                       goto err_disable_clk;
-               }
+               if (irq < 0)
+                       return irq;
 
                ret = devm_request_threaded_irq(dev, irq, NULL,
                                       mbhc_btn_release_irq_handler,
                                       IRQF_TRIGGER_RISING |
                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                       "mbhc btn release irq", priv);
-               if (ret)
+               if (ret) {
                        dev_err(dev, "cannot request mbhc button release irq\n");
-
+                       return ret;
+               }
        }
 
        dev_set_drvdata(dev, priv);
@@ -1270,17 +1256,6 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
        return devm_snd_soc_register_component(dev, &pm8916_wcd_analog,
                                      pm8916_wcd_analog_dai,
                                      ARRAY_SIZE(pm8916_wcd_analog_dai));
-
-err_disable_clk:
-       clk_disable_unprepare(priv->mclk);
-       return ret;
-}
-
-static void pm8916_wcd_analog_spmi_remove(struct platform_device *pdev)
-{
-       struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev);
-
-       clk_disable_unprepare(priv->mclk);
 }
 
 static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
@@ -1296,7 +1271,6 @@ static struct platform_driver pm8916_wcd_analog_spmi_driver = {
                   .of_match_table = pm8916_wcd_analog_spmi_match_table,
        },
        .probe = pm8916_wcd_analog_spmi_probe,
-       .remove_new = pm8916_wcd_analog_spmi_remove,
 };
 
 module_platform_driver(pm8916_wcd_analog_spmi_driver);
index 9e0e4ddf128ecd3426e07cf8ac434b0312053332..5cb0de648bd3c30b8e2bd0fb8b97b7c9933221d0 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/int_log.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
@@ -38,7 +39,6 @@
 #define NAU_FVCO_MIN 90000000
 
 /* cross talk suppression detection */
-#define LOG10_MAGIC 646456993
 #define GAIN_AUGMENT 22500
 #define SIDETONE_BASE 207000
 
@@ -219,42 +219,6 @@ static const struct reg_sequence nau8825_regmap_patch[] = {
        { NAU8825_REG_MIC_BIAS, 0x0046 },
 };
 
-
-static const unsigned short logtable[256] = {
-       0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
-       0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
-       0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
-       0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
-       0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
-       0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
-       0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
-       0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
-       0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
-       0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
-       0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
-       0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
-       0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
-       0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
-       0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
-       0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
-       0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
-       0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
-       0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
-       0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
-       0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
-       0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
-       0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
-       0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
-       0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
-       0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
-       0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
-       0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
-       0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
-       0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
-       0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
-       0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
 /**
  * nau8825_sema_acquire - acquire the semaphore of nau88l25
  * @nau8825:  component to register the codec private data with
@@ -368,65 +332,14 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825,
 }
 
 /**
- * nau8825_intlog10_dec3 - Computes log10 of a value
- * the result is round off to 3 decimal. This function takes reference to
- * dvb-math. The source code locates as the following.
- * Linux/drivers/media/dvb-core/dvb_math.c
+ * nau8825_intlog10_dec3 - Computes log10 of a value, rounding the result to 3 decimal places.
  * @value:  input for log10
  *
  * return log10(value) * 1000
  */
 static u32 nau8825_intlog10_dec3(u32 value)
 {
-       u32 msb, logentry, significand, interpolation, log10val;
-       u64 log2val;
-
-       /* first detect the msb (count begins at 0) */
-       msb = fls(value) - 1;
-       /**
-        *      now we use a logtable after the following method:
-        *
-        *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
-        *      where x = msb and therefore 1 <= y < 2
-        *      first y is determined by shifting the value left
-        *      so that msb is bit 31
-        *              0x00231f56 -> 0x8C7D5800
-        *      the result is y * 2^31 -> "significand"
-        *      then the highest 9 bits are used for a table lookup
-        *      the highest bit is discarded because it's always set
-        *      the highest nine bits in our example are 100011000
-        *      so we would use the entry 0x18
-        */
-       significand = value << (31 - msb);
-       logentry = (significand >> 23) & 0xff;
-       /**
-        *      last step we do is interpolation because of the
-        *      limitations of the log table the error is that part of
-        *      the significand which isn't used for lookup then we
-        *      compute the ratio between the error and the next table entry
-        *      and interpolate it between the log table entry used and the
-        *      next one the biggest error possible is 0x7fffff
-        *      (in our example it's 0x7D5800)
-        *      needed value for next table entry is 0x800000
-        *      so the interpolation is
-        *      (error / 0x800000) * (logtable_next - logtable_current)
-        *      in the implementation the division is moved to the end for
-        *      better accuracy there is also an overflow correction if
-        *      logtable_next is 256
-        */
-       interpolation = ((significand & 0x7fffff) *
-               ((logtable[(logentry + 1) & 0xff] -
-               logtable[logentry]) & 0xffff)) >> 15;
-
-       log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation);
-       /**
-        *      log10(x) = log2(x) * log10(2)
-        */
-       log10val = (log2val * LOG10_MAGIC) >> 31;
-       /**
-        *      the result is round off to 3 decimal
-        */
-       return log10val / ((1 << 24) / 1000);
+       return intlog10(value) / ((1 << 24) / 1000);
 }
 
 /**
index 42bac8150f6282e1f46d47e81a75d7c9a27bfebf..d5285baad53a39d78c65e070e5fa851430ac3a64 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/acpi.h>
 #include <linux/regmap.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
index 38d9f69b08d6a64d387e4b38fbca887ae374cf6f..99ec0f9a8362678762dbb22feafd5081525f4a18 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/fs.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/module.h>
index 06800dad879812a14e9d5a58ba095e5bbc142570..44e7fe3c32da56e0f194da99d744c18cc970d2fe 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index b1e69fa290b2367dda49c614904a7fc84c5d11c0..919a1f25e584dd11c633520ce4d6782324f50a85 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
-#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
new file mode 100644 (file)
index 0000000..7295f44
--- /dev/null
@@ -0,0 +1,824 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt1017-sdca-sdw.c -- rt1017 SDCA ALSA SoC amplifier audio driver
+//
+// Copyright(c) 2023 Realtek Semiconductor Corp.
+//
+//
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt1017-sdca-sdw.h"
+
+static bool rt1017_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x2f55:
+       case 0x3206:
+       case 0xc000:
+       case 0xc001:
+       case 0xc022:
+       case 0xc030:
+       case 0xc104:
+       case 0xc10b:
+       case 0xc10c:
+       case 0xc110:
+       case 0xc112:
+       case 0xc300:
+       case 0xc301:
+       case 0xc318:
+       case 0xc325 ... 0xc328:
+       case 0xc331:
+       case 0xc340:
+       case 0xc350 ... 0xc351:
+       case 0xc500:
+       case 0xc502:
+       case 0xc504:
+       case 0xc507:
+       case 0xc509:
+       case 0xc510:
+       case 0xc512:
+       case 0xc518:
+       case 0xc51b:
+       case 0xc51d:
+       case 0xc520:
+       case 0xc540 ... 0xc542:
+       case 0xc550 ... 0xc552:
+       case 0xc600:
+       case 0xc602:
+       case 0xc612:
+       case 0xc622:
+       case 0xc632:
+       case 0xc642:
+       case 0xc651:
+       case 0xca00:
+       case 0xca09 ... 0xca0c:
+       case 0xca0e ... 0xca0f:
+       case 0xca10 ... 0xca11:
+       case 0xca16 ... 0xca17:
+       case 0xcb00:
+       case 0xcc00:
+       case 0xcc02:
+       case 0xd017:
+       case 0xd01a ... 0xd01c:
+       case 0xd101:
+       case 0xd20c:
+       case 0xd300:
+       case 0xd370:
+       case 0xd500:
+       case 0xd545 ... 0xd548:
+       case 0xd5a5 ... 0xd5a8:
+       case 0xd5aa ... 0xd5ad:
+       case 0xda04 ... 0xda07:
+       case 0xda09 ... 0xda0a:
+       case 0xda0c ... 0xda0f:
+       case 0xda11 ... 0xda14:
+       case 0xda16 ... 0xda19:
+       case 0xdab6 ... 0xdabb:
+       case 0xdb09 ... 0xdb0a:
+       case 0xdb14:
+
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+                       RT1017_SDCA_CTL_UDMPU_CLUSTER, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
+                       RT1017_SDCA_CTL_FU_MUTE, 0x01):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
+                       RT1017_SDCA_CTL_BYPASS, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29,
+                       RT1017_SDCA_CTL_PROT_STAT, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+                       RT1017_SDCA_CTL_FS_INDEX, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+                       RT1017_SDCA_CTL_REQ_POWER_STATE, 0):
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
+                       RT1017_SDCA_CTL_REQ_POWER_STATE, 0):
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt1017_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case 0x2f55:
+       case 0xc000:
+       case 0xc022:
+       case 0xc351:
+       case 0xc518:
+       case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_SAPU29,
+                       RT1017_SDCA_CTL_PROT_STAT, 0):
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct reg_sequence rt1017_blind_write[] = {
+       { 0xc001, 0x43 },
+       { 0x2f55, 0x02 },
+       { 0x3206, 0x80 },
+       { 0x005f, 0x7f },
+       { 0xd101, 0xa0 },
+       { 0xc112, 0xc0 },
+       { 0xc104, 0xaa },
+       { 0xc110, 0x59 },
+       { 0xc112, 0xc0 },
+       { 0xc340, 0x80 },
+       { 0xd017, 0x2c },
+       { 0xd01a, 0xc8 },
+       { 0xd01b, 0xcf },
+       { 0xd01c, 0x0c },
+       { 0xd20c, 0x14 },
+       { 0xdb09, 0x0f },
+       { 0xdb0a, 0x7f },
+       { 0xdb14, 0x03 },
+       { 0xcb00, 0x31 },
+       { 0xc318, 0x44 },
+       { 0xc325, 0xce },
+       { 0xc326, 0x13 },
+       { 0xc327, 0x5f },
+       { 0xc328, 0xf3 },
+       { 0xc350, 0xe1 },
+       { 0xc351, 0x88 },
+       { 0xc030, 0x14 },
+       { 0xc331, 0xf2 },
+       { 0xc551, 0x0f },
+       { 0xc552, 0xff },
+       { 0xc651, 0xc0 },
+       { 0xc550, 0xd0 },
+       { 0xc612, 0x00 },
+       { 0xc622, 0x00 },
+       { 0xc632, 0x00 },
+       { 0xc642, 0x00 },
+       { 0xc602, 0xf0 },
+       { 0xc600, 0xd0 },
+       { 0xcc02, 0x78 },
+       { 0xcc00, 0x90 },
+       { 0xc300, 0x3f },
+       { 0xc301, 0x1d },
+       { 0xc10b, 0x2e },
+       { 0xc10c, 0x36 },
+
+       { 0xd5a5, 0x00 },
+       { 0xd5a6, 0x6a },
+       { 0xd5a7, 0xaa },
+       { 0xd5a8, 0xaa },
+       { 0xd5aa, 0x00 },
+       { 0xd5ab, 0x16 },
+       { 0xd5ac, 0xdb },
+       { 0xd5ad, 0x6d },
+       { 0xd545, 0x09 },
+       { 0xd546, 0x30 },
+       { 0xd547, 0xf0 },
+       { 0xd548, 0xf0 },
+       { 0xd500, 0x20 },
+       { 0xc504, 0x3f },
+       { 0xc540, 0x00 },
+       { 0xc541, 0x0a },
+       { 0xc542, 0x1a },
+       { 0xc512, 0x00 },
+       { 0xc520, 0x40 },
+       { 0xc51b, 0x7f },
+       { 0xc51d, 0x0f },
+       { 0xc500, 0x40 },
+       { 0xc502, 0xde },
+       { 0xc507, 0x05 },
+       { 0xc509, 0x05 },
+       { 0xc510, 0x40 },
+       { 0xc518, 0xc0 },
+       { 0xc500, 0xc0 },
+
+       { 0xda0c, 0x00 },
+       { 0xda0d, 0x0b },
+       { 0xda0e, 0x55 },
+       { 0xda0f, 0x55 },
+       { 0xda04, 0x00 },
+       { 0xda05, 0x51 },
+       { 0xda06, 0xeb },
+       { 0xda07, 0x85 },
+       { 0xca16, 0x0f },
+       { 0xca17, 0x00 },
+       { 0xda09, 0x5d },
+       { 0xda0a, 0xc0 },
+       { 0xda11, 0x26 },
+       { 0xda12, 0x66 },
+       { 0xda13, 0x66 },
+       { 0xda14, 0x66 },
+       { 0xda16, 0x79 },
+       { 0xda17, 0x99 },
+       { 0xda18, 0x99 },
+       { 0xda19, 0x99 },
+       { 0xca09, 0x00 },
+       { 0xca0a, 0x07 },
+       { 0xca0b, 0x89 },
+       { 0xca0c, 0x61 },
+       { 0xca0e, 0x00 },
+       { 0xca0f, 0x03 },
+       { 0xca10, 0xc4 },
+       { 0xca11, 0xb0 },
+       { 0xdab6, 0x00 },
+       { 0xdab7, 0x01 },
+       { 0xdab8, 0x00 },
+       { 0xdab9, 0x00 },
+       { 0xdaba, 0x00 },
+       { 0xdabb, 0x00 },
+       { 0xd017, 0x0e },
+       { 0xca00, 0xcd },
+       { 0xc022, 0x84 },
+};
+
+#define RT1017_MAX_REG_NUM 0x4108ffff
+
+static const struct regmap_config rt1017_sdca_regmap = {
+       .reg_bits = 32,
+       .val_bits = 8,
+       .readable_reg = rt1017_sdca_readable_register,
+       .volatile_reg = rt1017_sdca_volatile_register,
+       .max_register = RT1017_MAX_REG_NUM,
+       .reg_defaults = rt1017_sdca_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(rt1017_sdca_reg_defaults),
+       .cache_type = REGCACHE_MAPLE,
+       .use_single_read = true,
+       .use_single_write = true,
+};
+
+static int rt1017_sdca_read_prop(struct sdw_slave *slave)
+{
+       struct sdw_slave_prop *prop = &slave->prop;
+       int nval;
+       int i, j;
+       u32 bit;
+       unsigned long addr;
+       struct sdw_dpn_prop *dpn;
+
+       prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+       prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+
+       prop->paging_support = true;
+
+       /* first we need to allocate memory for set bits in port lists
+        * port = 1 for AMP playback
+        * port = 2 for IV capture
+        */
+       prop->source_ports = BIT(2); /* BITMAP: 00000100 */
+       prop->sink_ports = BIT(1);   /* BITMAP: 00000010 */
+
+       nval = hweight32(prop->source_ports);
+       prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
+               sizeof(*prop->src_dpn_prop), GFP_KERNEL);
+       if (!prop->src_dpn_prop)
+               return -ENOMEM;
+
+       i = 0;
+       dpn = prop->src_dpn_prop;
+       addr = prop->source_ports;
+       for_each_set_bit(bit, &addr, 32) {
+               dpn[i].num = bit;
+               dpn[i].type = SDW_DPN_FULL;
+               dpn[i].simple_ch_prep_sm = true;
+               dpn[i].ch_prep_timeout = 10;
+               i++;
+       }
+
+       /* do this again for sink now */
+       nval = hweight32(prop->sink_ports);
+       prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
+               sizeof(*prop->sink_dpn_prop), GFP_KERNEL);
+       if (!prop->sink_dpn_prop)
+               return -ENOMEM;
+
+       j = 0;
+       dpn = prop->sink_dpn_prop;
+       addr = prop->sink_ports;
+       for_each_set_bit(bit, &addr, 32) {
+               dpn[j].num = bit;
+               dpn[j].type = SDW_DPN_FULL;
+               dpn[j].simple_ch_prep_sm = true;
+               dpn[j].ch_prep_timeout = 10;
+               j++;
+       }
+
+       /* set the timeout values */
+       prop->clk_stop_timeout = 64;
+
+       return 0;
+}
+
+static int rt1017_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+       struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+
+       if (rt1017->hw_init)
+               return 0;
+
+       if (rt1017->first_hw_init) {
+               regcache_cache_only(rt1017->regmap, false);
+               regcache_cache_bypass(rt1017->regmap, true);
+       } else {
+               /*
+                * PM runtime is only enabled when a Slave reports as Attached
+                */
+
+               /* set autosuspend parameters */
+               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
+               pm_runtime_use_autosuspend(&slave->dev);
+
+               /* update count of parent 'active' children */
+               pm_runtime_set_active(&slave->dev);
+
+               /* make sure the device does not suspend immediately */
+               pm_runtime_mark_last_busy(&slave->dev);
+
+               pm_runtime_enable(&slave->dev);
+       }
+
+       pm_runtime_get_noresume(&slave->dev);
+
+       /* sw reset */
+       regmap_write(rt1017->regmap, 0xc000, 0x02);
+
+       /* initial settings - blind write */
+       regmap_multi_reg_write(rt1017->regmap, rt1017_blind_write,
+               ARRAY_SIZE(rt1017_blind_write));
+
+       if (rt1017->first_hw_init) {
+               regcache_cache_bypass(rt1017->regmap, false);
+               regcache_mark_dirty(rt1017->regmap);
+       } else
+               rt1017->first_hw_init = true;
+
+       /* Mark Slave initialization complete */
+       rt1017->hw_init = true;
+
+       pm_runtime_mark_last_busy(&slave->dev);
+       pm_runtime_put_autosuspend(&slave->dev);
+
+       dev_dbg(&slave->dev, "hw_init complete\n");
+       return 0;
+}
+
+static int rt1017_sdca_update_status(struct sdw_slave *slave,
+                               enum sdw_slave_status status)
+{
+       struct  rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev);
+
+       if (status == SDW_SLAVE_UNATTACHED)
+               rt1017->hw_init = false;
+
+       /*
+        * Perform initialization only if slave status is present and
+        * hw_init flag is false
+        */
+       if (rt1017->hw_init || status != SDW_SLAVE_ATTACHED)
+               return 0;
+
+       /* perform I/O transfers required for Slave initialization */
+       return rt1017_sdca_io_init(&slave->dev, slave);
+}
+
+static const char * const rt1017_rx_data_ch_select[] = {
+       "Bypass",
+       "CN1",
+       "CN2",
+       "CN3",
+       "CN4",
+       "(1+2)/2",
+       "(1+3)/2",
+       "(1+4)/2",
+       "(2+3)/2",
+       "(2+4)/2",
+       "(3+4)/2",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1017_rx_data_ch_enum,
+                       SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+                               RT1017_SDCA_CTL_UDMPU_CLUSTER, 0),
+                       0, rt1017_rx_data_ch_select);
+
+static const struct snd_kcontrol_new rt1017_sdca_controls[] = {
+       /* UDMPU Cluster Selection */
+       SOC_ENUM("RX Channel Select", rt1017_rx_data_ch_enum),
+};
+
+static const struct snd_kcontrol_new rt1017_sto_dac =
+       SOC_DAPM_SINGLE("Switch",
+               SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU, RT1017_SDCA_CTL_FU_MUTE, 0x1),
+               0, 1, 1);
+
+static int rt1017_sdca_pde23_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+       unsigned char ps0 = 0x0, ps3 = 0x3;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_write(rt1017->regmap,
+                       SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+                               RT1017_SDCA_CTL_REQ_POWER_STATE, 0),
+                               ps0);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_write(rt1017->regmap,
+                       SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+                               RT1017_SDCA_CTL_REQ_POWER_STATE, 0),
+                               ps3);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int rt1017_sdca_classd_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_update_bits(rt1017->regmap, RT1017_PWM_TRIM_1,
+                       RT1017_PWM_FREQ_CTL_SRC_SEL_MASK, RT1017_PWM_FREQ_CTL_SRC_SEL_REG);
+               regmap_write(rt1017->regmap, RT1017_CLASSD_INT_1, 0x10);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int rt1017_sdca_feedback_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x08);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(rt1017->regmap, 0xd017, 0x1f, 0x09);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt1017_sdca_dapm_widgets[] = {
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT_E("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0,
+               rt1017_sdca_feedback_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1017_sto_dac),
+
+       /* Output Lines */
+       SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
+               rt1017_sdca_classd_event, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_OUTPUT("SPO"),
+
+       SND_SOC_DAPM_SUPPLY("PDE23", SND_SOC_NOPM, 0, 0,
+               rt1017_sdca_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SIGGEN("I Gen"),
+       SND_SOC_DAPM_SIGGEN("V Gen"),
+};
+
+static const struct snd_soc_dapm_route rt1017_sdca_dapm_routes[] = {
+
+       { "DAC", "Switch", "DP1RX" },
+       { "CLASS D", NULL, "DAC" },
+       { "CLASS D", NULL, "PDE23" },
+       { "SPO", NULL, "CLASS D" },
+
+       { "I Sense", NULL, "I Gen" },
+       { "V Sense", NULL, "V Gen" },
+       { "I Sense", NULL, "PDE23" },
+       { "V Sense", NULL, "PDE23" },
+       { "DP2TX", NULL, "I Sense" },
+       { "DP2TX", NULL, "V Sense" },
+};
+
+static struct sdw_slave_ops rt1017_sdca_slave_ops = {
+       .read_prop = rt1017_sdca_read_prop,
+       .update_status = rt1017_sdca_update_status,
+};
+
+static int rt1017_sdca_component_probe(struct snd_soc_component *component)
+{
+       int ret;
+
+       ret = pm_runtime_resume(component->dev);
+       if (ret < 0 && ret != -EACCES)
+               return ret;
+
+       return 0;
+}
+
+static void rt1017_sdca_component_remove(struct snd_soc_component *component)
+{
+       struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+
+       regcache_cache_only(rt1017->regmap, true);
+}
+
+static const struct snd_soc_component_driver soc_sdca_component_rt1017 = {
+       .probe = rt1017_sdca_component_probe,
+       .remove = rt1017_sdca_component_remove,
+       .controls = rt1017_sdca_controls,
+       .num_controls = ARRAY_SIZE(rt1017_sdca_controls),
+       .dapm_widgets = rt1017_sdca_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt1017_sdca_dapm_widgets),
+       .dapm_routes = rt1017_sdca_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt1017_sdca_dapm_routes),
+       .endianness = 1,
+};
+
+static int rt1017_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+                               int direction)
+{
+       snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+       return 0;
+}
+
+static void rt1017_sdca_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+       struct sdw_stream_config stream_config;
+       struct sdw_port_config port_config;
+       enum sdw_data_direction direction;
+       struct sdw_stream_runtime *sdw_stream;
+       int retval, port, num_channels, ch_mask;
+       unsigned int sampling_rate;
+
+       dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+       sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+       if (!sdw_stream)
+               return -EINVAL;
+
+       if (!rt1017->sdw_slave)
+               return -EINVAL;
+
+       /* SoundWire specific configuration */
+       /* port 1 for playback */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               direction = SDW_DATA_DIR_RX;
+               port = 1;
+       } else {
+               direction = SDW_DATA_DIR_TX;
+               port = 2;
+       }
+
+       num_channels = params_channels(params);
+       ch_mask = (1 << num_channels) - 1;
+
+       stream_config.frame_rate = params_rate(params);
+       stream_config.ch_count = num_channels;
+       stream_config.bps = snd_pcm_format_width(params_format(params));
+       stream_config.direction = direction;
+
+       port_config.ch_mask = ch_mask;
+       port_config.num = port;
+
+       dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n",
+               params_rate(params), num_channels, snd_pcm_format_width(params_format(params)),
+               direction, ch_mask, port);
+
+       retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config,
+                               &port_config, 1, sdw_stream);
+       if (retval) {
+               dev_err(dai->dev, "Unable to configure port\n");
+               return retval;
+       }
+
+       /* sampling rate configuration */
+       switch (params_rate(params)) {
+       case 44100:
+               sampling_rate = RT1017_SDCA_RATE_44100HZ;
+               break;
+       case 48000:
+               sampling_rate = RT1017_SDCA_RATE_48000HZ;
+               break;
+       case 96000:
+               sampling_rate = RT1017_SDCA_RATE_96000HZ;
+               break;
+       case 192000:
+               sampling_rate = RT1017_SDCA_RATE_192000HZ;
+               break;
+       default:
+               dev_err(component->dev, "Rate %d is not supported\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       /* set sampling frequency */
+       regmap_write(rt1017->regmap,
+               SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+                       RT1017_SDCA_CTL_FS_INDEX, 0),
+               sampling_rate);
+
+       return 0;
+}
+
+static int rt1017_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component);
+       struct sdw_stream_runtime *sdw_stream =
+               snd_soc_dai_get_dma_data(dai, substream);
+
+       if (!rt1017->sdw_slave)
+               return -EINVAL;
+
+       sdw_stream_remove_slave(rt1017->sdw_slave, sdw_stream);
+       return 0;
+}
+
+static const struct snd_soc_dai_ops rt1017_sdca_ops = {
+       .hw_params      = rt1017_sdca_pcm_hw_params,
+       .hw_free        = rt1017_sdca_pcm_hw_free,
+       .set_stream     = rt1017_sdca_set_sdw_stream,
+       .shutdown       = rt1017_sdca_shutdown,
+};
+
+#define RT1017_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+                            SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+#define RT1017_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver rt1017_sdca_dai[] = {
+       {
+               .name = "rt1017-aif",
+               .playback = {
+                       .stream_name = "DP1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = RT1017_STEREO_RATES,
+                       .formats = RT1017_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "DP2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = RT1017_STEREO_RATES,
+                       .formats = RT1017_FORMATS,
+               },
+               .ops = &rt1017_sdca_ops,
+       },
+};
+
+static int rt1017_sdca_init(struct device *dev, struct regmap *regmap,
+                       struct sdw_slave *slave)
+{
+       struct rt1017_sdca_priv *rt1017;
+       int ret;
+
+       rt1017 = devm_kzalloc(dev, sizeof(*rt1017), GFP_KERNEL);
+       if (!rt1017)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, rt1017);
+       rt1017->sdw_slave = slave;
+       rt1017->regmap = regmap;
+
+       /*
+        * Mark hw_init to false
+        * HW init will be performed when device reports present
+        */
+       rt1017->hw_init = false;
+       rt1017->first_hw_init = false;
+
+       ret =  devm_snd_soc_register_component(dev,
+                               &soc_sdca_component_rt1017,
+                               rt1017_sdca_dai,
+                               ARRAY_SIZE(rt1017_sdca_dai));
+
+       return ret;
+}
+
+static int rt1017_sdca_sdw_probe(struct sdw_slave *slave,
+                               const struct sdw_device_id *id)
+{
+       struct regmap *regmap;
+
+       /* Regmap Initialization */
+       regmap = devm_regmap_init_sdw(slave, &rt1017_sdca_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return rt1017_sdca_init(&slave->dev, regmap, slave);
+}
+
+static int rt1017_sdca_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(&slave->dev);
+
+       if (rt1017->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
+static const struct sdw_device_id rt1017_sdca_id[] = {
+       SDW_SLAVE_ENTRY_EXT(0x025d, 0x1017, 0x3, 0x1, 0),
+       {},
+};
+MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id);
+
+static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev)
+{
+       struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+
+       if (!rt1017->hw_init)
+               return 0;
+
+       regcache_cache_only(rt1017->regmap, true);
+
+       return 0;
+}
+
+#define RT1017_PROBE_TIMEOUT 5000
+
+static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev)
+{
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
+       unsigned long time;
+
+       if (!rt1017->first_hw_init)
+               return 0;
+
+       if (!slave->unattach_request)
+               goto regmap_sync;
+
+       time = wait_for_completion_timeout(&slave->initialization_complete,
+                               msecs_to_jiffies(RT1017_PROBE_TIMEOUT));
+       if (!time) {
+               dev_err(&slave->dev, "Initialization not complete, timed out\n");
+               sdw_show_ping_status(slave->bus, true);
+
+               return -ETIMEDOUT;
+       }
+
+regmap_sync:
+       slave->unattach_request = 0;
+       regcache_cache_only(rt1017->regmap, false);
+       regcache_sync(rt1017->regmap);
+
+       return 0;
+}
+
+static const struct dev_pm_ops rt1017_sdca_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume)
+       SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt1017_sdca_sdw_driver = {
+       .driver = {
+               .name = "rt1017-sdca",
+               .owner = THIS_MODULE,
+               .pm = &rt1017_sdca_pm,
+       },
+       .probe = rt1017_sdca_sdw_probe,
+       .remove = rt1017_sdca_sdw_remove,
+       .ops = &rt1017_sdca_slave_ops,
+       .id_table = rt1017_sdca_id,
+};
+module_sdw_driver(rt1017_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT1017 driver SDCA SDW");
+MODULE_AUTHOR("Derek Fang <derek.fang@realtek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h
new file mode 100644 (file)
index 0000000..4932b5d
--- /dev/null
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt1017-sdca-sdw.h -- RT1017 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2023 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT1017_SDW_H__
+#define __RT1017_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/soc.h>
+
+/* RT1017 SDCA Control - function number */
+#define FUNC_NUM_SMART_AMP 0x04
+
+/* RT1017 SDCA entity */
+#define RT1017_SDCA_ENT_PDE23 0x31
+#define RT1017_SDCA_ENT_PDE22 0x33
+#define RT1017_SDCA_ENT_CS21 0x21
+#define RT1017_SDCA_ENT_SAPU29 0x29
+#define RT1017_SDCA_ENT_XU22 0x22
+#define RT1017_SDCA_ENT_FU 0x03
+#define RT1017_SDCA_ENT_UDMPU21 0x02
+
+/* RT1017 SDCA control */
+#define RT1017_SDCA_CTL_FS_INDEX 0x10
+#define RT1017_SDCA_CTL_REQ_POWER_STATE 0x01
+#define RT1017_SDCA_CTL_PROT_STAT 0x11
+#define RT1017_SDCA_CTL_BYPASS 0x01
+#define RT1017_SDCA_CTL_FU_MUTE 0x01
+#define RT1017_SDCA_CTL_FU_VOLUME 0x02
+#define RT1017_SDCA_CTL_UDMPU_CLUSTER 0x10
+
+
+#define RT1017_CLASSD_INT_1            0xd300
+#define RT1017_PWM_TRIM_1              0xd370
+
+
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_MASK       (0x3 << 2)
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_EFUSE      (0x2 << 2)
+#define RT1017_PWM_FREQ_CTL_SRC_SEL_REG                (0x0 << 2)
+
+enum {
+       RT1017_SDCA_RATE_44100HZ = 0x8,
+       RT1017_SDCA_RATE_48000HZ = 0x9,
+       RT1017_SDCA_RATE_96000HZ = 0xb,
+       RT1017_SDCA_RATE_192000HZ = 0xd,
+};
+
+struct rt1017_sdca_priv {
+       struct snd_soc_component *component;
+       struct regmap *regmap;
+       struct sdw_slave *sdw_slave;
+       struct sdw_bus_params params;
+       bool hw_init;
+       bool first_hw_init;
+};
+
+static const struct reg_default rt1017_sdca_reg_defaults[] = {
+       { 0x3206, 0x00 },
+       { 0xc001, 0x43 },
+       { 0xc030, 0x54 },
+       { 0xc104, 0x8a },
+       { 0xc10b, 0x2f },
+       { 0xc10c, 0x2f },
+       { 0xc110, 0x49 },
+       { 0xc112, 0x10 },
+       { 0xc300, 0xff },
+       { 0xc301, 0xdd },
+       { 0xc318, 0x40 },
+       { 0xc325, 0x00 },
+       { 0xc326, 0x00 },
+       { 0xc327, 0x00 },
+       { 0xc328, 0x02 },
+       { 0xc331, 0xb2 },
+       { 0xc340, 0x02 },
+       { 0xc350, 0x21 },
+       { 0xc500, 0x00 },
+       { 0xc502, 0x00 },
+       { 0xc504, 0x3f },
+       { 0xc507, 0x1f },
+       { 0xc509, 0x1f },
+       { 0xc510, 0x40 },
+       { 0xc512, 0x00 },
+       { 0xc518, 0x02 },
+       { 0xc51b, 0x7f },
+       { 0xc51d, 0x0f },
+       { 0xc520, 0x00 },
+       { 0xc540, 0x80 },
+       { 0xc541, 0x00 },
+       { 0xc542, 0x0a },
+       { 0xc550, 0x80 },
+       { 0xc551, 0x0f },
+       { 0xc552, 0xff },
+       { 0xc600, 0x10 },
+       { 0xc602, 0x83 },
+       { 0xc612, 0x40 },
+       { 0xc622, 0x40 },
+       { 0xc632, 0x40 },
+       { 0xc642, 0x40 },
+       { 0xc651, 0x00 },
+       { 0xca00, 0xc1 },
+       { 0xca09, 0x00 },
+       { 0xca0a, 0x51 },
+       { 0xca0b, 0xeb },
+       { 0xca0c, 0x85 },
+       { 0xca0e, 0x00 },
+       { 0xca0f, 0x10 },
+       { 0xca10, 0x62 },
+       { 0xca11, 0x4d },
+       { 0xca16, 0x0f },
+       { 0xca17, 0x00 },
+       { 0xcb00, 0x10 },
+       { 0xcc00, 0x10 },
+       { 0xcc02, 0x0b },
+       { 0xd017, 0x09 },
+       { 0xd01a, 0x00 },
+       { 0xd01b, 0x00 },
+       { 0xd01c, 0x00 },
+       { 0xd101, 0xa0 },
+       { 0xd20c, 0x14 },
+       { 0xd300, 0x0f },
+       { 0xd370, 0x18 },
+       { 0xd500, 0x00 },
+       { 0xd545, 0x0b },
+       { 0xd546, 0xf9 },
+       { 0xd547, 0xb2 },
+       { 0xd548, 0xa9 },
+       { 0xd5a5, 0x00 },
+       { 0xd5a6, 0x00 },
+       { 0xd5a7, 0x00 },
+       { 0xd5a8, 0x00 },
+       { 0xd5aa, 0x00 },
+       { 0xd5ab, 0x00 },
+       { 0xd5ac, 0x00 },
+       { 0xd5ad, 0x00 },
+       { 0xda04, 0x03 },
+       { 0xda05, 0x33 },
+       { 0xda06, 0x33 },
+       { 0xda07, 0x33 },
+       { 0xda09, 0x5d },
+       { 0xda0a, 0xc0 },
+       { 0xda0c, 0x00 },
+       { 0xda0d, 0x01 },
+       { 0xda0e, 0x5d },
+       { 0xda0f, 0x86 },
+       { 0xda11, 0x20 },
+       { 0xda12, 0x00 },
+       { 0xda13, 0x00 },
+       { 0xda14, 0x00 },
+       { 0xda16, 0x7f },
+       { 0xda17, 0xff },
+       { 0xda18, 0xff },
+       { 0xda19, 0xff },
+       { 0xdab6, 0x00 },
+       { 0xdab7, 0x01 },
+       { 0xdab8, 0x00 },
+       { 0xdab9, 0x01 },
+       { 0xdaba, 0x00 },
+       { 0xdabb, 0x01 },
+       { 0xdb09, 0x0f },
+       { 0xdb0a, 0xff },
+       { 0xdb14, 0x00 },
+
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+                       RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
+                       RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
+                       RT1017_SDCA_CTL_BYPASS, 0), 0x01 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+                       RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
+                       RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+       { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
+                       RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+};
+
+#endif /* __RT1017_SDW_H__ */
index fd55049920c190fc8741d2688fcbd3577fa0cd02..ceb8baa6a20d78f1d57e693c1ff168504495c3a1 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
-#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 59895131e6e02af8f9abb19220ffd8b67815b1be..80888cbcf49c9f2b0b3fe2c5950d5c16a1c911bf 100644 (file)
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
 #include <sound/core.h>
index f43520ca318740bd9577ab4823505bb6d8e3b0c2..63d4abf964d45cdc36938adb97b67ba8b98a4cdd 100644 (file)
@@ -52,6 +52,7 @@ static bool rt1308_volatile_register(struct device *dev, unsigned int reg)
        case 0x300a:
        case 0xc000:
        case 0xc710:
+       case 0xcf01:
        case 0xc860 ... 0xc863:
        case 0xc870 ... 0xc873:
                return true;
@@ -213,35 +214,28 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
 {
        struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
        int ret = 0;
-       unsigned int tmp;
+       unsigned int tmp, hibernation_flag;
 
        if (rt1308->hw_init)
                return 0;
 
-       if (rt1308->first_hw_init) {
-               regcache_cache_only(rt1308->regmap, false);
+       regcache_cache_only(rt1308->regmap, false);
+       if (rt1308->first_hw_init)
                regcache_cache_bypass(rt1308->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt1308->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt1308->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
+       regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag);
+       if ((hibernation_flag != 0x00) && rt1308->first_hw_init)
+               goto _preset_ready_;
+
        /* sw reset */
        regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0);
 
@@ -282,6 +276,12 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave)
        regmap_write(rt1308->regmap, 0xc100, 0xd7);
        regmap_write(rt1308->regmap, 0xc101, 0xd7);
 
+       /* apply BQ params */
+       rt1308_apply_bq_params(rt1308);
+
+       regmap_write(rt1308->regmap, 0xcf01, 0x01);
+
+_preset_ready_:
        if (rt1308->first_hw_init) {
                regcache_cache_bypass(rt1308->regmap, false);
                regcache_mark_dirty(rt1308->regmap);
@@ -626,6 +626,9 @@ static int rt1308_sdw_component_probe(struct snd_soc_component *component)
        rt1308->component = component;
        rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
 
+       if (!rt1308->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -688,6 +691,8 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
        rt1308->sdw_slave = slave;
        rt1308->regmap = regmap;
 
+       regcache_cache_only(rt1308->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -699,10 +704,27 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap,
                                &soc_component_sdw_rt1308,
                                rt1308_sdw_dai,
                                ARRAY_SIZE(rt1308_sdw_dai));
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 static int rt1308_sdw_probe(struct sdw_slave *slave,
@@ -715,17 +737,12 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt1308_sdw_init(&slave->dev, regmap, slave);
-
-       return 0;
+       return rt1308_sdw_init(&slave->dev, regmap, slave);
 }
 
 static int rt1308_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
-
-       if (rt1308->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 9d07756cda4079bf2510e118cea724b916769186..86afb429d4235460e7dccafceef43928136936aa 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
-#include <linux/of_gpio.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
index 721821d9e9af2abc4f95c32f5a3b00d36f605696..47511f70119ae3b1d810ce8561d6026ccbbd98da 100644 (file)
@@ -272,25 +272,16 @@ static int rt1316_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt1316->hw_init)
                return 0;
 
+       regcache_cache_only(rt1316->regmap, false);
        if (rt1316->first_hw_init) {
-               regcache_cache_only(rt1316->regmap, false);
                regcache_cache_bypass(rt1316->regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                *  PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
@@ -424,6 +415,15 @@ static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum,
        SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0,
        rt1316_rx_data_ch_select);
 
+static const char * const rt1316_dac_output_vol_select[] = {
+       "immediately",
+       "zero crossing",
+       "zero crossing with soft ramp",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt1316_dac_vol_ctl_enum,
+       0xc010, 6, rt1316_dac_output_vol_select);
+
 static const struct snd_kcontrol_new rt1316_snd_controls[] = {
 
        /* I2S Data Channel Selection */
@@ -442,6 +442,9 @@ static const struct snd_kcontrol_new rt1316_snd_controls[] = {
        /* IV mixer Control */
        SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1),
        SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1),
+
+       /* DAC Output Volume Control */
+       SOC_ENUM("DAC Output Vol Control", rt1316_dac_vol_ctl_enum),
 };
 
 static const struct snd_kcontrol_new rt1316_sto_dac =
@@ -595,6 +598,9 @@ static int rt1316_sdw_component_probe(struct snd_soc_component *component)
        rt1316->component = component;
        rt1316_sdw_parse_dt(rt1316, &rt1316->sdw_slave->dev);
 
+       if (!rt1316->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -662,6 +668,8 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
        rt1316->sdw_slave = slave;
        rt1316->regmap = regmap;
 
+       regcache_cache_only(rt1316->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -673,10 +681,27 @@ static int rt1316_sdw_init(struct device *dev, struct regmap *regmap,
                                &soc_component_sdw_rt1316,
                                rt1316_sdw_dai,
                                ARRAY_SIZE(rt1316_sdw_dai));
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 static int rt1316_sdw_probe(struct sdw_slave *slave,
@@ -694,10 +719,7 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
 
 static int rt1316_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
-
-       if (rt1316->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 16d750102c8c049ad5a6c842d2dd562326a2f934..ff364bde4a084943d78da479dc876f7b328eb02b 100644 (file)
@@ -408,25 +408,15 @@ static int rt1318_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt1318->hw_init)
                return 0;
 
+       regcache_cache_only(rt1318->regmap, false);
        if (rt1318->first_hw_init) {
-               regcache_cache_only(rt1318->regmap, false);
                regcache_cache_bypass(rt1318->regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                * PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
-
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
@@ -686,6 +676,9 @@ static int rt1318_sdw_component_probe(struct snd_soc_component *component)
 
        rt1318->component = component;
 
+       if (!rt1318->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        dev_dbg(&rt1318->sdw_slave->dev, "%s pm_runtime_resume, ret=%d", __func__, ret);
        if (ret < 0 && ret != -EACCES)
@@ -752,6 +745,8 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
        rt1318->sdw_slave = slave;
        rt1318->regmap = regmap;
 
+       regcache_cache_only(rt1318->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -763,8 +758,25 @@ static int rt1318_sdw_init(struct device *dev, struct regmap *regmap,
                                &soc_component_sdw_rt1318,
                                rt1318_sdw_dai,
                                ARRAY_SIZE(rt1318_sdw_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -784,10 +796,7 @@ static int rt1318_sdw_probe(struct sdw_slave *slave,
 
 static int rt1318_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(&slave->dev);
-
-       if (rt1318->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 362663abcb89e4eebca7268f89c146d40498034d..3ee6d85268ba59f7797e66483e407efaa3ce7a4d 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 #include <linux/regulator/consumer.h>
index b3aac2373357b68089a927668546a9fe22200574..43fc7814fddeb538968525a344ea78b2c3a20173 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/firmware.h>
-#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index eceed820978774835987d0bebb06d0e8813d62af..15e1a62b9e571053284e3a2e8e8466fd5faf290f 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
@@ -2571,7 +2570,7 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
                                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                        "rt5640", rt5640);
        if (ret) {
-               dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
+               dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
                rt5640_disable_jack_detect(component);
                return;
        }
@@ -2626,7 +2625,7 @@ static void rt5640_enable_hda_jack_detect(
                                        NULL, rt5640_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                                        "rt5640", rt5640);
        if (ret) {
-               dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
+               dev_warn(component->dev, "Failed to request IRQ %d: %d\n", rt5640->irq, ret);
                rt5640->irq = -ENXIO;
                return;
        }
@@ -2812,8 +2811,8 @@ static int rt5640_suspend(struct snd_soc_component *component)
        rt5640_reset(component);
        regcache_cache_only(rt5640->regmap, true);
        regcache_mark_dirty(rt5640->regmap);
-       if (gpio_is_valid(rt5640->ldo1_en))
-               gpio_set_value_cansleep(rt5640->ldo1_en, 0);
+       if (rt5640->ldo1_en)
+               gpiod_set_value_cansleep(rt5640->ldo1_en, 0);
 
        return 0;
 }
@@ -2822,8 +2821,8 @@ static int rt5640_resume(struct snd_soc_component *component)
 {
        struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
 
-       if (gpio_is_valid(rt5640->ldo1_en)) {
-               gpio_set_value_cansleep(rt5640->ldo1_en, 1);
+       if (rt5640->ldo1_en) {
+               gpiod_set_value_cansleep(rt5640->ldo1_en, 1);
                msleep(400);
        }
 
@@ -2986,22 +2985,6 @@ static const struct acpi_device_id rt5640_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
 #endif
 
-static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
-{
-       rt5640->ldo1_en = of_get_named_gpio(np, "realtek,ldo1-en-gpios", 0);
-       /*
-        * LDO1_EN is optional (it may be statically tied on the board).
-        * -ENOENT means that the property doesn't exist, i.e. there is no
-        * GPIO, so is not an error. Any other error code means the property
-        * exists, but could not be parsed.
-        */
-       if (!gpio_is_valid(rt5640->ldo1_en) &&
-                       (rt5640->ldo1_en != -ENOENT))
-               return rt5640->ldo1_en;
-
-       return 0;
-}
-
 static int rt5640_i2c_probe(struct i2c_client *i2c)
 {
        struct rt5640_priv *rt5640;
@@ -3015,12 +2998,16 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
                return -ENOMEM;
        i2c_set_clientdata(i2c, rt5640);
 
-       if (i2c->dev.of_node) {
-               ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
-               if (ret)
-                       return ret;
-       } else
-               rt5640->ldo1_en = -EINVAL;
+       rt5640->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+                                                 "realtek,ldo1-en",
+                                                 GPIOD_OUT_HIGH);
+       if (IS_ERR(rt5640->ldo1_en))
+               return PTR_ERR(rt5640->ldo1_en);
+
+       if (rt5640->ldo1_en) {
+               gpiod_set_consumer_name(rt5640->ldo1_en, "RT5640 LDO1_EN");
+               msleep(400);
+       }
 
        rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
        if (IS_ERR(rt5640->regmap)) {
@@ -3030,18 +3017,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
-       if (gpio_is_valid(rt5640->ldo1_en)) {
-               ret = devm_gpio_request_one(&i2c->dev, rt5640->ldo1_en,
-                                           GPIOF_OUT_INIT_HIGH,
-                                           "RT5640 LDO1_EN");
-               if (ret < 0) {
-                       dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
-                               rt5640->ldo1_en, ret);
-                       return ret;
-               }
-               msleep(400);
-       }
-
        regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
        if (val != RT5640_DEVICE_ID) {
                dev_err(&i2c->dev,
index 9847a1ae01f445348d0571bc6f9e9790949f69fe..94b9a502f7f9d24624c065909f629732e04fd378 100644 (file)
@@ -2138,7 +2138,7 @@ struct rt5640_priv {
        struct regmap *regmap;
        struct clk *mclk;
 
-       int ldo1_en; /* GPIO for LDO1_EN */
+       struct gpio_desc *ldo1_en; /* GPIO for LDO1_EN */
        int irq;
        int jd_gpio_irq;
        int sysclk;
index a506d940a2eadcd011506eb72cdd075be2492006..038d93e208838014a4158f45e49b7b6b603aa8e7 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
@@ -81,6 +80,7 @@ static const struct reg_sequence init_list[] = {
 
 static const struct reg_sequence rt5650_init_list[] = {
        {0xf6,  0x0100},
+       {RT5645_PWR_ANLG1, 0x02},
 };
 
 static const struct reg_default rt5645_reg[] = {
@@ -1697,6 +1697,9 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
                                regmap_write(rt5645->regmap, RT5645_PR_BASE +
                                        RT5645_MAMP_INT_REG2, 0xfc00);
                                snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
+                               snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+                                       RT5645_PWR_HP_L | RT5645_PWR_HP_R,
+                                       RT5645_PWR_HP_L | RT5645_PWR_HP_R);
                                msleep(90);
                        } else {
                                /* depop parameters */
@@ -1744,7 +1747,8 @@ static void hp_amp_power(struct snd_soc_component *component, int on)
                                snd_soc_component_write(component, RT5645_DEPOP_M2, 0x1140);
                                msleep(100);
                                snd_soc_component_write(component, RT5645_DEPOP_M1, 0x0001);
-
+                               snd_soc_component_update_bits(component, RT5645_PWR_ANLG1,
+                                       RT5645_PWR_HP_L | RT5645_PWR_HP_R, 0);
                        } else {
                                snd_soc_component_update_bits(component, RT5645_DEPOP_M1,
                                        RT5645_HP_SG_MASK |
@@ -3151,7 +3155,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
        unsigned int val;
 
        if (jack_insert) {
-               regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
+               regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0206);
 
                /* for jack type detect */
                snd_soc_dapm_force_enable_pin(dapm, "LDO2");
@@ -3196,6 +3200,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
                if (rt5645->pdata.level_trigger_irq)
                        regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
                                RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR);
+
+               regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06);
        } else { /* jack out */
                rt5645->jack_type = 0;
 
@@ -3258,6 +3264,22 @@ int rt5645_set_jack_detect(struct snd_soc_component *component,
 }
 EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
 
+static int rt5645_component_set_jack(struct snd_soc_component *component,
+       struct snd_soc_jack *hs_jack, void *data)
+{
+       struct snd_soc_jack *mic_jack = NULL;
+       struct snd_soc_jack *btn_jack = NULL;
+       int *type = (int *)data;
+
+       if (*type & SND_JACK_MICROPHONE)
+               mic_jack = hs_jack;
+       if (*type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+               SND_JACK_BTN_2 | SND_JACK_BTN_3))
+               btn_jack = hs_jack;
+
+       return rt5645_set_jack_detect(component, hs_jack, mic_jack, btn_jack);
+}
+
 static void rt5645_jack_detect_work(struct work_struct *work)
 {
        struct rt5645_priv *rt5645 =
@@ -3532,6 +3554,7 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = {
        .num_dapm_widgets       = ARRAY_SIZE(rt5645_dapm_widgets),
        .dapm_routes            = rt5645_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(rt5645_dapm_routes),
+       .set_jack               = rt5645_component_set_jack,
        .use_pmdown_time        = 1,
        .endianness             = 1,
 };
@@ -3987,13 +4010,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
 
        regmap_write(rt5645->regmap, RT5645_AD_DA_MIXER, 0x8080);
 
-       ret = regmap_register_patch(rt5645->regmap, init_list,
+       ret = regmap_multi_reg_write(rt5645->regmap, init_list,
                                    ARRAY_SIZE(init_list));
        if (ret != 0)
                dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
        if (rt5645->codec_type == CODEC_TYPE_RT5650) {
-               ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+               ret = regmap_multi_reg_write(rt5645->regmap, rt5650_init_list,
                                    ARRAY_SIZE(rt5650_init_list));
                if (ret != 0)
                        dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
@@ -4182,11 +4205,43 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
        regmap_write(rt5645->regmap, RT5645_RESET, 0);
 }
 
+static int __maybe_unused rt5645_sys_suspend(struct device *dev)
+{
+       struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+
+       del_timer_sync(&rt5645->btn_check_timer);
+       cancel_delayed_work_sync(&rt5645->jack_detect_work);
+       cancel_delayed_work_sync(&rt5645->rcclock_work);
+
+       regcache_cache_only(rt5645->regmap, true);
+       regcache_mark_dirty(rt5645->regmap);
+       return 0;
+}
+
+static int __maybe_unused rt5645_sys_resume(struct device *dev)
+{
+       struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+
+       regcache_cache_only(rt5645->regmap, false);
+       regcache_sync(rt5645->regmap);
+
+       if (rt5645->hp_jack) {
+               rt5645->jack_type = 0;
+               rt5645_jack_detect_work(&rt5645->jack_detect_work.work);
+       }
+       return 0;
+}
+
+static const struct dev_pm_ops rt5645_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume)
+};
+
 static struct i2c_driver rt5645_i2c_driver = {
        .driver = {
                .name = "rt5645",
                .of_match_table = of_match_ptr(rt5645_of_match),
                .acpi_match_table = ACPI_PTR(rt5645_acpi_match),
+               .pm = &rt5645_pm,
        },
        .probe = rt5645_i2c_probe,
        .remove = rt5645_i2c_remove,
index df6f0d769bbdd4d9ac2a9c047c2863891a7a7c44..a061028a16d82b812ee2b318c63c942a96546edd 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index eade087b2d8b74a0ff43d2421c72254f9cc1271f..0cecfd6024158d3f068e6773de24aafce87b8141 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
index 83c367af91dad4697dbc0ff3499a26dd739f8220..a39de4a7df002c99b3ee0b56e0b7c6060b9adaef 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
 #include <sound/core.h>
@@ -4472,6 +4471,8 @@ static void rt5665_remove(struct snd_soc_component *component)
        struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);
 
        regmap_write(rt5665->regmap, RT5665_RESET, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(rt5665->supplies), rt5665->supplies);
 }
 
 #ifdef CONFIG_PM
@@ -4657,9 +4658,6 @@ static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev)
        of_property_read_u32(dev->of_node, "realtek,jd-src",
                &rt5665->pdata.jd_src);
 
-       rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
-               "realtek,ldo1-en-gpios", 0);
-
        return 0;
 }
 
@@ -4793,10 +4791,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
-       if (gpio_is_valid(rt5665->pdata.ldo1_en)) {
-               if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en,
-                                         GPIOF_OUT_INIT_HIGH, "rt5665"))
-                       dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+
+       rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+                                                       "realtek,ldo1-en",
+                                                       GPIOD_OUT_HIGH);
+       if (IS_ERR(rt5665->gpiod_ldo1_en)) {
+               dev_err(&i2c->dev, "Failed gpio request ldo1_en\n");
+               return PTR_ERR(rt5665->gpiod_ldo1_en);
        }
 
        /* Sleep for 300 ms miniumum */
index f04c810fd7102f2f2623daab65ecd558c52a23db..4623b3e62487064719175b4f2f8f375b758c26c2 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
 #include <sound/core.h>
@@ -43,6 +42,7 @@ static const char *rt5668_supply_names[RT5668_NUM_SUPPLIES] = {
 struct rt5668_priv {
        struct snd_soc_component *component;
        struct rt5668_platform_data pdata;
+       struct gpio_desc *ldo1_en;
        struct regmap *regmap;
        struct snd_soc_jack *hs_jack;
        struct regulator_bulk_data supplies[RT5668_NUM_SUPPLIES];
@@ -2393,9 +2393,6 @@ static int rt5668_parse_dt(struct rt5668_priv *rt5668, struct device *dev)
        of_property_read_u32(dev->of_node, "realtek,jd-src",
                &rt5668->pdata.jd_src);
 
-       rt5668->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
-               "realtek,ldo1-en-gpios", 0);
-
        return 0;
 }
 
@@ -2497,10 +2494,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
-       if (gpio_is_valid(rt5668->pdata.ldo1_en)) {
-               if (devm_gpio_request_one(&i2c->dev, rt5668->pdata.ldo1_en,
-                                         GPIOF_OUT_INIT_HIGH, "rt5668"))
-                       dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+       rt5668->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+                                                 "realtek,ldo1-en",
+                                                 GPIOD_OUT_HIGH);
+       if (IS_ERR(rt5668->ldo1_en)) {
+               dev_err(&i2c->dev, "Fail gpio request ldo1_en\n");
+               return PTR_ERR(rt5668->ldo1_en);
        }
 
        /* Sleep for 300 ms miniumum */
index ad14d18860fc3b92d64d4e5f67405f4891e28f4c..0e70a3ab42b5084d7cb0d5f931a0f2d0a384b6a8 100644 (file)
@@ -6,23 +6,21 @@
  * Author: Oder Chiou <oder_chiou@realtek.com>
  */
 
-#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
 #include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
-#include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
-#include <linux/firmware.h>
-#include <linux/of_device.h>
-#include <linux/property.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/irqdomain.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -4717,50 +4715,34 @@ static int rt5677_set_bias_level(struct snd_soc_component *component,
        return 0;
 }
 
+static int rt5677_update_gpio_bits(struct rt5677_priv *rt5677, unsigned offset, int m, int v)
+{
+       unsigned int bank = offset / 5;
+       unsigned int shift = (offset % 5) * 3;
+       unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2;
+
+       return regmap_update_bits(rt5677->regmap, reg, m << shift, v << shift);
+}
+
 #ifdef CONFIG_GPIOLIB
 static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+       int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO;
+       int m = RT5677_GPIOx_OUT_MASK;
 
-       switch (offset) {
-       case RT5677_GPIO1 ... RT5677_GPIO5:
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
-                       0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1));
-               break;
-
-       case RT5677_GPIO6:
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
-                       RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT);
-               break;
-
-       default:
-               break;
-       }
+       rt5677_update_gpio_bits(rt5677, offset, m, level);
 }
 
 static int rt5677_gpio_direction_out(struct gpio_chip *chip,
                                     unsigned offset, int value)
 {
        struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+       int level = value ? RT5677_GPIOx_OUT_HI : RT5677_GPIOx_OUT_LO;
+       int m = RT5677_GPIOx_DIR_MASK | RT5677_GPIOx_OUT_MASK;
+       int v = RT5677_GPIOx_DIR_OUT | level;
 
-       switch (offset) {
-       case RT5677_GPIO1 ... RT5677_GPIO5:
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
-                       0x3 << (offset * 3 + 1),
-                       (0x2 | !!value) << (offset * 3 + 1));
-               break;
-
-       case RT5677_GPIO6:
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
-                       RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK,
-                       RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT);
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
+       return rt5677_update_gpio_bits(rt5677, offset, m, v);
 }
 
 static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -4778,26 +4760,14 @@ static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
 static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+       int m = RT5677_GPIOx_DIR_MASK;
+       int v = RT5677_GPIOx_DIR_IN;
 
-       switch (offset) {
-       case RT5677_GPIO1 ... RT5677_GPIO5:
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
-                       0x1 << (offset * 3 + 2), 0x0);
-               break;
-
-       case RT5677_GPIO6:
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3,
-                       RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN);
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
+       return rt5677_update_gpio_bits(rt5677, offset, m, v);
 }
 
-/** Configures the gpio as
+/*
+ * Configures the GPIO as
  *   0 - floating
  *   1 - pull down
  *   2 - pull up
@@ -5539,7 +5509,7 @@ static int rt5677_init_irq(struct i2c_client *i2c)
                        RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);
 
        /* Ready to listen for interrupts */
-       rt5677->domain = irq_domain_add_linear(i2c->dev.of_node,
+       rt5677->domain = irq_domain_create_linear(dev_fwnode(&i2c->dev),
                        RT5677_IRQ_NUM, &rt5677_domain_ops, rt5677);
        if (!rt5677->domain) {
                dev_err(&i2c->dev, "Failed to create IRQ domain\n");
@@ -5559,6 +5529,7 @@ static int rt5677_init_irq(struct i2c_client *i2c)
 
 static int rt5677_i2c_probe(struct i2c_client *i2c)
 {
+       struct device *dev = &i2c->dev;
        struct rt5677_priv *rt5677;
        int ret;
        unsigned int val;
@@ -5573,21 +5544,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
        INIT_DELAYED_WORK(&rt5677->dsp_work, rt5677_dsp_work);
        i2c_set_clientdata(i2c, rt5677);
 
-       if (i2c->dev.of_node) {
-               const struct of_device_id *match_id;
-
-               match_id = of_match_device(rt5677_of_match, &i2c->dev);
-               if (match_id)
-                       rt5677->type = (enum rt5677_type)match_id->data;
-       } else if (ACPI_HANDLE(&i2c->dev)) {
-               const struct acpi_device_id *acpi_id;
-
-               acpi_id = acpi_match_device(rt5677_acpi_match, &i2c->dev);
-               if (acpi_id)
-                       rt5677->type = (enum rt5677_type)acpi_id->driver_data;
-       } else {
+       rt5677->type = (enum rt5677_type)(uintptr_t)device_get_match_data(dev);
+       if (rt5677->type == 0)
                return -EINVAL;
-       }
 
        rt5677_read_device_properties(rt5677, &i2c->dev);
 
@@ -5673,9 +5632,9 @@ static int rt5677_i2c_probe(struct i2c_client *i2c)
                regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2,
                                        RT5677_GPIO5_FUNC_MASK,
                                        RT5677_GPIO5_FUNC_DMIC);
-               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2,
-                                       RT5677_GPIO5_DIR_MASK,
-                                       RT5677_GPIO5_DIR_OUT);
+               rt5677_update_gpio_bits(rt5677, RT5677_GPIO5,
+                                       RT5677_GPIOx_DIR_MASK,
+                                       RT5677_GPIOx_DIR_OUT);
        }
 
        if (rt5677->pdata.micbias1_vdd_3v3)
@@ -5702,7 +5661,7 @@ static struct i2c_driver rt5677_i2c_driver = {
        .driver = {
                .name = RT5677_DRV_NAME,
                .of_match_table = rt5677_of_match,
-               .acpi_match_table = ACPI_PTR(rt5677_acpi_match),
+               .acpi_match_table = rt5677_acpi_match,
        },
        .probe    = rt5677_i2c_probe,
        .remove   = rt5677_i2c_remove,
index 944ae02aafc2f122b695e9be2716674b87991bc0..d67ebae067d9d09aea369b47364762dcf12e5279 100644 (file)
 #define RT5677_FUNC_MODE_DMIC_GPIO             (0x0 << 13)
 #define RT5677_FUNC_MODE_JTAG                  (0x1 << 13)
 
-/* GPIO Control 2 (0xc1) */
-#define RT5677_GPIO5_DIR_MASK                  (0x1 << 14)
-#define RT5677_GPIO5_DIR_SFT                   14
-#define RT5677_GPIO5_DIR_IN                    (0x0 << 14)
-#define RT5677_GPIO5_DIR_OUT                   (0x1 << 14)
-#define RT5677_GPIO5_OUT_MASK                  (0x1 << 13)
-#define RT5677_GPIO5_OUT_SFT                   13
-#define RT5677_GPIO5_OUT_LO                    (0x0 << 13)
-#define RT5677_GPIO5_OUT_HI                    (0x1 << 13)
-#define RT5677_GPIO5_P_MASK                    (0x1 << 12)
-#define RT5677_GPIO5_P_SFT                     12
-#define RT5677_GPIO5_P_NOR                     (0x0 << 12)
-#define RT5677_GPIO5_P_INV                     (0x1 << 12)
-#define RT5677_GPIO4_DIR_MASK                  (0x1 << 11)
-#define RT5677_GPIO4_DIR_SFT                   11
-#define RT5677_GPIO4_DIR_IN                    (0x0 << 11)
-#define RT5677_GPIO4_DIR_OUT                   (0x1 << 11)
-#define RT5677_GPIO4_OUT_MASK                  (0x1 << 10)
-#define RT5677_GPIO4_OUT_SFT                   10
-#define RT5677_GPIO4_OUT_LO                    (0x0 << 10)
-#define RT5677_GPIO4_OUT_HI                    (0x1 << 10)
-#define RT5677_GPIO4_P_MASK                    (0x1 << 9)
-#define RT5677_GPIO4_P_SFT                     9
-#define RT5677_GPIO4_P_NOR                     (0x0 << 9)
-#define RT5677_GPIO4_P_INV                     (0x1 << 9)
-#define RT5677_GPIO3_DIR_MASK                  (0x1 << 8)
-#define RT5677_GPIO3_DIR_SFT                   8
-#define RT5677_GPIO3_DIR_IN                    (0x0 << 8)
-#define RT5677_GPIO3_DIR_OUT                   (0x1 << 8)
-#define RT5677_GPIO3_OUT_MASK                  (0x1 << 7)
-#define RT5677_GPIO3_OUT_SFT                   7
-#define RT5677_GPIO3_OUT_LO                    (0x0 << 7)
-#define RT5677_GPIO3_OUT_HI                    (0x1 << 7)
-#define RT5677_GPIO3_P_MASK                    (0x1 << 6)
-#define RT5677_GPIO3_P_SFT                     6
-#define RT5677_GPIO3_P_NOR                     (0x0 << 6)
-#define RT5677_GPIO3_P_INV                     (0x1 << 6)
-#define RT5677_GPIO2_DIR_MASK                  (0x1 << 5)
-#define RT5677_GPIO2_DIR_SFT                   5
-#define RT5677_GPIO2_DIR_IN                    (0x0 << 5)
-#define RT5677_GPIO2_DIR_OUT                   (0x1 << 5)
-#define RT5677_GPIO2_OUT_MASK                  (0x1 << 4)
-#define RT5677_GPIO2_OUT_SFT                   4
-#define RT5677_GPIO2_OUT_LO                    (0x0 << 4)
-#define RT5677_GPIO2_OUT_HI                    (0x1 << 4)
-#define RT5677_GPIO2_P_MASK                    (0x1 << 3)
-#define RT5677_GPIO2_P_SFT                     3
-#define RT5677_GPIO2_P_NOR                     (0x0 << 3)
-#define RT5677_GPIO2_P_INV                     (0x1 << 3)
-#define RT5677_GPIO1_DIR_MASK                  (0x1 << 2)
-#define RT5677_GPIO1_DIR_SFT                   2
-#define RT5677_GPIO1_DIR_IN                    (0x0 << 2)
-#define RT5677_GPIO1_DIR_OUT                   (0x1 << 2)
-#define RT5677_GPIO1_OUT_MASK                  (0x1 << 1)
-#define RT5677_GPIO1_OUT_SFT                   1
-#define RT5677_GPIO1_OUT_LO                    (0x0 << 1)
-#define RT5677_GPIO1_OUT_HI                    (0x1 << 1)
-#define RT5677_GPIO1_P_MASK                    (0x1 << 0)
-#define RT5677_GPIO1_P_SFT                     0
-#define RT5677_GPIO1_P_NOR                     (0x0 << 0)
-#define RT5677_GPIO1_P_INV                     (0x1 << 0)
-
-/* GPIO Control 3 (0xc2) */
-#define RT5677_GPIO6_DIR_MASK                  (0x1 << 2)
-#define RT5677_GPIO6_DIR_SFT                   2
-#define RT5677_GPIO6_DIR_IN                    (0x0 << 2)
-#define RT5677_GPIO6_DIR_OUT                   (0x1 << 2)
-#define RT5677_GPIO6_OUT_MASK                  (0x1 << 1)
-#define RT5677_GPIO6_OUT_SFT                   1
-#define RT5677_GPIO6_OUT_LO                    (0x0 << 1)
-#define RT5677_GPIO6_OUT_HI                    (0x1 << 1)
-#define RT5677_GPIO6_P_MASK                    (0x1 << 0)
-#define RT5677_GPIO6_P_SFT                     0
-#define RT5677_GPIO6_P_NOR                     (0x0 << 0)
-#define RT5677_GPIO6_P_INV                     (0x1 << 0)
+/* GPIO Control 2 (0xc1) & 3 (0xc2) common bits */
+#define RT5677_GPIOx_DIR_MASK                  (0x1 << 2)
+#define RT5677_GPIOx_DIR_SFT                   2
+#define RT5677_GPIOx_DIR_IN                    (0x0 << 2)
+#define RT5677_GPIOx_DIR_OUT                   (0x1 << 2)
+#define RT5677_GPIOx_OUT_MASK                  (0x1 << 1)
+#define RT5677_GPIOx_OUT_SFT                   1
+#define RT5677_GPIOx_OUT_LO                    (0x0 << 1)
+#define RT5677_GPIOx_OUT_HI                    (0x1 << 1)
+#define RT5677_GPIOx_P_MASK                    (0x1 << 0)
+#define RT5677_GPIOx_P_SFT                     0
+#define RT5677_GPIOx_P_NOR                     (0x0 << 0)
+#define RT5677_GPIOx_P_INV                     (0x1 << 0)
 
 /* General Control (0xfa) */
 #define RT5677_IRQ_DEBOUNCE_SEL_MASK           (0x3 << 3)
@@ -1753,8 +1691,8 @@ enum {
 };
 
 enum rt5677_type {
-       RT5677,
-       RT5676,
+       RT5677 = 1,
+       RT5676 = 2,
 };
 
 /* ASRC clock source selection */
index fb8ffb5b2ff647b1b9f0e977b0e57e97647eeba6..b05b4f73d8aa7311fc1f82043564727f579c3bfc 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -170,11 +169,9 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
-       if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
-               if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
-                                         GPIOF_OUT_INIT_HIGH, "rt5682"))
-                       dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
-       }
+       ret = rt5682_get_ldo1(rt5682, &i2c->dev);
+       if (ret)
+               return ret;
 
        /* Sleep for 300 ms miniumum */
        usleep_range(300000, 350000);
index 4968a8c0064dda29135a5fdd747557a4348c1649..e67c2e19cb1a7291170ada3b69cbdda4aadb8b6c 100644 (file)
@@ -12,8 +12,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
@@ -322,6 +320,14 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
                return ret;
        }
 
+
+       ret = rt5682_get_ldo1(rt5682, dev);
+       if (ret)
+               return ret;
+
+       regcache_cache_only(rt5682->sdw_regmap, true);
+       regcache_cache_only(rt5682->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -336,7 +342,25 @@ static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
        ret = devm_snd_soc_register_component(dev,
                                              &rt5682_soc_component_dev,
                                              rt5682_dai, ARRAY_SIZE(rt5682_dai));
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -352,30 +376,20 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt5682->hw_init)
                return 0;
 
+       regcache_cache_only(rt5682->sdw_regmap, false);
+       regcache_cache_only(rt5682->regmap, false);
+       if (rt5682->first_hw_init)
+               regcache_cache_bypass(rt5682->regmap, true);
+
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt5682->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt5682->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
-       if (rt5682->first_hw_init) {
-               regcache_cache_only(rt5682->regmap, false);
-               regcache_cache_bypass(rt5682->regmap, true);
-       }
-
        while (loop > 0) {
                regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
                if (val == DEVICE_ID)
@@ -674,9 +688,7 @@ static int rt5682_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return -EINVAL;
 
-       rt5682_sdw_init(&slave->dev, regmap, slave);
-
-       return 0;
+       return rt5682_sdw_init(&slave->dev, regmap, slave);
 }
 
 static int rt5682_sdw_remove(struct sdw_slave *slave)
@@ -686,8 +698,7 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
        if (rt5682->hw_init)
                cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
-       if (rt5682->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
@@ -707,6 +718,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
 
        cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
+       regcache_cache_only(rt5682->sdw_regmap, true);
        regcache_cache_only(rt5682->regmap, true);
        regcache_mark_dirty(rt5682->regmap);
 
@@ -771,6 +783,7 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
 
 regmap_sync:
        slave->unattach_request = 0;
+       regcache_cache_only(rt5682->sdw_regmap, false);
        regcache_cache_only(rt5682->regmap, false);
        regcache_sync(rt5682->regmap);
 
index 5d992543b791fc317cbc51217d429fd63252005c..e3aca9c785a079296213628dcf5a4ec28ebaa252 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -1017,6 +1016,9 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
 
        rt5682->hs_jack = hs_jack;
 
+       if (rt5682->is_sdw && !rt5682->first_hw_init)
+               return 0;
+
        if (!hs_jack) {
                regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
                        RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
@@ -3091,9 +3093,6 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
        device_property_read_u32(dev, "realtek,dmic-delay-ms",
                &rt5682->pdata.dmic_delay);
 
-       rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
-               "realtek,ldo1-en-gpios", 0);
-
        if (device_property_read_string_array(dev, "clock-output-names",
                                              rt5682->pdata.dai_clk_names,
                                              RT5682_DAI_NUM_CLKS) < 0)
@@ -3108,6 +3107,20 @@ int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
 }
 EXPORT_SYMBOL_GPL(rt5682_parse_dt);
 
+int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev)
+{
+       rt5682->ldo1_en = devm_gpiod_get_optional(dev,
+                                                 "realtek,ldo1-en",
+                                                 GPIOD_OUT_HIGH);
+       if (IS_ERR(rt5682->ldo1_en)) {
+               dev_err(dev, "Fail gpio request ldo1_en\n");
+               return PTR_ERR(rt5682->ldo1_en);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5682_get_ldo1);
+
 void rt5682_calibrate(struct rt5682_priv *rt5682)
 {
        int value, count;
index 1a43d595f3415511274f8633012d77680b11e280..b2d9e87af2595a91cdd2864e4a7c669724d87cea 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <sound/rt5682.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
@@ -1430,6 +1431,7 @@ struct rt5682_priv {
        struct snd_soc_component *component;
        struct device *i2c_dev;
        struct rt5682_platform_data pdata;
+       struct gpio_desc *ldo1_en;
        struct regmap *regmap;
        struct regmap *sdw_regmap;
        struct snd_soc_jack *hs_jack;
@@ -1481,6 +1483,7 @@ int rt5682_register_component(struct device *dev);
 void rt5682_calibrate(struct rt5682_priv *rt5682);
 void rt5682_reset(struct rt5682_priv *rt5682);
 int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev);
+int rt5682_get_ldo1(struct rt5682_priv *rt5682, struct device *dev);
 
 int rt5682_register_dai_clks(struct rt5682_priv *rt5682);
 
index c77c675bd5f585b790ae3a989c6b913d6c67af91..68ac5ea50396d5723f514348f51d51b89bef8b59 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/acpi.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -2973,9 +2972,6 @@ static int rt5682s_parse_dt(struct rt5682s_priv *rt5682s, struct device *dev)
        device_property_read_u32(dev, "realtek,amic-delay-ms",
                &rt5682s->pdata.amic_delay);
 
-       rt5682s->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
-               "realtek,ldo1-en-gpios", 0);
-
        if (device_property_read_string_array(dev, "clock-output-names",
                                              rt5682s->pdata.dai_clk_names,
                                              RT5682S_DAI_NUM_CLKS) < 0)
@@ -3172,10 +3168,12 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
                return ret;
        }
 
-       if (gpio_is_valid(rt5682s->pdata.ldo1_en)) {
-               if (devm_gpio_request_one(&i2c->dev, rt5682s->pdata.ldo1_en,
-                                         GPIOF_OUT_INIT_HIGH, "rt5682s"))
-                       dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+       rt5682s->ldo1_en = devm_gpiod_get_optional(&i2c->dev,
+                                                  "realtek,ldo1-en",
+                                                  GPIOD_OUT_HIGH);
+       if (IS_ERR(rt5682s->ldo1_en)) {
+               dev_err(&i2c->dev, "Fail gpio request ldo1_en\n");
+               return PTR_ERR(rt5682s->ldo1_en);
        }
 
        /* Sleep for 50 ms minimum */
index caa7733b430f262ad02b476e98377273e5ce9732..1d79d432d0d8f08737ef9767a4d76b362b53d973 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <sound/rt5682s.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
@@ -1446,6 +1447,7 @@ enum {
 struct rt5682s_priv {
        struct snd_soc_component *component;
        struct rt5682s_platform_data pdata;
+       struct gpio_desc *ldo1_en;
        struct regmap *regmap;
        struct snd_soc_jack *hs_jack;
        struct regulator_bulk_data supplies[RT5682S_NUM_SUPPLIES];
index 8b28e47775cc28f879f7da0cb2f29666db49562e..52c33d56b143a9a127da7634d4412488614c6349 100644 (file)
@@ -452,9 +452,7 @@ static int rt700_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt700_init(&slave->dev, sdw_regmap, regmap, slave);
-
-       return 0;
+       return rt700_init(&slave->dev, sdw_regmap, regmap, slave);
 }
 
 static int rt700_sdw_remove(struct sdw_slave *slave)
@@ -466,8 +464,7 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
                cancel_delayed_work_sync(&rt700->jack_btn_check_work);
        }
 
-       if (rt700->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index a04b9246256b4711cd09e8464e4dd19e7cd57768..0ebf344a1b6094a38a4c38c6817b8cf0c9242f48 100644 (file)
@@ -320,6 +320,10 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
 
        rt700->hs_jack = hs_jack;
 
+       /* we can only resume if the device was initialized at least once */
+       if (!rt700->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -823,6 +827,9 @@ static int rt700_probe(struct snd_soc_component *component)
 
        rt700->component = component;
 
+       if (!rt700->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1099,6 +1106,8 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
        rt700->sdw_regmap = sdw_regmap;
        rt700->regmap = regmap;
 
+       regcache_cache_only(rt700->regmap, true);
+
        mutex_init(&rt700->disable_irq_lock);
 
        INIT_DELAYED_WORK(&rt700->jack_detect_work,
@@ -1117,10 +1126,26 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
                                &soc_codec_dev_rt700,
                                rt700_dai,
                                ARRAY_SIZE(rt700_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
 
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
        dev_dbg(&slave->dev, "%s\n", __func__);
 
-       return ret;
+       return 0;
 }
 
 int rt700_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1132,28 +1157,17 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt700->hw_init)
                return 0;
 
-       if (rt700->first_hw_init) {
-               regcache_cache_only(rt700->regmap, false);
+       regcache_cache_only(rt700->regmap, false);
+       if (rt700->first_hw_init)
                regcache_cache_bypass(rt700->regmap, true);
-       }
 
        /*
         * PM runtime is only enabled when a Slave reports as Attached
         */
-       if (!rt700->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
-               /* update count of parent 'active' children */
+       if (!rt700->first_hw_init)
+               /* PM runtime status is marked as 'active' only when a Slave reports as Attached */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
        /* reset */
index 23f23f714b3991afff4fb96dc3ce336b5678558a..935e597022d3242187b378107e302a36bedd17f5 100644 (file)
@@ -366,8 +366,7 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
        }
 
-       if (rt711->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        mutex_destroy(&rt711->calibrate_mutex);
        mutex_destroy(&rt711->disable_irq_lock);
index 07640d2f6e560797bb300513309f022606f35bdb..447154cb60104d31bb66ef268d7b60c513e273e3 100644 (file)
@@ -507,6 +507,10 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
 
        rt711->hs_jack = hs_jack;
 
+       /* we can only resume if the device was initialized at least once */
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -1215,6 +1219,9 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
        rt711_sdca_parse_dt(rt711, &rt711->slave->dev);
        rt711->component = component;
 
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1406,6 +1413,9 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
        rt711->regmap = regmap;
        rt711->mbq_regmap = mbq_regmap;
 
+       regcache_cache_only(rt711->regmap, true);
+       regcache_cache_only(rt711->mbq_regmap, true);
+
        mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
@@ -1431,9 +1441,27 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
                        rt711_sdca_dai,
                        ARRAY_SIZE(rt711_sdca_dai));
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       if (ret < 0)
+               return ret;
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711)
@@ -1500,27 +1528,19 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt711->hw_init)
                return 0;
 
+       regcache_cache_only(rt711->regmap, false);
+       regcache_cache_only(rt711->mbq_regmap, false);
+
        if (rt711->first_hw_init) {
-               regcache_cache_only(rt711->regmap, false);
                regcache_cache_bypass(rt711->regmap, true);
-               regcache_cache_only(rt711->mbq_regmap, false);
                regcache_cache_bypass(rt711->mbq_regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                * PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
index 33dced388f9e5aa76d490858b68ebf9f2dd1d4a6..3f5773310ae8cc3b5d94f76aa481724ac35bad0a 100644 (file)
@@ -453,9 +453,7 @@ static int rt711_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt711_init(&slave->dev, sdw_regmap, regmap, slave);
-
-       return 0;
+       return rt711_init(&slave->dev, sdw_regmap, regmap, slave);
 }
 
 static int rt711_sdw_remove(struct sdw_slave *slave)
@@ -468,8 +466,7 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
                cancel_work_sync(&rt711->calibration_work);
        }
 
-       if (rt711->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        mutex_destroy(&rt711->calibrate_mutex);
        mutex_destroy(&rt711->disable_irq_lock);
index af53cbcc7bf2dd8636937accdeebb514c7f9ddcb..66eaed13b0d6a06ff1a649be6924e16850e65997 100644 (file)
@@ -462,6 +462,10 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
 
        rt711->hs_jack = hs_jack;
 
+       /* we can only resume if the device was initialized at least once */
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -941,6 +945,9 @@ static int rt711_probe(struct snd_soc_component *component)
        rt711_parse_dt(rt711, &rt711->slave->dev);
        rt711->component = component;
 
+       if (!rt711->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1183,6 +1190,8 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
        rt711->sdw_regmap = sdw_regmap;
        rt711->regmap = regmap;
 
+       regcache_cache_only(rt711->regmap, true);
+
        mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
@@ -1204,8 +1213,25 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
                                &soc_codec_dev_rt711,
                                rt711_dai,
                                ARRAY_SIZE(rt711_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -1219,28 +1245,17 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt711->hw_init)
                return 0;
 
-       if (rt711->first_hw_init) {
-               regcache_cache_only(rt711->regmap, false);
+       regcache_cache_only(rt711->regmap, false);
+       if (rt711->first_hw_init)
                regcache_cache_bypass(rt711->regmap, true);
-       }
 
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt711->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt711->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
        rt711_reset(rt711->regmap);
index 869cc7bfd17840e31b58640901ab763815f1a8eb..ba08d03e717cc0b660986e581d36a4432d48d604 100644 (file)
@@ -182,27 +182,18 @@ static int rt712_sdca_dmic_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt712->hw_init)
                return 0;
 
+       regcache_cache_only(rt712->regmap, false);
+       regcache_cache_only(rt712->mbq_regmap, false);
        if (rt712->first_hw_init) {
-               regcache_cache_only(rt712->regmap, false);
                regcache_cache_bypass(rt712->regmap, true);
-               regcache_cache_only(rt712->mbq_regmap, false);
                regcache_cache_bypass(rt712->mbq_regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                * PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
@@ -608,6 +599,9 @@ static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
 
        rt712->component = component;
 
+       if (!rt712->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -777,6 +771,9 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
        rt712->regmap = regmap;
        rt712->mbq_regmap = mbq_regmap;
 
+       regcache_cache_only(rt712->regmap, true);
+       regcache_cache_only(rt712->mbq_regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -791,10 +788,27 @@ static int rt712_sdca_dmic_init(struct device *dev, struct regmap *regmap,
                        &soc_sdca_dev_rt712_dmic,
                        rt712_sdca_dmic_dai,
                        ARRAY_SIZE(rt712_sdca_dmic_dai));
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 
@@ -954,10 +968,7 @@ static int rt712_sdca_dmic_sdw_probe(struct sdw_slave *slave,
 
 static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(&slave->dev);
-
-       if (rt712->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 6bc50396a0f62c1e36a36347997b463faef65b6a..6b644a89c5890bb0a802c97c9ecbcfd977d6b35d 100644 (file)
@@ -363,8 +363,7 @@ static int rt712_sdca_sdw_remove(struct sdw_slave *slave)
                cancel_delayed_work_sync(&rt712->jack_btn_check_work);
        }
 
-       if (rt712->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        mutex_destroy(&rt712->calibrate_mutex);
        mutex_destroy(&rt712->disable_irq_lock);
index 89d245655ca480ac2a8f7b548f62bbd62412ebda..7077ff6ba1f4bc30cbde0b69ff147c349f8ea710 100644 (file)
@@ -453,6 +453,9 @@ static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
 
        rt712->hs_jack = hs_jack;
 
+       if (!rt712->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume_and_get(component->dev);
        if (ret < 0) {
                if (ret != -EACCES) {
@@ -960,6 +963,9 @@ static int rt712_sdca_probe(struct snd_soc_component *component)
        rt712_sdca_parse_dt(rt712, &rt712->slave->dev);
        rt712->component = component;
 
+       if (!rt712->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -1183,6 +1189,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
        rt712->regmap = regmap;
        rt712->mbq_regmap = mbq_regmap;
 
+       regcache_cache_only(rt712->regmap, true);
+       regcache_cache_only(rt712->mbq_regmap, true);
+
        mutex_init(&rt712->calibrate_mutex);
        mutex_init(&rt712->disable_irq_lock);
 
@@ -1207,10 +1216,27 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
        else
                ret =  devm_snd_soc_register_component(dev,
                                &soc_sdca_dev_rt712, rt712_sdca_dai, 1);
+       if (ret < 0)
+               return ret;
 
-       dev_dbg(&slave->dev, "%s\n", __func__);
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
 
-       return ret;
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
 }
 
 int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1224,27 +1250,18 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt712->hw_init)
                return 0;
 
+       regcache_cache_only(rt712->regmap, false);
+       regcache_cache_only(rt712->mbq_regmap, false);
        if (rt712->first_hw_init) {
-               regcache_cache_only(rt712->regmap, false);
                regcache_cache_bypass(rt712->regmap, true);
-               regcache_cache_only(rt712->mbq_regmap, false);
                regcache_cache_bypass(rt712->mbq_regmap, true);
        } else {
                /*
-                * PM runtime is only enabled when a Slave reports as Attached
+                *  PM runtime status is marked as 'active' only when a Slave reports as Attached
                 */
 
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
-
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
        }
 
        pm_runtime_get_noresume(&slave->dev);
index df10916bab46feec327947b2f0bf22a8fa4f88b8..ab54a67a27ebbfc8fbe19837fa07ed7d084bd429 100644 (file)
@@ -193,10 +193,7 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
 
 static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
-
-       if (rt715->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index b989f907784b9d4dd1f36c52f3362b1886f44bbf..9fa96fd83d4aa5a81a29284248e0111a97c4657d 100644 (file)
@@ -761,8 +761,12 @@ static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = {
 
 static int rt715_sdca_probe(struct snd_soc_component *component)
 {
+       struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component);
        int ret;
 
+       if (!rt715->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -977,6 +981,10 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
        rt715->regmap = regmap;
        rt715->mbq_regmap = mbq_regmap;
        rt715->hw_sdw_ver = slave->id.sdw_version;
+
+       regcache_cache_only(rt715->regmap, true);
+       regcache_cache_only(rt715->mbq_regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -988,6 +996,25 @@ int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap,
                        &soc_codec_dev_rt715_sdca,
                        rt715_sdca_dai,
                        ARRAY_SIZE(rt715_sdca_dai));
+       if (ret < 0)
+               return ret;
+
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       dev_dbg(dev, "%s\n", __func__);
 
        return ret;
 }
@@ -1000,22 +1027,16 @@ int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt715->hw_init)
                return 0;
 
+       regcache_cache_only(rt715->regmap, false);
+       regcache_cache_only(rt715->mbq_regmap, false);
+
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
        if (!rt715->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-
                rt715->first_hw_init = true;
        }
 
index 6db87442b783b3f4c469f017759658a30b896489..21f37babd148a487e82568144a791bff07fdf6c0 100644 (file)
@@ -508,17 +508,12 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
 
-       rt715_init(&slave->dev, sdw_regmap, regmap, slave);
-
-       return 0;
+       return rt715_init(&slave->dev, sdw_regmap, regmap, slave);
 }
 
 static int rt715_sdw_remove(struct sdw_slave *slave)
 {
-       struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
-
-       if (rt715->first_hw_init)
-               pm_runtime_disable(&slave->dev);
+       pm_runtime_disable(&slave->dev);
 
        return 0;
 }
index 6c2e165dd6218a7dbe15ea80df5cc43411d93bd4..b59230c8fd32a2ab1af3b70aba1609698821a727 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/pm.h>
 #include <linux/soundwire/sdw.h>
-#include <linux/gpio.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
-#include <linux/gpio/consumer.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/of_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -52,6 +49,60 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg,
        return ret;
 }
 
+static int rt715_index_write_nid(struct regmap *regmap,
+               unsigned int nid, unsigned int reg, unsigned int value)
+{
+       int ret;
+       unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
+
+       ret = regmap_write(regmap, addr, value);
+       if (ret < 0)
+               pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
+                       addr, value, ret);
+
+       return ret;
+}
+
+static int rt715_index_read_nid(struct regmap *regmap,
+               unsigned int nid, unsigned int reg, unsigned int *value)
+{
+       int ret;
+       unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg;
+
+       *value = 0;
+       ret = regmap_read(regmap, addr, value);
+       if (ret < 0)
+               pr_err("Failed to get private value: %06x => %04x ret=%d\n",
+                       addr, *value, ret);
+
+       return ret;
+}
+
+static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid,
+                       unsigned int reg, unsigned int mask, unsigned int val)
+{
+       unsigned int tmp, orig;
+       int ret;
+
+       ret = rt715_index_read_nid(regmap, nid, reg, &orig);
+       if (ret < 0)
+               return ret;
+
+       tmp = orig & ~mask;
+       tmp |= val & mask;
+
+       return rt715_index_write_nid(regmap, nid, reg, tmp);
+}
+
+static void rt715_reset(struct regmap *regmap)
+{
+       regmap_write(regmap, RT715_FUNC_RESET, 0);
+       rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS,
+               RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG,
+               RT715_CLEAR_HIDDEN_REG);
+}
+
+
 static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h,
                                unsigned int addr_l, unsigned int val_h,
                                unsigned int *r_val, unsigned int *l_val)
@@ -740,8 +791,12 @@ static int rt715_set_bias_level(struct snd_soc_component *component,
 
 static int rt715_probe(struct snd_soc_component *component)
 {
+       struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component);
        int ret;
 
+       if (!rt715->first_hw_init)
+               return 0;
+
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@ -984,6 +1039,8 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
        rt715->regmap = regmap;
        rt715->sdw_regmap = sdw_regmap;
 
+       regcache_cache_only(rt715->regmap, true);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -995,8 +1052,25 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap,
                                                &soc_codec_dev_rt715,
                                                rt715_dai,
                                                ARRAY_SIZE(rt715_dai));
+       if (ret < 0)
+               return ret;
 
-       return ret;
+       /* set autosuspend parameters */
+       pm_runtime_set_autosuspend_delay(dev, 3000);
+       pm_runtime_use_autosuspend(dev);
+
+       /* make sure the device does not suspend immediately */
+       pm_runtime_mark_last_busy(dev);
+
+       pm_runtime_enable(dev);
+
+       /* important note: the device is NOT tagged as 'active' and will remain
+        * 'suspended' until the hardware is enumerated/initialized. This is required
+        * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
+        * fail with -EACCESS because of race conditions between card creation and enumeration
+        */
+
+       return 0;
 }
 
 int rt715_io_init(struct device *dev, struct sdw_slave *slave)
@@ -1006,25 +1080,19 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave)
        if (rt715->hw_init)
                return 0;
 
+       regcache_cache_only(rt715->regmap, false);
+
        /*
-        * PM runtime is only enabled when a Slave reports as Attached
+        *  PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
-       if (!rt715->first_hw_init) {
-               /* set autosuspend parameters */
-               pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
-               pm_runtime_use_autosuspend(&slave->dev);
-
+       if (!rt715->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
 
-               /* make sure the device does not suspend immediately */
-               pm_runtime_mark_last_busy(&slave->dev);
-
-               pm_runtime_enable(&slave->dev);
-       }
-
        pm_runtime_get_noresume(&slave->dev);
 
+       rt715_reset(rt715->regmap);
+
        /* Mute nid=08h/09h */
        regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080);
        regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080);
index 12a0ae656d093159587be34d6a0fcc5f78217d44..6e37bf64e12f89660d7ffa74c11e72237f042dd3 100644 (file)
@@ -48,6 +48,7 @@ struct rt715_priv {
 #define RT715_INLINE_CMD                               0x55
 
 /* Index (NID:20h) */
+#define RT715_VD_CLEAR_CTRL                            0x01
 #define RT715_SDW_INPUT_SEL                            0x39
 #define RT715_EXT_DMIC_CLK_CTRL2                       0x54
 
@@ -71,6 +72,8 @@ struct rt715_priv {
 #define RT715_READ_HDA_0                               0x2015
 #define RT715_PRIV_INDEX_W_H                           0x7520
 #define RT715_PRIV_INDEX_W_L                           0x85a0
+#define RT715_PRIV_INDEX_W_H_2                         0x7500
+#define RT715_PRIV_INDEX_W_L_2                         0x8580
 #define RT715_PRIV_DATA_W_H                            0x7420
 #define RT715_PRIV_DATA_W_L                            0x84a0
 #define RT715_PRIV_INDEX_R_H                           0x9d20
@@ -198,6 +201,10 @@ struct rt715_priv {
 #define RT715_SET_DMIC4_CONFIG_DEFAULT4\
        (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4)
 
+/* vendor register clear ctrl-1    (0x01)(NID:20h) */
+#define RT715_CLEAR_HIDDEN_REG (0x1 << 15)
+
+
 #define RT715_MUTE_SFT                                 7
 #define RT715_DIR_IN_SFT                               6
 #define RT715_DIR_OUT_SFT                              7
index e9103ffb3f504dca934cf103903ea670d8c8294a..a38ec58622145750a0a61f21b8708823f2e75997 100644 (file)
@@ -175,7 +175,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave,
                 * This also could sync with the cache value as the rt722_sdca_jack_init set.
                 */
                        sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
-                               SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6);
+                               SDW_SCP_SDCA_INTMASK_SDCA_6);
                        sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2,
                                SDW_SCP_SDCA_INTMASK_SDCA_8);
                }
index 9c0d34366c9e5f92802a8878c109fc8a0d55341f..0e1c65a20392addb92a6bdbc39319884f4d2f9c9 100644 (file)
@@ -191,8 +191,7 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work)
                return;
 
        /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */
-       if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6 ||
-               rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) {
+       if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6) {
                ret = rt722_sdca_headset_detect(rt722);
                if (ret < 0)
                        return;
index 008cb3eb575804de39ca26122e8f43febd061d84..8c6665677a17590a4988e3fcda402c1a9dbc531f 100644 (file)
@@ -437,7 +437,7 @@ MODULE_DEVICE_TABLE(of, ssm3515_of_match);
 static struct i2c_driver ssm3515_i2c_driver = {
        .driver = {
                .name = "ssm3515",
-               .of_match_table = of_match_ptr(ssm3515_of_match),
+               .of_match_table = ssm3515_of_match,
        },
        .probe = ssm3515_i2c_probe,
 };
index 4a694d0bfd686e767934219605c220370dfe2cda..34ffd32ab9dca10e367aff1ef4c6079b49093ef5 100644 (file)
@@ -1022,7 +1022,7 @@ static const struct regmap_config sta32x_regmap = {
        .max_register =         STA32X_FDRC2,
        .reg_defaults =         sta32x_regs,
        .num_reg_defaults =     ARRAY_SIZE(sta32x_regs),
-       .cache_type =           REGCACHE_RBTREE,
+       .cache_type =           REGCACHE_MAPLE,
        .wr_table =             &sta32x_write_regs,
        .rd_table =             &sta32x_read_regs,
        .volatile_table =       &sta32x_volatile_regs,
index d05f3fd576612e5cc9a67dd7513a3d9aba417016..e4a9e9241c607eb4aec278c244e1544f2d0021e8 100644 (file)
@@ -1065,7 +1065,7 @@ static const struct regmap_config sta350_regmap = {
        .max_register =         STA350_MISC2,
        .reg_defaults =         sta350_regs,
        .num_reg_defaults =     ARRAY_SIZE(sta350_regs),
-       .cache_type =           REGCACHE_RBTREE,
+       .cache_type =           REGCACHE_MAPLE,
        .wr_table =             &sta350_write_regs,
        .rd_table =             &sta350_read_regs,
        .volatile_table =       &sta350_volatile_regs,
index 0ac08478ddac5aa6d672e9bc1cd2944b84b77b7d..eedafef775e53332d03698d73649a4edf1d68fd0 100644 (file)
@@ -331,7 +331,7 @@ static const struct regmap_config sta529_regmap = {
        .max_register = STA529_MAX_REGISTER,
        .readable_reg = sta529_readable,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = sta529_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults),
 };
index 1824a71fe053d1a2fdfc6c119f327370e434a5f3..2f9f10a4dfed987504bde4fe6d58582b9467d945 100644 (file)
@@ -67,7 +67,7 @@ static const struct regmap_config stac9766_regmap_config = {
        .reg_stride = 2,
        .val_bits = 16,
        .max_register = 0x78,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = regmap_ac97_default_volatile,
 
index 99545bcb2ba9edba86c223ea80ea29ffd174d4ca..c421906a0694fef5f4ce70ccae374b54a9897568 100644 (file)
@@ -316,7 +316,7 @@ static const struct regmap_config stih407_sas_regmap = {
        .reg_defaults = stih407_sas_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
        .volatile_reg = sti_sas_volatile_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_read = sti_sas_read_reg,
        .reg_write = sti_sas_write_reg,
 };
index a88c6c28a3941085ba71e71d9f1239839eacc39b..ffb26e4a7e2f09cbec42d3f02904d8efd71ec789 100644 (file)
@@ -57,16 +57,17 @@ static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv,
 
                if (client->addr != tasdev->dev_addr) {
                        client->addr = tasdev->dev_addr;
-                       if (tasdev->cur_book == book) {
-                               ret = regmap_write(map,
-                                       TASDEVICE_PAGE_SELECT, 0);
-                               if (ret < 0) {
-                                       dev_err(tas_priv->dev, "%s, E=%d\n",
-                                               __func__, ret);
-                                       goto out;
-                               }
+                       /* All tas2781s share the same regmap, clear the page
+                        * inside regmap once switching to another tas2781.
+                        * Register 0 at any pages and any books inside tas2781
+                        * is the same one for page-switching.
+                        */
+                       ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0);
+                       if (ret < 0) {
+                               dev_err(tas_priv->dev, "%s, E=%d\n",
+                                       __func__, ret);
+                               goto out;
                        }
-                       goto out;
                }
 
                if (tasdev->cur_book != book) {
index 4c59429a42b76400aea31fae518754b3c0966573..55cd5e3c23a5d90f9167dc83fe55fab8ad6c0069 100644 (file)
@@ -743,7 +743,6 @@ MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
 static struct i2c_driver tasdevice_i2c_driver = {
        .driver = {
                .name = "tas2781-codec",
-               .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(tasdevice_of_match),
 #ifdef CONFIG_ACPI
                .acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
index aca3756ffab63d99723eb1f06108a78200bfc01d..3b53eba38a0b1d064f5584099cafb6edead89cd4 100644 (file)
@@ -520,12 +520,11 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
        }
 
        tas5805m->dsp_cfg_len = fw->size;
-       tas5805m->dsp_cfg_data = devm_kmalloc(dev, fw->size, GFP_KERNEL);
+       tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL);
        if (!tas5805m->dsp_cfg_data) {
                release_firmware(fw);
                return -ENOMEM;
        }
-       memcpy(tas5805m->dsp_cfg_data, fw->data, fw->size);
 
        release_firmware(fw);
 
index c116e82f712d6f76d7f40715614e41bcea4568e0..5c0a76a4a106b24f7579522e14ad2d6b59ca1de5 100644 (file)
@@ -321,7 +321,7 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
        u8 divisor;
 
        divisor = DIV_ROUND_UP(parent_rate, rate);
-       if (divisor > 128)
+       if (divisor > AIC32X4_DIV_MAX)
                return -EINVAL;
 
        return regmap_update_bits(div->regmap, div->reg,
@@ -334,7 +334,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
        unsigned long divisor;
 
        divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
-       if (divisor > 128)
+       if (divisor > AIC32X4_DIV_MAX)
                return -EINVAL;
 
        req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);
@@ -345,12 +345,18 @@ static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
                                                unsigned long parent_rate)
 {
        struct clk_aic32x4 *div = to_clk_aic32x4(hw);
-
        unsigned int val;
+       int err;
+
+       err = regmap_read(div->regmap, div->reg, &val);
+       if (err)
+               return 0;
 
-       regmap_read(div->regmap, div->reg, &val);
+       val &= AIC32X4_DIV_MASK;
+       if (!val)
+               val = AIC32X4_DIV_MAX;
 
-       return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
+       return DIV_ROUND_UP(parent_rate, val);
 }
 
 static const struct clk_ops aic32x4_div_ops = {
index ffe1828a4b7ed1af7ef7ca23b9ea0157437fc4c0..6829834a412fc03cdc64a238922d614f051ad814 100644 (file)
@@ -1349,7 +1349,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
                return -ENOMEM;
 
        aic32x4->dev = dev;
-       aic32x4->type = (enum aic32x4_type)dev_get_drvdata(dev);
+       aic32x4->type = (uintptr_t)dev_get_drvdata(dev);
 
        dev_set_drvdata(dev, aic32x4);
 
index 4de5bd9e8cc5f327f65b51167b11364dba286423..d6101ce73f80d0200b97aa1dd1d13391f61038b7 100644 (file)
@@ -223,8 +223,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
 #define AIC32X4_REFPOWERUP_120MS       0x07
 
 /* Common mask and enable for all of the dividers */
-#define AIC32X4_DIVEN           BIT(7)
-#define AIC32X4_DIV_MASK        GENMASK(6, 0)
+#define AIC32X4_DIVEN                  BIT(7)
+#define AIC32X4_DIV_MASK               GENMASK(6, 0)
+#define AIC32X4_DIV_MAX                        128
 
 /* Clock Limits */
 #define AIC32X4_MAX_DOSR_FREQ          6200000
index 8bf3510a3ea3f295613a7dc4c57504b402d53b8b..a05b553e6472f48f0c837d427506c673b9bc6ede 100644 (file)
@@ -4968,7 +4968,7 @@ static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
 static struct regmap_config wcd9335_regmap_config = {
        .reg_bits = 16,
        .val_bits = 8,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .max_register = WCD9335_MAX_REGISTER,
        .can_multi_write = true,
        .ranges = wcd9335_ranges,
index bd0e9fbc12ebfb3fdbd445ed790871dd5b2eb89a..6951120057e55d97f9f6513363f354aa4ef03c7d 100644 (file)
@@ -1183,7 +1183,7 @@ static const struct regmap_config wcd938x_regmap_config = {
        .name = "wcd938x_csr",
        .reg_bits = 32,
        .val_bits = 8,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wcd938x_defaults,
        .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults),
        .max_register = WCD938X_MAX_REGISTER,
index 277b8c468c788215639ce5fcb5de8caf9237a390..9679906c6bd50298d78b6056d985c5a66333087c 100644 (file)
@@ -1770,11 +1770,6 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops wm2200_dai_ops = {
-       .set_fmt = wm2200_set_fmt,
-       .hw_params = wm2200_hw_params,
-};
-
 static int wm2200_set_sysclk(struct snd_soc_component *component, int clk_id,
                             int source, unsigned int freq, int dir)
 {
@@ -2068,6 +2063,12 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops wm2200_dai_ops = {
+       .probe = wm2200_dai_probe,
+       .set_fmt = wm2200_set_fmt,
+       .hw_params = wm2200_hw_params,
+};
+
 #define WM2200_RATES SNDRV_PCM_RATE_8000_48000
 
 #define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
@@ -2075,7 +2076,6 @@ static int wm2200_dai_probe(struct snd_soc_dai *dai)
 
 static struct snd_soc_dai_driver wm2200_dai = {
        .name = "wm2200",
-       .probe = wm2200_dai_probe,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -2151,7 +2151,7 @@ static const struct regmap_config wm2200_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
        .volatile_reg = wm2200_volatile_register,
        .readable_reg = wm2200_readable_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .ranges = wm2200_ranges,
        .num_ranges = ARRAY_SIZE(wm2200_ranges),
 };
index a86eacb2a9bb7b0f272df8d01b1e1ebf84234c64..ff63723928a166e5c4da9e8bb249c41489bf0618 100644 (file)
@@ -2400,7 +2400,7 @@ static const struct regmap_config wm5100_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults),
        .volatile_reg = wm5100_volatile_register,
        .readable_reg = wm5100_readable_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static const unsigned int wm5100_mic_ctrl_reg[] = {
index 3bdbdf3770b5d87abebd9951aa9e2d79c34c2378..4ecf07c7448c544790225ee27e0e891d8cc64fc8 100644 (file)
@@ -1773,6 +1773,10 @@ static int wm5102_set_fll(struct snd_soc_component *component, int fll_id,
 #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const struct snd_soc_dai_ops wm5102_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver wm5102_dai[] = {
        {
                .name = "wm5102-aif1",
@@ -1906,7 +1910,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
                        .rates = WM5102_RATES,
                        .formats = WM5102_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &wm5102_dai_ops,
        },
        {
                .name = "wm5102-dsp-trace",
index ad670300de8d0c9e5e760b1ce5152141f11db476..ac1f2c850346501ce6b3ddc74197b50b2d8345b1 100644 (file)
@@ -2073,6 +2073,10 @@ static int wm5110_set_fll(struct snd_soc_component *component, int fll_id,
 #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
+static const struct snd_soc_dai_ops wm5110_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver wm5110_dai[] = {
        {
                .name = "wm5110-aif1",
@@ -2206,7 +2210,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                        .rates = WM5110_RATES,
                        .formats = WM5110_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &wm5110_dai_ops,
        },
        {
                .name = "wm5110-dsp-voicectrl",
@@ -2227,7 +2231,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                        .rates = WM5110_RATES,
                        .formats = WM5110_FORMATS,
                },
-               .compress_new = snd_soc_new_compress,
+               .ops = &wm5110_dai_ops,
        },
        {
                .name = "wm5110-dsp-trace",
index c0ed76d5b65f3db96febd6c885062c7e11e73ec3..6636a70f3895c0eb37967a7ab3da76eaea1b7413 100644 (file)
@@ -607,7 +607,7 @@ static const struct regmap_config wm8510_regmap = {
 
        .reg_defaults = wm8510_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8510_volatile,
 };
index 55c72c5ac8451aacd24680304e71869b5e789a5b..ea87cd3cc0d67832c1a1a694d58100716dab466e 100644 (file)
@@ -437,7 +437,7 @@ static const struct regmap_config wm8523_regmap = {
 
        .reg_defaults = wm8523_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8523_volatile_register,
 };
index 34ae7fe053985667a187d2ca06dfc5c41327f6a0..6d22f7d40ec2b82db09adc57d6ac9e11afe0e387 100644 (file)
@@ -975,7 +975,7 @@ static const struct regmap_config wm8580_regmap = {
 
        .reg_defaults = wm8580_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8580_volatile,
 };
index 903a0147d584df3eb1e81898abb6f5c536dd60e6..916f297164de0257614600cfc5b51d8b0f05f8ec 100644 (file)
@@ -393,7 +393,7 @@ static const struct regmap_config wm8711_regmap = {
 
        .reg_defaults = wm8711_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8711_volatile,
 };
index 5ea6d8fd10f6865823b0a54dd98991ef93d2dde3..0c943e7d4159e66aec0fcd110fc3c8c601d39fe4 100644 (file)
@@ -236,7 +236,7 @@ static const struct regmap_config wm8728_regmap = {
 
        .reg_defaults = wm8728_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 #if defined(CONFIG_SPI_MASTER)
index d5ab3ba126a6b5a1519064ed841f09aefc0fbc23..efc160c75f40490e2fc6d91ac01de36cb619b734 100644 (file)
@@ -642,7 +642,7 @@ const struct regmap_config wm8731_regmap = {
        .max_register = WM8731_RESET,
        .volatile_reg = wm8731_volatile,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8731_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8731_reg_defaults),
 };
index 9f4e372e90eab04391a811a5e12ab8b32780d765..0d231c289ef33b20604e4b2d97ea92951488fe98 100644 (file)
@@ -599,7 +599,7 @@ static const struct regmap_config wm8737_regmap = {
 
        .reg_defaults = wm8737_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8737_volatile,
 };
index 787156b980a1a78d5dde76d01de8085724e01bd0..19e8fc4062c79a45d88e5e1c00d37ae28cccec17 100644 (file)
@@ -543,7 +543,7 @@ static const struct regmap_config wm8741_regmap = {
 
        .reg_defaults = wm8741_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
index 20dc9ff9fea91c0cbf721f36c984e5d8ccbbacc9..2d2feaf95e49521a37aa50941b10a0eab80496ba 100644 (file)
@@ -735,7 +735,7 @@ static const struct regmap_config wm8750_regmap = {
 
        .reg_defaults = wm8750_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 5e8a8eb41b2b9ee6977fd35306405ac4c0d8f6a0..b5d8290c37d9b12b48b1038cbe89a4bc4acbe336 100644 (file)
@@ -1507,7 +1507,7 @@ static const struct regmap_config wm8753_regmap = {
        .max_register = WM8753_ADCTL2,
        .volatile_reg = wm8753_volatile,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8753_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8753_reg_defaults),
 };
index e03fee8869c371995a6bfe67a6b4ab94315eb202..2469f4f3bea355f199cc3a86e60b2ae9a43509dc 100644 (file)
@@ -632,7 +632,7 @@ static const struct regmap_config wm8770_regmap = {
 
        .reg_defaults = wm8770_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8770_volatile_reg,
 };
index 212224a680061659cba1f0970b98da37e1212dc5..0673bbd32bab10d8b4fe09ba3f11e0b0ab4ece57 100644 (file)
@@ -451,7 +451,7 @@ static const struct regmap_config wm8776_regmap = {
 
        .reg_defaults = wm8776_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8776_volatile,
 };
index 0b234bae480e117b515721fa71005c9cc8883083..bbb4b6e3b41cfedc111d725b3ca24308a8d3b2a3 100644 (file)
@@ -555,7 +555,7 @@ const struct regmap_config wm8804_regmap_config = {
        .max_register = WM8804_MAX_REGISTER,
        .volatile_reg = wm8804_volatile,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8804_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8804_reg_defaults),
 };
index 320ccd92f318ac762b4c3e11007dbf494aace758..84d06c190411932f6f44e21572852060a48d6bea 100644 (file)
@@ -1223,7 +1223,7 @@ static const struct regmap_config wm8900_regmap = {
 
        .reg_defaults = wm8900_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8900_volatile_register,
 };
index 901b65ef8de5b5c35dc6a7ce71bbc2769ffd5d0f..84ae1102ac883738d4fa31849234a4a5094b7b6e 100644 (file)
@@ -1902,7 +1902,7 @@ static const struct regmap_config wm8903_regmap = {
        .volatile_reg = wm8903_volatile_register,
        .readable_reg = wm8903_readable_register,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8903_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults),
 };
index f2baee7c332e9b1475b1c240ea371ab5421ae1c5..829bf055622a7f966849bbfaeec1d9e3b3f6ba93 100644 (file)
@@ -2148,7 +2148,7 @@ static const struct regmap_config wm8904_regmap = {
        .volatile_reg = wm8904_volatile_register,
        .readable_reg = wm8904_readable_register,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8904_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults),
 };
@@ -2202,7 +2202,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c)
                match = of_match_node(wm8904_of_match, i2c->dev.of_node);
                if (match == NULL)
                        return -EINVAL;
-               wm8904->devtype = (enum wm8904_type)match->data;
+               wm8904->devtype = (uintptr_t)match->data;
        } else {
                const struct i2c_device_id *id =
                        i2c_match_id(wm8904_i2c_id, i2c);
index 53c27986d216f67e16db0e20fd2bddabe98daa14..b9432f8b64e5bc1a5c1379f9327b869ccd686dd8 100644 (file)
@@ -815,7 +815,7 @@ static const struct regmap_config wm8940_regmap = {
        .max_register = WM8940_MONOMIX,
        .reg_defaults = wm8940_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .readable_reg = wm8940_readable_register,
        .volatile_reg = wm8940_volatile_register,
index 78044f580a676902c2834dc662b97f3b9d720e93..4f433832643860d0bb64beacf02a9b0e5919fe1b 100644 (file)
@@ -962,7 +962,7 @@ static const struct regmap_config wm8955_regmap = {
        .volatile_reg = wm8955_volatile,
        .writeable_reg = wm8955_writeable,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8955_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults),
 };
index 366f5d769d6df301d528a46b74b195c7d1e41157..0a50180750e8815c42040b4e433cd2f0381d3148 100644 (file)
@@ -120,6 +120,15 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
        }
 }
 
+#define WM8960_NUM_SUPPLIES 5
+static const char *wm8960_supply_names[WM8960_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD",
+       "SPKVDD1",
+       "SPKVDD2",
+};
+
 struct wm8960_priv {
        struct clk *mclk;
        struct regmap *regmap;
@@ -137,6 +146,7 @@ struct wm8960_priv {
        bool is_stream_in_use[2];
        struct wm8960_data pdata;
        ktime_t dsch_start;
+       struct regulator_bulk_data supplies[WM8960_NUM_SUPPLIES];
 };
 
 #define wm8960_reset(c)        regmap_write(c, WM8960_RESET, 0)
@@ -155,6 +165,7 @@ static const char *wm8960_adc_data_output_sel[] = {
        "Left Data = Right ADC; Right Data = Left ADC",
 };
 static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
+static const char *wm8960_dacslope[] = {"Normal", "Sloping"};
 
 static const struct soc_enum wm8960_enum[] = {
        SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
@@ -165,6 +176,7 @@ static const struct soc_enum wm8960_enum[] = {
        SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
        SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
        SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
+       SOC_ENUM_SINGLE(WM8960_DACCTL2, 1, 2, wm8960_dacslope),
 };
 
 static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
@@ -307,6 +319,7 @@ SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
 
 SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
 SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
+SOC_ENUM("DAC Filter Characteristics", wm8960_enum[8]),
 };
 
 static const struct snd_kcontrol_new wm8960_lin_boost[] = {
@@ -1387,7 +1400,7 @@ static const struct regmap_config wm8960_regmap = {
 
        .reg_defaults = wm8960_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8960_volatile,
 };
@@ -1414,7 +1427,9 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
 {
        struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
        struct wm8960_priv *wm8960;
+       unsigned int i;
        int ret;
+       u8 val;
 
        wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv),
                              GFP_KERNEL);
@@ -1425,6 +1440,31 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
        if (IS_ERR(wm8960->mclk)) {
                if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
+       } else {
+               ret = clk_get_rate(wm8960->mclk);
+               if (ret >= 0) {
+                       wm8960->freq_in = ret;
+               } else {
+                       dev_err(&i2c->dev, "Failed to read MCLK rate: %d\n",
+                               ret);
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8960->supplies); i++)
+               wm8960->supplies[i].supply = wm8960_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8960->supplies),
+                                wm8960->supplies);
+       if (ret <  0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8960->supplies),
+                                   wm8960->supplies);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
        }
 
        wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
@@ -1436,6 +1476,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
        else if (i2c->dev.of_node)
                wm8960_set_pdata_from_of(i2c, &wm8960->pdata);
 
+       ret = i2c_master_recv(i2c, &val, sizeof(val));
+       if (ret >= 0) {
+               dev_err(&i2c->dev, "Not wm8960, wm8960 reg can not read by i2c\n");
+               return -EINVAL;
+       }
+
        ret = wm8960_reset(wm8960->regmap);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to issue reset\n");
@@ -1487,7 +1533,11 @@ static int wm8960_i2c_probe(struct i2c_client *i2c)
 }
 
 static void wm8960_i2c_remove(struct i2c_client *client)
-{}
+{
+       struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8960->supplies), wm8960->supplies);
+}
 
 static const struct i2c_device_id wm8960_i2c_id[] = {
        { "wm8960", 0 },
index 63ba6c03c4883874e3990f242502c43b580295e7..e8ff33b188e9939ebec72d250e01cf30651f087e 100644 (file)
@@ -77,9 +77,9 @@
 #define WM8960_SYSCLK_DIV_1            (0 << 1)
 #define WM8960_SYSCLK_DIV_2            (2 << 1)
 
-#define WM8960_SYSCLK_MCLK             (0 << 0)
+#define WM8960_SYSCLK_AUTO             (0 << 0)
 #define WM8960_SYSCLK_PLL              (1 << 0)
-#define WM8960_SYSCLK_AUTO             (2 << 0)
+#define WM8960_SYSCLK_MCLK             (2 << 0)
 
 #define WM8960_DAC_DIV_1               (0 << 3)
 #define WM8960_DAC_DIV_1_5             (1 << 3)
index c076f78d04cea50045c2527097377cd7f96f0c2c..8f8330efb341d12649c08d7fe4069828db913bb4 100644 (file)
@@ -904,7 +904,7 @@ static const struct regmap_config wm8961_regmap = {
 
        .reg_defaults = wm8961_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm8961_volatile,
        .readable_reg = wm8961_readable,
index 68ea15be73309015f92aec44c445a74a584ddec0..83ce5dbecc45d45debb005a8c49a0934f654d94c 100644 (file)
@@ -3573,7 +3573,7 @@ static const struct regmap_config wm8962_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm8962_reg),
        .volatile_reg = wm8962_volatile_register,
        .readable_reg = wm8962_readable_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
index b22d8f0b59be0d9a843f34375c85c4f51d7b4c32..e88f323d28b237e55ed02d37666f295fe6cb295e 100644 (file)
@@ -668,7 +668,7 @@ static const struct regmap_config wm8971_regmap = {
 
        .reg_defaults = wm8971_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8971_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int wm8971_i2c_probe(struct i2c_client *i2c)
index 5c829301cf4c4cb2d30c1d51cf249a2541fb5a06..718bfef302cc6373ee77f02b6b28e364d1715f64 100644 (file)
@@ -1014,7 +1014,7 @@ static const struct regmap_config wm8978_regmap_config = {
        .max_register = WM8978_MAX_REGISTER,
        .volatile_reg = wm8978_volatile,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8978_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults),
 };
index 2bd26e2478d9680ee480064d9b1b8443a3fdc599..b26d6a68e8d2c2c186c36b8044a6029adbc22dc1 100644 (file)
@@ -995,7 +995,7 @@ static const struct regmap_config wm8983_regmap = {
 
        .reg_defaults = wm8983_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .max_register = WM8983_MAX_REGISTER,
 
        .writeable_reg = wm8983_writeable,
index c0816bcfa2944a48b68eaa468eea6360ec7521ef..8606e0752a6043bc1934a1b08869eae71e82d180 100644 (file)
@@ -1125,7 +1125,7 @@ static const struct regmap_config wm8985_regmap = {
        .max_register = WM8985_MAX_REGISTER,
        .writeable_reg = wm8985_writeable,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8985_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8985_reg_defaults),
 };
index b440719cca7dc5ea9f9e62c8e49d88696dfdc50f..76f214f12ce034166158399d62aeb0215b65744d 100644 (file)
@@ -832,7 +832,7 @@ static const struct regmap_config wm8988_regmap = {
        .max_register = WM8988_LPPB,
        .writeable_reg = wm8988_writeable,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8988_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults),
 };
index 8cb2ae829699842a29d059a9ed4f899e79b55340..590318aafaea1eeacd6936d16f0d5a34884236f5 100644 (file)
@@ -1253,7 +1253,7 @@ static const struct regmap_config wm8991_regmap = {
        .volatile_reg = wm8991_volatile,
        .reg_defaults = wm8991_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults),
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int wm8991_i2c_probe(struct i2c_client *i2c)
index feb997c698e2f5b59465148b35ba216f8bf80e94..5b788f35e5e4e8e4e49cfaacf2b8da8989eb3f0c 100644 (file)
@@ -1608,7 +1608,7 @@ static const struct regmap_config wm8993_regmap = {
        .volatile_reg = wm8993_volatile,
        .readable_reg = wm8993_readable,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm8993_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
 };
index bca3ebe0dac4c1aeecd44a6114c9c97da8b81c7e..a48e904a974031a08d068cbda787d8705977b5e2 100644 (file)
@@ -3215,6 +3215,7 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
 };
 
 static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
+       .probe          = wm8994_aif2_probe,
        .set_sysclk     = wm8994_set_dai_sysclk,
        .set_fmt        = wm8994_set_dai_fmt,
        .hw_params      = wm8994_hw_params,
@@ -3269,7 +3270,6 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
                        .formats = WM8994_FORMATS,
                        .sig_bits = 24,
                },
-               .probe = wm8994_aif2_probe,
                .ops = &wm8994_aif2_dai_ops,
        },
        {
index 90588614edcc795e3b83775ed77616b55deb1efc..4ffa1896faabd01e434d011352a6b3a5f322ce0a 100644 (file)
@@ -2193,7 +2193,7 @@ static const struct regmap_config wm8995_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm8995_reg_defaults),
        .volatile_reg = wm8995_volatile,
        .readable_reg = wm8995_readable,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 5d0eb0ae04750b040292ae52289b4024fb574a33..df6195778c570a96d47b8b1ffc9f22ff773de7fe 100644 (file)
@@ -2610,7 +2610,7 @@ static const struct regmap_config wm8996_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm8996_reg),
        .volatile_reg = wm8996_volatile_register,
        .readable_reg = wm8996_readable_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int wm8996_probe(struct snd_soc_component *component)
index 34a07db7342a024db42a6551b1461f3cbe5f0993..e7ec799573d3deec46d7bec41e7e3b4cbed6ec7a 100644 (file)
@@ -1295,7 +1295,7 @@ static const struct regmap_config wm9081_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm9081_reg),
        .volatile_reg = wm9081_volatile_register,
        .readable_reg = wm9081_readable_register,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 };
 
 static int wm9081_i2c_probe(struct i2c_client *i2c)
index 432729c753dd75308cdc6427002f1e33eee75eb2..50c1cbccfdb920edd5803947e2f22abea8d17268 100644 (file)
@@ -553,7 +553,7 @@ static const struct regmap_config wm9090_regmap = {
        .volatile_reg = wm9090_volatile,
        .readable_reg = wm9090_readable,
 
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wm9090_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm9090_reg_defaults),
 };
index d04902ef1d5f30c84d96359b7853120d3d75a512..5c6aebe29cf1325f608b2f38aaa5da5cff097c14 100644 (file)
@@ -64,7 +64,7 @@ static const struct regmap_config wm9705_regmap_config = {
        .reg_stride = 2,
        .val_bits = 16,
        .max_register = 0x7e,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = regmap_ac97_default_volatile,
 
index df9b7980706b255cac155b0ce3daf7963100d191..e63921de0c37a4e217cd0ffbadbb4e6175dc6812 100644 (file)
@@ -86,7 +86,7 @@ static const struct regmap_config wm9712_regmap_config = {
        .reg_stride = 2,
        .val_bits = 16,
        .max_register = 0x7e,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .volatile_reg = wm9712_volatile_reg,
 
index 5d2e54e06e30ae490f81f6cfd998d7827438d3bc..64b69316e4c7054a9b400c8ffba4d88547ccb7db 100644 (file)
@@ -727,7 +727,7 @@ static const struct regmap_config wm9713_regmap_config = {
        .reg_stride = 2,
        .val_bits = 16,
        .max_register = 0x7e,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
 
        .reg_defaults = wm9713_reg_defaults,
        .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
index 5a89abfe8784610865874491bee1a97db05bc014..6fc34f41b1758094acb4ba653eeb1bb023712399 100644 (file)
@@ -998,7 +998,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
 
-int wm_adsp_power_up(struct wm_adsp *dsp)
+int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware)
 {
        int ret = 0;
        char *wmfw_filename = NULL;
@@ -1006,11 +1006,13 @@ int wm_adsp_power_up(struct wm_adsp *dsp)
        char *coeff_filename = NULL;
        const struct firmware *coeff_firmware = NULL;
 
-       ret = wm_adsp_request_firmware_files(dsp,
-                                            &wmfw_firmware, &wmfw_filename,
-                                            &coeff_firmware, &coeff_filename);
-       if (ret)
-               return ret;
+       if (load_firmware) {
+               ret = wm_adsp_request_firmware_files(dsp,
+                                                    &wmfw_firmware, &wmfw_filename,
+                                                    &coeff_firmware, &coeff_filename);
+               if (ret)
+                       return ret;
+       }
 
        ret = cs_dsp_power_up(&dsp->cs_dsp,
                              wmfw_firmware, wmfw_filename,
@@ -1025,13 +1027,19 @@ int wm_adsp_power_up(struct wm_adsp *dsp)
 }
 EXPORT_SYMBOL_GPL(wm_adsp_power_up);
 
+void wm_adsp_power_down(struct wm_adsp *dsp)
+{
+       cs_dsp_power_down(&dsp->cs_dsp);
+}
+EXPORT_SYMBOL_GPL(wm_adsp_power_down);
+
 static void wm_adsp_boot_work(struct work_struct *work)
 {
        struct wm_adsp *dsp = container_of(work,
                                           struct wm_adsp,
                                           boot_work);
 
-       wm_adsp_power_up(dsp);
+       wm_adsp_power_up(dsp, true);
 }
 
 int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
@@ -1046,7 +1054,7 @@ int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
                queue_work(system_unbound_wq, &dsp->boot_work);
                break;
        case SND_SOC_DAPM_PRE_PMD:
-               cs_dsp_power_down(&dsp->cs_dsp);
+               wm_adsp_power_down(dsp);
                break;
        default:
                break;
index 769904d34a87c978a48615567675aa5299150677..067d807a7ca82d262685591226620abd75de64bd 100644 (file)
@@ -91,7 +91,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event);
 
-int wm_adsp_power_up(struct wm_adsp *dsp);
+int wm_adsp_power_up(struct wm_adsp *dsp, bool load_firmware);
+void wm_adsp_power_down(struct wm_adsp *dsp);
 
 irqreturn_t wm_adsp2_bus_error(int irq, void *data);
 irqreturn_t wm_halo_bus_error(int irq, void *data);
index 97f6873a0a8c7a0eacdbddebd9eb34266878fcec..3c025dabaf7a47f180b6f5bdaf6d6f67d128956d 100644 (file)
@@ -637,7 +637,7 @@ static bool wsa881x_volatile_register(struct device *dev, unsigned int reg)
 static struct regmap_config wsa881x_regmap_config = {
        .reg_bits = 32,
        .val_bits = 8,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wsa881x_defaults,
        .max_register = WSA881X_SPKR_STATUS3,
        .num_reg_defaults = ARRAY_SIZE(wsa881x_defaults),
index e40d583a1ce64aac9b9eb6c17a20a9288b9fa5ed..197fae23762f533b03b7364efe44e66ad9701639 100644 (file)
@@ -938,7 +938,7 @@ static bool wsa883x_volatile_register(struct device *dev, unsigned int reg)
 static struct regmap_config wsa883x_regmap_config = {
        .reg_bits = 32,
        .val_bits = 8,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .reg_defaults = wsa883x_defaults,
        .max_register = WSA883X_MAX_REGISTER,
        .num_reg_defaults = ARRAY_SIZE(wsa883x_defaults),
index 97d652f0e84d362a49f2402ed848e1efe2ba99af..0a4698008d64c13e7079244c731e6207014a50c5 100644 (file)
@@ -183,7 +183,15 @@ static void i2s_start(struct dw_i2s_dev *dev,
 {
        struct i2s_clk_config_data *config = &dev->config;
 
-       i2s_write_reg(dev->i2s_base, IER, 1);
+       u32 reg = IER_IEN;
+
+       if (dev->tdm_slots) {
+               reg |= (dev->tdm_slots - 1) << IER_TDM_SLOTS_SHIFT;
+               reg |= IER_INTF_TYPE;
+               reg |= dev->frame_offset << IER_FRAME_OFF_SHIFT;
+       }
+
+       i2s_write_reg(dev->i2s_base, IER, reg);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                i2s_write_reg(dev->i2s_base, ITER, 1);
@@ -233,13 +241,15 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
                                      dev->xfer_resolution);
                        i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
                                      dev->fifo_th - 1);
-                       i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+                       i2s_write_reg(dev->i2s_base, TER(ch_reg), TER_TXCHEN |
+                                     dev->tdm_mask << TER_TXSLOT_SHIFT);
                } else {
                        i2s_write_reg(dev->i2s_base, RCR(ch_reg),
                                      dev->xfer_resolution);
                        i2s_write_reg(dev->i2s_base, RFCR(ch_reg),
                                      dev->fifo_th - 1);
-                       i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+                       i2s_write_reg(dev->i2s_base, RER(ch_reg), RER_RXCHEN |
+                                     dev->tdm_mask << RER_RXSLOT_SHIFT);
                }
 
        }
@@ -276,6 +286,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       if (dev->tdm_slots)
+               config->data_width = 32;
+
        config->chan_nr = params_channels(params);
 
        switch (config->chan_nr) {
@@ -384,14 +397,67 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
                ret = -EINVAL;
                break;
        }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_LEFT_J:
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               dev->frame_offset = 1;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               dev->frame_offset = 0;
+               break;
+       default:
+               dev_err(dev->dev, "DAI format unsupported");
+               return -EINVAL;
+       }
+
        return ret;
 }
 
+static int dw_i2s_set_tdm_slot(struct snd_soc_dai *cpu_dai,    unsigned int tx_mask,
+                          unsigned int rx_mask, int slots, int slot_width)
+{
+       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (slot_width != 32)
+               return -EINVAL;
+
+       if (slots < 0 || slots > 16)
+               return -EINVAL;
+
+       if (rx_mask != tx_mask)
+               return -EINVAL;
+
+       if (!rx_mask)
+               return -EINVAL;
+
+       dev->tdm_slots = slots;
+       dev->tdm_mask = rx_mask;
+
+       dev->l_reg = RSLOT_TSLOT(ffs(rx_mask) - 1);
+       dev->r_reg = RSLOT_TSLOT(fls(rx_mask) - 1);
+
+       return 0;
+}
+
+static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
+       return 0;
+}
+
 static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
+       .probe          = dw_i2s_dai_probe,
        .hw_params      = dw_i2s_hw_params,
        .prepare        = dw_i2s_prepare,
        .trigger        = dw_i2s_trigger,
        .set_fmt        = dw_i2s_set_fmt,
+       .set_tdm_slot   = dw_i2s_set_tdm_slot,
 };
 
 #ifdef CONFIG_PM
@@ -623,14 +689,6 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
 
 }
 
-static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
-{
-       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
-
-       snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
-       return 0;
-}
-
 static int dw_i2s_probe(struct platform_device *pdev)
 {
        const struct i2s_platform_data *pdata = pdev->dev.platform_data;
@@ -649,7 +707,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        dw_i2s_dai->ops = &dw_i2s_dai_ops;
-       dw_i2s_dai->probe = dw_i2s_dai_probe;
 
        dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(dev->i2s_base))
@@ -726,6 +783,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
                if (irq >= 0) {
                        ret = dw_pcm_register(pdev);
                        dev->use_pio = true;
+                       dev->l_reg = LRBR_LTHR(0);
+                       dev->r_reg = RRBR_RTHR(0);
                } else {
                        ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
                                        0);
index 9f25631d43d3029bec4ef336f0bb089223049257..f99262b89008268ed88e62cd4291983fe7cfd3fb 100644 (file)
@@ -31,8 +31,8 @@ static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \
        int i; \
 \
        for (i = 0; i < dev->fifo_th; i++) { \
-               iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \
-               iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \
+               iowrite32(p[tx_ptr][0], dev->i2s_base + dev->l_reg); \
+               iowrite32(p[tx_ptr][1], dev->i2s_base + dev->r_reg); \
                period_pos++; \
                if (++tx_ptr >= runtime->buffer_size) \
                        tx_ptr = 0; \
@@ -51,8 +51,8 @@ static unsigned int dw_pcm_rx_##sample_bits(struct dw_i2s_dev *dev, \
        int i; \
 \
        for (i = 0; i < dev->fifo_th; i++) { \
-               p[rx_ptr][0] = ioread32(dev->i2s_base + LRBR_LTHR(0)); \
-               p[rx_ptr][1] = ioread32(dev->i2s_base + RRBR_RTHR(0)); \
+               p[rx_ptr][0] = ioread32(dev->i2s_base + dev->l_reg); \
+               p[rx_ptr][1] = ioread32(dev->i2s_base + dev->r_reg); \
                period_pos++; \
                if (++rx_ptr >= runtime->buffer_size) \
                        rx_ptr = 0; \
index ba4e397099be44d10e89dd4f22ba94e42732dcdb..4ce96bac2f39984511fe93a6d4cd864a6bcf1c3f 100644 (file)
 #define RXFFR          0x014
 #define TXFFR          0x018
 
+/* Enable register fields */
+#define IER_TDM_SLOTS_SHIFT    8
+#define IER_FRAME_OFF_SHIFT    5
+#define IER_FRAME_OFF  BIT(5)
+#define IER_INTF_TYPE  BIT(1)
+#define IER_IEN                BIT(0)
+
 /* Interrupt status register fields */
 #define ISR_TXFO       BIT(5)
 #define ISR_TXFE       BIT(4)
 #define TFCR(x)                (0x40 * x + 0x04C)
 #define RFF(x)         (0x40 * x + 0x050)
 #define TFF(x)         (0x40 * x + 0x054)
+#define RSLOT_TSLOT(x) (0x4 * (x) + 0x224)
+
+/* Receive enable register fields */
+#define RER_RXSLOT_SHIFT       8
+#define RER_RXCHEN     BIT(0)
+
+/* Transmit enable register fields */
+#define TER_TXSLOT_SHIFT       8
+#define TER_TXCHEN     BIT(0)
 
 /* I2SCOMPRegisters */
 #define I2S_COMP_PARAM_2       0x01F0
@@ -105,6 +121,8 @@ struct dw_i2s_dev {
        u32 ccr;
        u32 xfer_resolution;
        u32 fifo_th;
+       u32 l_reg;
+       u32 r_reg;
 
        /* data related to DMA transfers b/w i2s and DMAC */
        union dw_i2s_snd_dma_data play_dma_data;
@@ -114,6 +132,12 @@ struct dw_i2s_dev {
 
        /* data related to PIO transfers */
        bool use_pio;
+
+       /* data related to TDM mode */
+       u32 tdm_slots;
+       u32 tdm_mask;
+       u32 frame_offset;
+
        struct snd_pcm_substream __rcu *tx_substream;
        struct snd_pcm_substream __rcu *rx_substream;
        unsigned int (*tx_fn)(struct dw_i2s_dev *dev,
index adb8a59de2bd9eaab25daf2d932762c1c017cb2d..b793263291dc8d66520c04723c3f14b7ba2c1601 100644 (file)
@@ -780,13 +780,6 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
-       .startup      = fsl_asrc_dai_startup,
-       .hw_params    = fsl_asrc_dai_hw_params,
-       .hw_free      = fsl_asrc_dai_hw_free,
-       .trigger      = fsl_asrc_dai_trigger,
-};
-
 static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai);
@@ -797,12 +790,19 @@ static int fsl_asrc_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
+       .probe          = fsl_asrc_dai_probe,
+       .startup        = fsl_asrc_dai_startup,
+       .hw_params      = fsl_asrc_dai_hw_params,
+       .hw_free        = fsl_asrc_dai_hw_free,
+       .trigger        = fsl_asrc_dai_trigger,
+};
+
 #define FSL_ASRC_FORMATS       (SNDRV_PCM_FMTBIT_S24_LE | \
                                 SNDRV_PCM_FMTBIT_S16_LE | \
                                 SNDRV_PCM_FMTBIT_S24_3LE)
 
 static struct snd_soc_dai_driver fsl_asrc_dai = {
-       .probe = fsl_asrc_dai_probe,
        .playback = {
                .stream_name = "ASRC-Playback",
                .channels_min = 1,
index 46b0c5dcc4a502d4207d3045333a0fcb26cafa70..fc56f6ade3682749c3afaae98eda2465fad79fc4 100644 (file)
@@ -49,10 +49,6 @@ static int fsl_aud2htx_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
-       .trigger        = fsl_aud2htx_trigger,
-};
-
 static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_aud2htx *aud2htx = dev_get_drvdata(cpu_dai->dev);
@@ -84,8 +80,12 @@ static int fsl_aud2htx_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_aud2htx_dai_ops = {
+       .probe          = fsl_aud2htx_dai_probe,
+       .trigger        = fsl_aud2htx_trigger,
+};
+
 static struct snd_soc_dai_driver fsl_aud2htx_dai = {
-       .probe = fsl_aud2htx_dai_probe,
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 1,
index 670cbdb361b6c7e547cc6ce2a1a61588d455eeb7..ba62995c909ac398de929bd9001fe59c93b5492d 100644 (file)
@@ -1531,13 +1531,6 @@ static int fsl_easrc_hw_free(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
-       .startup = fsl_easrc_startup,
-       .trigger = fsl_easrc_trigger,
-       .hw_params = fsl_easrc_hw_params,
-       .hw_free = fsl_easrc_hw_free,
-};
-
 static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_asrc *easrc = dev_get_drvdata(cpu_dai->dev);
@@ -1548,8 +1541,15 @@ static int fsl_easrc_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
+       .probe          = fsl_easrc_dai_probe,
+       .startup        = fsl_easrc_startup,
+       .trigger        = fsl_easrc_trigger,
+       .hw_params      = fsl_easrc_hw_params,
+       .hw_free        = fsl_easrc_hw_free,
+};
+
 static struct snd_soc_dai_driver fsl_easrc_dai = {
-       .probe = fsl_easrc_dai_probe,
        .playback = {
                .stream_name = "ASRC-Playback",
                .channels_min = 1,
index 936f0cd4b06d8e20c34e9b172f9be581db43da05..d0d8a01da9bdda593a9cfa186b7399a527cf3278 100644 (file)
@@ -785,15 +785,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
-       .startup = fsl_esai_startup,
-       .trigger = fsl_esai_trigger,
-       .hw_params = fsl_esai_hw_params,
-       .set_sysclk = fsl_esai_set_dai_sysclk,
-       .set_fmt = fsl_esai_set_dai_fmt,
-       .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
-};
-
 static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
@@ -804,8 +795,17 @@ static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_esai_dai_ops = {
+       .probe          = fsl_esai_dai_probe,
+       .startup        = fsl_esai_startup,
+       .trigger        = fsl_esai_trigger,
+       .hw_params      = fsl_esai_hw_params,
+       .set_sysclk     = fsl_esai_set_dai_sysclk,
+       .set_fmt        = fsl_esai_set_dai_fmt,
+       .set_tdm_slot   = fsl_esai_set_dai_tdm_slot,
+};
+
 static struct snd_soc_dai_driver fsl_esai_dai = {
-       .probe = fsl_esai_dai_probe,
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 1,
index 3f08082a55bec27e498726cdcd6bcd3c2783a152..0d37edb70261cb64a47dc10659155b0e793d1c06 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 // Copyright 2018 NXP
 
 #include <linux/bitfield.h>
@@ -56,6 +56,8 @@ struct fsl_micfil {
        int vad_init_mode;
        int vad_enabled;
        int vad_detected;
+       struct fsl_micfil_verid verid;
+       struct fsl_micfil_param param;
 };
 
 struct fsl_micfil_soc_data {
@@ -64,6 +66,7 @@ struct fsl_micfil_soc_data {
        unsigned int dataline;
        bool imx;
        bool use_edma;
+       bool use_verid;
        u64  formats;
 };
 
@@ -90,6 +93,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
        .dataline =  0xf,
        .formats = SNDRV_PCM_FMTBIT_S32_LE,
        .use_edma = true,
+       .use_verid = true,
 };
 
 static const struct of_device_id fsl_micfil_dt_ids[] = {
@@ -356,6 +360,49 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
        SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL),
 };
 
+static int fsl_micfil_use_verid(struct device *dev)
+{
+       struct fsl_micfil *micfil = dev_get_drvdata(dev);
+       unsigned int val;
+       int ret;
+
+       if (!micfil->soc->use_verid)
+               return 0;
+
+       ret = regmap_read(micfil->regmap, REG_MICFIL_VERID, &val);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(dev, "VERID: 0x%016X\n", val);
+
+       micfil->verid.version = val &
+               (MICFIL_VERID_MAJOR_MASK | MICFIL_VERID_MINOR_MASK);
+       micfil->verid.version >>= MICFIL_VERID_MINOR_SHIFT;
+       micfil->verid.feature = val & MICFIL_VERID_FEATURE_MASK;
+
+       ret = regmap_read(micfil->regmap, REG_MICFIL_PARAM, &val);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(dev, "PARAM: 0x%016X\n", val);
+
+       micfil->param.hwvad_num = (val & MICFIL_PARAM_NUM_HWVAD_MASK) >>
+               MICFIL_PARAM_NUM_HWVAD_SHIFT;
+       micfil->param.hwvad_zcd = val & MICFIL_PARAM_HWVAD_ZCD;
+       micfil->param.hwvad_energy_mode = val & MICFIL_PARAM_HWVAD_ENERGY_MODE;
+       micfil->param.hwvad = val & MICFIL_PARAM_HWVAD;
+       micfil->param.dc_out_bypass = val & MICFIL_PARAM_DC_OUT_BYPASS;
+       micfil->param.dc_in_bypass = val & MICFIL_PARAM_DC_IN_BYPASS;
+       micfil->param.low_power = val & MICFIL_PARAM_LOW_POWER;
+       micfil->param.fil_out_width = val & MICFIL_PARAM_FIL_OUT_WIDTH;
+       micfil->param.fifo_ptrwid = (val & MICFIL_PARAM_FIFO_PTRWID_MASK) >>
+               MICFIL_PARAM_FIFO_PTRWID_SHIFT;
+       micfil->param.npair = (val & MICFIL_PARAM_NPAIR_MASK) >>
+               MICFIL_PARAM_NPAIR_SHIFT;
+
+       return 0;
+}
+
 /* The SRES is a self-negated bit which provides the CPU with the
  * capability to initialize the PDM Interface module through the
  * slave-bus interface. This bit always reads as zero, and this
@@ -717,12 +764,6 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
-       .startup = fsl_micfil_startup,
-       .trigger = fsl_micfil_trigger,
-       .hw_params = fsl_micfil_hw_params,
-};
-
 static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev);
@@ -760,8 +801,14 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_micfil_dai_ops = {
+       .probe          = fsl_micfil_dai_probe,
+       .startup        = fsl_micfil_startup,
+       .trigger        = fsl_micfil_trigger,
+       .hw_params      = fsl_micfil_hw_params,
+};
+
 static struct snd_soc_dai_driver fsl_micfil_dai = {
-       .probe = fsl_micfil_dai_probe,
        .capture = {
                .stream_name = "CPU-Capture",
                .channels_min = 1,
@@ -825,6 +872,9 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg)
        case REG_MICFIL_DC_CTRL:
        case REG_MICFIL_OUT_CTRL:
        case REG_MICFIL_OUT_STAT:
+       case REG_MICFIL_FSYNC_CTRL:
+       case REG_MICFIL_VERID:
+       case REG_MICFIL_PARAM:
        case REG_MICFIL_VAD0_CTRL1:
        case REG_MICFIL_VAD0_CTRL2:
        case REG_MICFIL_VAD0_STAT:
@@ -849,6 +899,7 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg)
        case REG_MICFIL_DC_CTRL:
        case REG_MICFIL_OUT_CTRL:
        case REG_MICFIL_OUT_STAT:       /* Write 1 to Clear */
+       case REG_MICFIL_FSYNC_CTRL:
        case REG_MICFIL_VAD0_CTRL1:
        case REG_MICFIL_VAD0_CTRL2:
        case REG_MICFIL_VAD0_STAT:      /* Write 1 to Clear */
@@ -873,6 +924,8 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg)
        case REG_MICFIL_DATACH5:
        case REG_MICFIL_DATACH6:
        case REG_MICFIL_DATACH7:
+       case REG_MICFIL_VERID:
+       case REG_MICFIL_PARAM:
        case REG_MICFIL_VAD0_STAT:
        case REG_MICFIL_VAD0_NDATA:
                return true;
@@ -1031,6 +1084,9 @@ static irqreturn_t hwvad_err_isr(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+static int fsl_micfil_runtime_suspend(struct device *dev);
+static int fsl_micfil_runtime_resume(struct device *dev);
+
 static int fsl_micfil_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -1044,7 +1100,7 @@ static int fsl_micfil_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        micfil->pdev = pdev;
-       strncpy(micfil->name, np->name, sizeof(micfil->name) - 1);
+       strscpy(micfil->name, np->name, sizeof(micfil->name));
 
        micfil->soc = of_device_get_match_data(&pdev->dev);
 
@@ -1150,6 +1206,25 @@ static int fsl_micfil_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, micfil);
 
        pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = fsl_micfil_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_pm_disable;
+       }
+
+       ret = pm_runtime_resume_and_get(&pdev->dev);
+       if (ret < 0)
+               goto err_pm_get_sync;
+
+       /* Get micfil version */
+       ret = fsl_micfil_use_verid(&pdev->dev);
+       if (ret < 0)
+               dev_warn(&pdev->dev, "Error reading MICFIL version: %d\n", ret);
+
+       ret = pm_runtime_put_sync(&pdev->dev);
+       if (ret < 0 && ret != -ENOSYS)
+               goto err_pm_get_sync;
+
        regcache_cache_only(micfil->regmap, true);
 
        /*
@@ -1174,6 +1249,9 @@ static int fsl_micfil_probe(struct platform_device *pdev)
 
        return ret;
 
+err_pm_get_sync:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               fsl_micfil_runtime_suspend(&pdev->dev);
 err_pm_disable:
        pm_runtime_disable(&pdev->dev);
 
@@ -1185,7 +1263,7 @@ static void fsl_micfil_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 }
 
-static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev)
+static int fsl_micfil_runtime_suspend(struct device *dev)
 {
        struct fsl_micfil *micfil = dev_get_drvdata(dev);
 
@@ -1197,7 +1275,7 @@ static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
+static int fsl_micfil_runtime_resume(struct device *dev)
 {
        struct fsl_micfil *micfil = dev_get_drvdata(dev);
        int ret;
@@ -1219,26 +1297,12 @@ static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused fsl_micfil_suspend(struct device *dev)
-{
-       pm_runtime_force_suspend(dev);
-
-       return 0;
-}
-
-static int __maybe_unused fsl_micfil_resume(struct device *dev)
-{
-       pm_runtime_force_resume(dev);
-
-       return 0;
-}
-
 static const struct dev_pm_ops fsl_micfil_pm_ops = {
        SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend,
                           fsl_micfil_runtime_resume,
                           NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend,
-                               fsl_micfil_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver fsl_micfil_driver = {
@@ -1254,4 +1318,4 @@ module_platform_driver(fsl_micfil_driver);
 
 MODULE_AUTHOR("Cosmin-Gabriel Samoila <cosmin.samoila@nxp.com>");
 MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("Dual BSD/GPL");
index 9237a1c4cb8f7781671acb5c4f9e2e42dd732ab4..c6b902ba0a5317d4ead1ce6ec320d8901f0fb69b 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
  * PDM Microphone Interface for the NXP i.MX SoC
  * Copyright 2018 NXP
@@ -24,6 +24,9 @@
 #define REG_MICFIL_DC_CTRL             0x64
 #define REG_MICFIL_OUT_CTRL            0x74
 #define REG_MICFIL_OUT_STAT            0x7C
+#define REG_MICFIL_FSYNC_CTRL          0x80
+#define REG_MICFIL_VERID               0x84
+#define REG_MICFIL_PARAM               0x88
 #define REG_MICFIL_VAD0_CTRL1          0x90
 #define REG_MICFIL_VAD0_CTRL2          0x94
 #define REG_MICFIL_VAD0_STAT           0x98
@@ -39,6 +42,8 @@
 #define MICFIL_CTRL1_DBG               BIT(28)
 #define MICFIL_CTRL1_SRES              BIT(27)
 #define MICFIL_CTRL1_DBGE              BIT(26)
+#define MICFIL_CTRL1_DECFILS           BIT(20)
+#define MICFIL_CTRL1_FSYNCEN           BIT(16)
 
 #define MICFIL_CTRL1_DISEL_DISABLE     0
 #define MICFIL_CTRL1_DISEL_DMA         1
 #define MICFIL_DC_CUTOFF_152Hz         2
 #define MICFIL_DC_BYPASS               3
 
+/* MICFIL VERID Register -- REG_MICFIL_VERID */
+#define MICFIL_VERID_MAJOR_SHIFT        24
+#define MICFIL_VERID_MAJOR_MASK         GENMASK(31, 24)
+#define MICFIL_VERID_MINOR_SHIFT        16
+#define MICFIL_VERID_MINOR_MASK         GENMASK(23, 16)
+#define MICFIL_VERID_FEATURE_SHIFT      0
+#define MICFIL_VERID_FEATURE_MASK       GENMASK(15, 0)
+
+/* MICFIL PARAM Register -- REG_MICFIL_PARAM */
+#define MICFIL_PARAM_NUM_HWVAD_SHIFT    24
+#define MICFIL_PARAM_NUM_HWVAD_MASK     GENMASK(27, 24)
+#define MICFIL_PARAM_HWVAD_ZCD          BIT(19)
+#define MICFIL_PARAM_HWVAD_ENERGY_MODE  BIT(17)
+#define MICFIL_PARAM_HWVAD              BIT(16)
+#define MICFIL_PARAM_DC_OUT_BYPASS      BIT(11)
+#define MICFIL_PARAM_DC_IN_BYPASS       BIT(10)
+#define MICFIL_PARAM_LOW_POWER          BIT(9)
+#define MICFIL_PARAM_FIL_OUT_WIDTH      BIT(8)
+#define MICFIL_PARAM_FIFO_PTRWID_SHIFT  4
+#define MICFIL_PARAM_FIFO_PTRWID_MASK   GENMASK(7, 4)
+#define MICFIL_PARAM_NPAIR_SHIFT        0
+#define MICFIL_PARAM_NPAIR_MASK         GENMASK(3, 0)
+
 /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/
 #define MICFIL_VAD0_CTRL1_CHSEL                GENMASK(26, 24)
 #define MICFIL_VAD0_CTRL1_CICOSR       GENMASK(19, 16)
 #define MICFIL_HWVAD_ENVELOPE_MODE     0
 #define MICFIL_HWVAD_ENERGY_MODE       1
 
+/**
+ * struct fsl_micfil_verid - version id data
+ * @version: version number
+ * @feature: feature specification number
+ */
+struct fsl_micfil_verid {
+       u32 version;
+       u32 feature;
+};
+
+/**
+ * struct fsl_micfil_param - parameter data
+ * @hwvad_num: the number of HWVADs
+ * @hwvad_zcd: HWVAD zero-cross detector is active
+ * @hwvad_energy_mode: HWVAD energy mode is active
+ * @hwvad: HWVAD is active
+ * @dc_out_bypass: points out if the output DC remover is disabled
+ * @dc_in_bypass: points out if the input DC remover is disabled
+ * @low_power: low power decimation filter
+ * @fil_out_width: filter output width
+ * @fifo_ptrwid: FIFO pointer width
+ * @npair: number of microphone pairs
+ */
+struct fsl_micfil_param {
+       u32 hwvad_num;
+       bool hwvad_zcd;
+       bool hwvad_energy_mode;
+       bool hwvad;
+       bool dc_out_bypass;
+       bool dc_in_bypass;
+       bool low_power;
+       bool fil_out_width;
+       u32 fifo_ptrwid;
+       u32 npair;
+};
+
 #endif /* _FSL_MICFIL_H */
index 7cbb8e4758ccc631ccc3a2d3f9961c736b3a6f20..56d6b0b039a2e9af340f5aa70d585204f3b861be 100644 (file)
@@ -372,8 +372,8 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
        struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        unsigned int channels = params_channels(params);
        unsigned int slot_width;
+       snd_pcm_format_t format;
        struct snd_mask f_new;
-       unsigned int i;
 
        if (!channels || channels > nb_ts) {
                dev_err(qmc_dai->dev, "channels %u not supported\n",
@@ -384,10 +384,10 @@ static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_dai,
        slot_width = (nb_ts / channels) * 8;
 
        snd_mask_none(&f_new);
-       for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
-               if (snd_mask_test(f_old, i)) {
-                       if (snd_pcm_format_physical_width(i) <= slot_width)
-                               snd_mask_set(&f_new, i);
+       pcm_for_each_format(format) {
+               if (snd_mask_test_format(f_old, format)) {
+                       if (snd_pcm_format_physical_width(format) <= slot_width)
+                               snd_mask_set_format(&f_new, format);
                }
        }
 
@@ -551,26 +551,26 @@ static const struct snd_soc_dai_ops qmc_dai_ops = {
 
 static u64 qmc_audio_formats(u8 nb_ts)
 {
-       u64 formats;
-       unsigned int chan_width;
        unsigned int format_width;
-       int i;
+       unsigned int chan_width;
+       snd_pcm_format_t format;
+       u64 formats_mask;
 
        if (!nb_ts)
                return 0;
 
-       formats = 0;
+       formats_mask = 0;
        chan_width = nb_ts * 8;
-       for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+       pcm_for_each_format(format) {
                /*
                 * Support format other than little-endian (ie big-endian or
                 * without endianness such as 8bit formats)
                 */
-               if (snd_pcm_format_little_endian(i) == 1)
+               if (snd_pcm_format_little_endian(format) == 1)
                        continue;
 
                /* Support physical width multiple of 8bit */
-               format_width = snd_pcm_format_physical_width(i);
+               format_width = snd_pcm_format_physical_width(format);
                if (format_width == 0 || format_width % 8)
                        continue;
 
@@ -581,9 +581,9 @@ static u64 qmc_audio_formats(u8 nb_ts)
                if (format_width > chan_width || chan_width % format_width)
                        continue;
 
-               formats |= (1ULL << i);
+               formats_mask |= pcm_format_to_bits(format);
        }
-       return formats;
+       return formats_mask;
 }
 
 static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
index 15b48b5ea856599d849c53c26e77cade36e39a96..abe19a8a7aa72dce19fb73a8cb84f2f8ef010988 100644 (file)
@@ -170,12 +170,20 @@ static const struct fsl_rpmsg_soc_data imx8mp_data = {
                   SNDRV_PCM_FMTBIT_S32_LE,
 };
 
+static const struct fsl_rpmsg_soc_data imx93_data = {
+       .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |
+                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+                  SNDRV_PCM_FMTBIT_S32_LE,
+};
+
 static const struct of_device_id fsl_rpmsg_ids[] = {
        { .compatible = "fsl,imx7ulp-rpmsg-audio", .data = &imx7ulp_data},
        { .compatible = "fsl,imx8mm-rpmsg-audio", .data = &imx8mm_data},
        { .compatible = "fsl,imx8mn-rpmsg-audio", .data = &imx8mn_data},
        { .compatible = "fsl,imx8mp-rpmsg-audio", .data = &imx8mp_data},
        { .compatible = "fsl,imx8ulp-rpmsg-audio", .data = &imx7ulp_data},
+       { .compatible = "fsl,imx93-rpmsg-audio", .data = &imx93_data},
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
index f7676d30c82fd3dc77b7f937b67e3a129906a56d..1e4020fae05abbbb55c403d261a50ba857b31e3e 100644 (file)
@@ -849,17 +849,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
-       .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
-       .set_sysclk     = fsl_sai_set_dai_sysclk,
-       .set_fmt        = fsl_sai_set_dai_fmt,
-       .set_tdm_slot   = fsl_sai_set_dai_tdm_slot,
-       .hw_params      = fsl_sai_hw_params,
-       .hw_free        = fsl_sai_hw_free,
-       .trigger        = fsl_sai_trigger,
-       .startup        = fsl_sai_startup,
-};
-
 static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
@@ -885,6 +874,18 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+       .probe          = fsl_sai_dai_probe,
+       .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
+       .set_sysclk     = fsl_sai_set_dai_sysclk,
+       .set_fmt        = fsl_sai_set_dai_fmt,
+       .set_tdm_slot   = fsl_sai_set_dai_tdm_slot,
+       .hw_params      = fsl_sai_hw_params,
+       .hw_free        = fsl_sai_hw_free,
+       .trigger        = fsl_sai_trigger,
+       .startup        = fsl_sai_startup,
+};
+
 static int fsl_sai_dai_resume(struct snd_soc_component *component)
 {
        struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
@@ -903,7 +904,6 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
 }
 
 static struct snd_soc_dai_driver fsl_sai_dai_template = {
-       .probe = fsl_sai_dai_probe,
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 1,
index 3fd26f2cdd60f3e4d4baabc2ed84ea3f74f5c913..78d9dfbe65484edcafdb4cf83b719f6e760a963a 100644 (file)
@@ -514,6 +514,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
        int ret;
 
        switch (sample_rate) {
+       case 22050:
+               rate = SPDIF_TXRATE_22050;
+               csfs = IEC958_AES3_CON_FS_22050;
+               break;
        case 32000:
                rate = SPDIF_TXRATE_32000;
                csfs = IEC958_AES3_CON_FS_32000;
@@ -761,14 +765,6 @@ static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
-       .startup = fsl_spdif_startup,
-       .hw_params = fsl_spdif_hw_params,
-       .trigger = fsl_spdif_trigger,
-       .shutdown = fsl_spdif_shutdown,
-};
-
-
 /*
  * FSL SPDIF IEC958 controller(mixer) functions
  *
@@ -1279,8 +1275,15 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+       .probe          = fsl_spdif_dai_probe,
+       .startup        = fsl_spdif_startup,
+       .hw_params      = fsl_spdif_hw_params,
+       .trigger        = fsl_spdif_trigger,
+       .shutdown       = fsl_spdif_shutdown,
+};
+
 static struct snd_soc_dai_driver fsl_spdif_dai = {
-       .probe = &fsl_spdif_dai_probe,
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 2,
@@ -1424,7 +1427,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
                                struct clk *clk, u64 savesub,
                                enum spdif_txrate index, bool round)
 {
-       static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+       static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400,
                                    192000, };
        bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
        u64 rate_ideal, rate_actual, sub;
@@ -1485,7 +1488,7 @@ out:
 static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
                                enum spdif_txrate index)
 {
-       static const u32 rate[] = { 32000, 44100, 48000, 88200, 96000, 176400,
+       static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400,
                                    192000, };
        struct platform_device *pdev = spdif_priv->pdev;
        struct device *dev = &pdev->dev;
index 75b42a692c90ed5d5b3ecf5655b0f4b05398c462..2bc1b10c17d4bf54c83aa6148c825d7f8ed01d2b 100644 (file)
@@ -175,7 +175,8 @@ enum spdif_gainsel {
 
 /* SPDIF tx rate */
 enum spdif_txrate {
-       SPDIF_TXRATE_32000 = 0,
+       SPDIF_TXRATE_22050 = 0,
+       SPDIF_TXRATE_32000,
        SPDIF_TXRATE_44100,
        SPDIF_TXRATE_48000,
        SPDIF_TXRATE_88200,
@@ -191,7 +192,8 @@ enum spdif_txrate {
 #define SPDIF_QSUB_SIZE                        (SPDIF_UBITS_SIZE / 8)
 
 
-#define FSL_SPDIF_RATES_PLAYBACK       (SNDRV_PCM_RATE_32000 | \
+#define FSL_SPDIF_RATES_PLAYBACK       (SNDRV_PCM_RATE_22050 | \
+                                        SNDRV_PCM_RATE_32000 | \
                                         SNDRV_PCM_RATE_44100 | \
                                         SNDRV_PCM_RATE_48000 | \
                                         SNDRV_PCM_RATE_88200 | \
index 53ed3701b0b0e83d578f551056247d0d017cba3d..079ac04272b854277823801da6c44a7118716ca6 100644 (file)
@@ -1152,6 +1152,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+       .probe = fsl_ssi_dai_probe,
        .startup = fsl_ssi_startup,
        .shutdown = fsl_ssi_shutdown,
        .hw_params = fsl_ssi_hw_params,
@@ -1162,7 +1163,6 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
 };
 
 static struct snd_soc_dai_driver fsl_ssi_dai_template = {
-       .probe = fsl_ssi_dai_probe,
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 1,
@@ -1187,7 +1187,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
 
 static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
        .symmetric_channels = 1,
-       .probe = fsl_ssi_dai_probe,
        .playback = {
                .stream_name = "CPU AC97 Playback",
                .channels_min = 2,
index 318fe77683f56bed3dc706a71804234a92b0d3bf..fa0a15263c66dc117dcdd7886de6e9e19660ff22 100644 (file)
@@ -888,13 +888,6 @@ static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = {
        },
 };
 
-static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
-       .prepare = fsl_xcvr_prepare,
-       .startup = fsl_xcvr_startup,
-       .shutdown = fsl_xcvr_shutdown,
-       .trigger = fsl_xcvr_trigger,
-};
-
 static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
@@ -915,8 +908,15 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops fsl_xcvr_dai_ops = {
+       .probe          = fsl_xcvr_dai_probe,
+       .prepare        = fsl_xcvr_prepare,
+       .startup        = fsl_xcvr_startup,
+       .shutdown       = fsl_xcvr_shutdown,
+       .trigger        = fsl_xcvr_trigger,
+};
+
 static struct snd_soc_dai_driver fsl_xcvr_dai = {
-       .probe  = fsl_xcvr_dai_probe,
        .ops = &fsl_xcvr_dai_ops,
        .playback = {
                .stream_name = "CPU-Playback",
index d5234ac4b09b2af236f521971e40cf4622a33f2c..289e47c03d402646cc99a50bc1edacecb406868b 100644 (file)
@@ -116,7 +116,6 @@ static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
 
 static struct rpmsg_driver imx_audio_rpmsg_driver = {
        .drv.name       = "imx_audio_rpmsg",
-       .drv.owner      = THIS_MODULE,
        .id_table       = imx_audio_rpmsg_id_table,
        .probe          = imx_audio_rpmsg_probe,
        .callback       = imx_audio_rpmsg_cb,
index 85bd36fb68a2290180f539723b7ed1251fa057a7..6f0d031c1d5fd7a16edccfbc0ab81e881dbc85d1 100644 (file)
@@ -37,6 +37,16 @@ static struct snd_soc_jack_gpio headset_jack_gpios[] = {
 };
 
 static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
 
 static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
@@ -46,9 +56,11 @@ static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
 
        /* Headphone jack detection */
        if (gpio_is_valid(data->jack_gpio)) {
-               ret = snd_soc_card_jack_new(rtd->card, "Headphone",
-                                           SND_JACK_HEADPHONE | SND_JACK_BTN_0,
-                                           &headset_jack);
+               ret = snd_soc_card_jack_new_pins(rtd->card, "Headphone",
+                                                SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                                &headset_jack,
+                                                headset_jack_pins,
+                                                ARRAY_SIZE(headset_jack_pins));
                if (ret)
                        return ret;
 
@@ -68,6 +80,11 @@ static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
        SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
 };
 
+static const struct snd_kcontrol_new imx_es8328_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
+
 static int imx_es8328_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -183,6 +200,8 @@ static int imx_es8328_probe(struct platform_device *pdev)
        data->card.dev = dev;
        data->card.dapm_widgets = imx_es8328_dapm_widgets;
        data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
+       data->card.controls = imx_es8328_controls;
+       data->card.num_controls = ARRAY_SIZE(imx_es8328_controls);
        ret = snd_soc_of_parse_card_name(&data->card, "model");
        if (ret) {
                dev_err(dev, "Unable to parse card name\n");
index 765dad607bf6133f1123b87c6145509ef99702e3..d63782b8bdef8f8b27d9669dabdc550cd0445f5a 100644 (file)
@@ -228,6 +228,10 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
                              struct snd_pcm_substream *substream)
 {
        struct rpmsg_info *info = dev_get_drvdata(component->dev);
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+       struct snd_pcm_hardware pcm_hardware;
        struct rpmsg_msg *msg;
        int ret = 0;
        int cmd;
@@ -255,10 +259,11 @@ static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
 
        info->send_message(msg, info);
 
-       imx_rpmsg_pcm_hardware.period_bytes_max =
-                       imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
+       pcm_hardware = imx_rpmsg_pcm_hardware;
+       pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
+       pcm_hardware.period_bytes_max = pcm_hardware.buffer_bytes_max / 2;
 
-       snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
+       snd_soc_set_runtime_hwparams(substream, &pcm_hardware);
 
        ret = snd_pcm_hw_constraint_integer(substream->runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
@@ -597,7 +602,6 @@ static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
        if (ret)
                return ret;
 
-       imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
        return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
                                            pcm->card->dev, rpmsg->buffer_size);
 }
index c6e0f91321930e9239606469b2f5cd0f2321bc78..13693ef9c242078afd5bebb94db3342085df5bd9 100644 (file)
@@ -60,7 +60,7 @@ static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
        struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
 
        if (dai && (dai->component->driver->pcm_construct ||
-                   dai->driver->pcm_new))
+                   (dai->driver->ops && dai->driver->ops->pcm_new)))
                return true;
 
        return false;
@@ -126,7 +126,7 @@ static int graph_parse_node(struct asoc_simple_priv *priv,
 
        graph_parse_mclk_fs(top, ep, dai_props);
 
-       ret = asoc_graph_parse_dai(ep, dlc, cpu);
+       ret = asoc_graph_parse_dai(dev, ep, dlc, cpu);
        if (ret < 0)
                return ret;
 
index 542c4a1149403a2023bd4f50e8473ae4f5f76548..98732468a992cacf04b29684b85de6ea8998cb8d 100644 (file)
@@ -407,7 +407,7 @@ static int __graph_parse_node(struct asoc_simple_priv *priv,
 
        graph_parse_mclk_fs(ep, dai_props);
 
-       ret = asoc_graph_parse_dai(ep, dlc, &is_single_links);
+       ret = asoc_graph_parse_dai(dev, ep, dlc, &is_single_links);
        if (ret < 0)
                return ret;
 
index 3019626b05927dc9209dd10c1fe4ad7f149d17d3..5b18a4af022f19a1c14cf734f1df0f1f8609f64d 100644 (file)
@@ -649,7 +649,7 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platfo
         *      simple-card.c :: simple_count_noml()
         */
        if (!platforms->of_node)
-               platforms->of_node = cpus->of_node;
+               snd_soc_dlc_use_cpu_as_platform(platforms, cpus);
 }
 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform);
 
@@ -1066,12 +1066,12 @@ static int graph_get_dai_id(struct device_node *ep)
        return id;
 }
 
-int asoc_graph_parse_dai(struct device_node *ep,
-                        struct snd_soc_dai_link_component *dlc,
-                        int *is_single_link)
+int asoc_graph_parse_dai(struct device *dev, struct device_node *ep,
+                        struct snd_soc_dai_link_component *dlc, int *is_single_link)
 {
        struct device_node *node;
        struct of_phandle_args args = {};
+       struct snd_soc_dai *dai;
        int ret;
 
        if (!ep)
@@ -1079,6 +1079,20 @@ int asoc_graph_parse_dai(struct device_node *ep,
 
        node = of_graph_get_port_parent(ep);
 
+       /*
+        * Try to find from DAI node
+        */
+       args.np = ep;
+       dai = snd_soc_get_dai_via_args(&args);
+       if (dai) {
+               dlc->dai_name = snd_soc_dai_name_get(dai);
+               dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
+               if (!dlc->dai_args)
+                       return -ENOMEM;
+
+               goto parse_dai_end;
+       }
+
        /* Get dai->name */
        args.np         = node;
        args.args[0]    = graph_get_dai_id(ep);
@@ -1109,6 +1123,7 @@ int asoc_graph_parse_dai(struct device_node *ep,
                return ret;
        }
 
+parse_dai_end:
        if (is_single_link)
                *is_single_link = of_graph_get_endpoint_count(node) == 1;
 
index 0745bf6a09aa0a20457f21ff54bad0af39de395b..190f11366e84e0075625604f341d633f4b0075dd 100644 (file)
@@ -52,11 +52,13 @@ static int asoc_simple_parse_platform(struct device_node *node,
        return 0;
 }
 
-static int asoc_simple_parse_dai(struct device_node *node,
+static int asoc_simple_parse_dai(struct device *dev,
+                                struct device_node *node,
                                 struct snd_soc_dai_link_component *dlc,
                                 int *is_single_link)
 {
        struct of_phandle_args args;
+       struct snd_soc_dai *dai;
        int ret;
 
        if (!node)
@@ -70,6 +72,19 @@ static int asoc_simple_parse_dai(struct device_node *node,
        if (ret)
                return ret;
 
+       /*
+        * Try to find from DAI args
+        */
+       dai = snd_soc_get_dai_via_args(&args);
+       if (dai) {
+               dlc->dai_name = snd_soc_dai_name_get(dai);
+               dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
+               if (!dlc->dai_args)
+                       return -ENOMEM;
+
+               goto parse_dai_end;
+       }
+
        /*
         * FIXME
         *
@@ -93,6 +108,7 @@ static int asoc_simple_parse_dai(struct device_node *node,
        if (ret < 0)
                return ret;
 
+parse_dai_end:
        if (is_single_link)
                *is_single_link = !args.args_count;
 
@@ -156,7 +172,7 @@ static int simple_parse_node(struct asoc_simple_priv *priv,
 
        simple_parse_mclk_fs(top, np, dai_props, prefix);
 
-       ret = asoc_simple_parse_dai(np, dlc, cpu);
+       ret = asoc_simple_parse_dai(dev, np, dlc, cpu);
        if (ret)
                return ret;
 
@@ -346,6 +362,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
        struct device *dev = simple_priv_to_dev(priv);
        struct device_node *top = dev->of_node;
        struct device_node *node;
+       struct device_node *add_devs;
        uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
        bool is_top = 0;
        int ret = 0;
@@ -357,6 +374,8 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
                is_top = 1;
        }
 
+       add_devs = of_get_child_by_name(top, PREFIX "additional-devs");
+
        /* loop for all dai-link */
        do {
                struct asoc_simple_data adata;
@@ -365,6 +384,12 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
                struct device_node *np;
                int num = of_get_child_count(node);
 
+               /* Skip additional-devs node */
+               if (node == add_devs) {
+                       node = of_get_next_child(top, node);
+                       continue;
+               }
+
                /* get codec */
                codec = of_get_child_by_name(node, is_top ?
                                             PREFIX "codec" : "codec");
@@ -378,12 +403,15 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 
                /* get convert-xxx property */
                memset(&adata, 0, sizeof(adata));
-               for_each_child_of_node(node, np)
+               for_each_child_of_node(node, np) {
+                       if (np == add_devs)
+                               continue;
                        simple_parse_convert(dev, np, &adata);
+               }
 
                /* loop for all CPU/Codec node */
                for_each_child_of_node(node, np) {
-                       if (plat == np)
+                       if (plat == np || add_devs == np)
                                continue;
                        /*
                         * It is DPCM
@@ -426,6 +454,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
        } while (!is_top && node);
 
  error:
+       of_node_put(add_devs);
        of_node_put(node);
        return ret;
 }
@@ -463,6 +492,31 @@ static int simple_for_each_link(struct asoc_simple_priv *priv,
        return ret;
 }
 
+static void simple_depopulate_aux(void *data)
+{
+       struct asoc_simple_priv *priv = data;
+
+       of_platform_depopulate(simple_priv_to_dev(priv));
+}
+
+static int simple_populate_aux(struct asoc_simple_priv *priv)
+{
+       struct device *dev = simple_priv_to_dev(priv);
+       struct device_node *node;
+       int ret;
+
+       node = of_get_child_by_name(dev->of_node, PREFIX "additional-devs");
+       if (!node)
+               return 0;
+
+       ret = of_platform_populate(node, NULL, NULL, dev);
+       of_node_put(node);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, simple_depopulate_aux, priv);
+}
+
 static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
 {
        struct snd_soc_card *card = simple_priv_to_card(priv);
@@ -492,6 +546,10 @@ static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li)
        if (ret < 0)
                return ret;
 
+       ret = simple_populate_aux(priv);
+       if (ret < 0)
+               return ret;
+
        ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
 
        return ret;
index 27219a9e7d0d84c8bf79b963bae1e0a1e6505e97..dd7d2a077248cda87c5a43e33aaaed3444673137 100644 (file)
@@ -511,6 +511,7 @@ static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
 
 
 static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
+       .probe          = hi6210_i2s_dai_probe,
        .trigger        = hi6210_i2s_trigger,
        .hw_params      = hi6210_i2s_hw_params,
        .set_fmt        = hi6210_i2s_set_fmt,
@@ -519,7 +520,6 @@ static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
 };
 
 static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
-       .probe          = hi6210_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index b7ab8467b5cf7d094ddca93630230874b5b773f9..b6b6339c164bcb0db745bcbb1dbcb451e4d40742 100644 (file)
@@ -370,12 +370,6 @@ static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
-       .trigger = img_i2s_in_trigger,
-       .hw_params = img_i2s_in_hw_params,
-       .set_fmt = img_i2s_in_set_fmt
-};
-
 static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
 {
        struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai);
@@ -385,6 +379,13 @@ static int img_i2s_in_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops img_i2s_in_dai_ops = {
+       .probe          = img_i2s_in_dai_probe,
+       .trigger        = img_i2s_in_trigger,
+       .hw_params      = img_i2s_in_hw_params,
+       .set_fmt        = img_i2s_in_set_fmt
+};
+
 static const struct snd_soc_component_driver img_i2s_in_component = {
        .name = "img-i2s-in",
        .legacy_dai_naming = 1,
@@ -468,7 +469,6 @@ static int img_i2s_in_probe(struct platform_device *pdev)
        i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO;
        i2s->dma_data.addr_width = 4;
 
-       i2s->dai_driver.probe = img_i2s_in_dai_probe;
        i2s->dai_driver.capture.channels_min = 2;
        i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2;
        i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000;
index fe95ddfb840775879025a613bca362abf2ee8bc9..41ea5ba52181e9ab2079c9e9ecbbdcf20e54a3ca 100644 (file)
@@ -376,12 +376,6 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
-       .trigger = img_i2s_out_trigger,
-       .hw_params = img_i2s_out_hw_params,
-       .set_fmt = img_i2s_out_set_fmt
-};
-
 static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
 {
        struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
@@ -391,6 +385,13 @@ static int img_i2s_out_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops img_i2s_out_dai_ops = {
+       .probe          = img_i2s_out_dai_probe,
+       .trigger        = img_i2s_out_trigger,
+       .hw_params      = img_i2s_out_hw_params,
+       .set_fmt        = img_i2s_out_set_fmt
+};
+
 static const struct snd_soc_component_driver img_i2s_out_component = {
        .name = "img-i2s-out",
        .legacy_dai_naming = 1,
@@ -504,7 +505,6 @@ static int img_i2s_out_probe(struct platform_device *pdev)
        i2s->dma_data.addr_width = 4;
        i2s->dma_data.maxburst = 4;
 
-       i2s->dai_driver.probe = img_i2s_out_dai_probe;
        i2s->dai_driver.playback.channels_min = 2;
        i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2;
        i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000;
index df1291ee2b3b36b326d5453ccdf1ab2c3234dbff..815e68a7048ccca76e43e21be7ba857f5a364f6b 100644 (file)
@@ -174,12 +174,6 @@ static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
-       .trigger = img_prl_out_trigger,
-       .hw_params = img_prl_out_hw_params,
-       .set_fmt = img_prl_out_set_fmt
-};
-
 static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
 {
        struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai);
@@ -189,8 +183,14 @@ static int img_prl_out_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops img_prl_out_dai_ops = {
+       .probe          = img_prl_out_dai_probe,
+       .trigger        = img_prl_out_trigger,
+       .hw_params      = img_prl_out_hw_params,
+       .set_fmt        = img_prl_out_set_fmt
+};
+
 static struct snd_soc_dai_driver img_prl_out_dai = {
-       .probe = img_prl_out_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index 558062a1804ac2318b8622a32320107df1019ce7..9646e9d3f0bc450f98926e495c1c79b340ab5185 100644 (file)
@@ -682,11 +682,6 @@ static int img_spdif_in_hw_params(struct snd_pcm_substream *substream,
        return img_spdif_in_do_clkgen_single(spdif, rate);
 }
 
-static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
-       .trigger = img_spdif_in_trigger,
-       .hw_params = img_spdif_in_hw_params
-};
-
 static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
 {
        struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai);
@@ -699,8 +694,13 @@ static int img_spdif_in_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops img_spdif_in_dai_ops = {
+       .probe          = img_spdif_in_dai_probe,
+       .trigger        = img_spdif_in_trigger,
+       .hw_params      = img_spdif_in_hw_params
+};
+
 static struct snd_soc_dai_driver img_spdif_in_dai = {
-       .probe = img_spdif_in_dai_probe,
        .capture = {
                .channels_min = 2,
                .channels_max = 2,
index b13e128e50d6d1970a6a02897eb2e23ab950f9f9..dfa72afa946e4811645f836e96177e3bc3abf59d 100644 (file)
@@ -287,11 +287,6 @@ static int img_spdif_out_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
-       .trigger = img_spdif_out_trigger,
-       .hw_params = img_spdif_out_hw_params
-};
-
 static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
 {
        struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai);
@@ -304,8 +299,13 @@ static int img_spdif_out_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops img_spdif_out_dai_ops = {
+       .probe          = img_spdif_out_dai_probe,
+       .trigger        = img_spdif_out_trigger,
+       .hw_params      = img_spdif_out_hw_params
+};
+
 static struct snd_soc_dai_driver img_spdif_out_dai = {
-       .probe = img_spdif_out_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index ba4597bdf32e72475f01397a59256ca489354447..6f986c7bbc8bc13e20d427ee7190a5856a7a6008 100644 (file)
@@ -467,6 +467,7 @@ static const struct snd_soc_dai_ops sst_media_dai_ops = {
 };
 
 static const struct snd_soc_dai_ops sst_compr_dai_ops = {
+       .compress_new = snd_soc_new_compress,
        .mute_stream = sst_media_digital_mute,
 };
 
@@ -510,7 +511,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 },
 {
        .name = "compress-cpu-dai",
-       .compress_new = snd_soc_new_compress,
        .ops = &sst_compr_dai_ops,
        .playback = {
                .stream_name = "Compress Playback",
index a0d29510d2bc486cbaeb7f3a9bae4287136e2aeb..e0357d257c6c3c63c7baeae7721a85a9d5368dc0 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/firmware.h>
+#include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_qos.h>
 #include <linux/async.h>
@@ -174,9 +175,9 @@ int sst_driver_ops(struct intel_sst_drv *sst)
 {
 
        switch (sst->dev_id) {
-       case SST_MRFLD_PCI_ID:
-       case SST_BYT_ACPI_ID:
-       case SST_CHV_ACPI_ID:
+       case PCI_DEVICE_ID_INTEL_SST_TNG:
+       case PCI_DEVICE_ID_INTEL_SST_BYT:
+       case PCI_DEVICE_ID_INTEL_SST_BSW:
                sst->tstamp = SST_TIME_STAMP_MRFLD;
                sst->ops = &mrfld_ops;
                return 0;
@@ -221,8 +222,13 @@ static void sst_init_locks(struct intel_sst_drv *ctx)
        spin_lock_init(&ctx->block_lock);
 }
 
+/*
+ * Driver handles PCI IDs in ACPI - sst_acpi_probe() - and we are using only
+ * device ID part. If real ACPI ID appears, the kstrtouint() returns error, so
+ * we are fine with using unsigned short as dev_id type.
+ */
 int sst_alloc_drv_context(struct intel_sst_drv **ctx,
-               struct device *dev, unsigned int dev_id)
+               struct device *dev, unsigned short dev_id)
 {
        *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL);
        if (!(*ctx))
index 4d37d39fd8f42aa101c1bae304221dcd1b54162b..126903e126e45f64644802141d197f6f50f3c621 100644 (file)
@@ -20,9 +20,6 @@
 
 /* driver names */
 #define SST_DRV_NAME "intel_sst_driver"
-#define SST_MRFLD_PCI_ID 0x119A
-#define SST_BYT_ACPI_ID        0x80860F28
-#define SST_CHV_ACPI_ID        0x808622A8
 
 #define SST_SUSPEND_DELAY 2000
 #define FW_CONTEXT_MEM (64*1024)
@@ -358,7 +355,7 @@ struct sst_fw_save {
 struct intel_sst_drv {
        int                     sst_state;
        int                     irq_num;
-       unsigned int            dev_id;
+       unsigned short          dev_id;
        void __iomem            *ddr;
        void __iomem            *shim;
        void __iomem            *mailbox;
@@ -523,7 +520,7 @@ int sst_register(struct device *);
 int sst_unregister(struct device *);
 
 int sst_alloc_drv_context(struct intel_sst_drv **ctx,
-               struct device *dev, unsigned int dev_id);
+               struct device *dev, unsigned short dev_id);
 int sst_context_init(struct intel_sst_drv *ctx);
 void sst_context_cleanup(struct intel_sst_drv *ctx);
 void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
index 4058b4f80a0cf067421eb001807314ba5d8ffd38..d1e64c3500be1783aab50cc9abcb33dec6646db3 100644 (file)
@@ -32,7 +32,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
 
        /* map registers */
        /* DDR base */
-       if (ctx->dev_id == SST_MRFLD_PCI_ID) {
+       if (ctx->dev_id == PCI_DEVICE_ID_INTEL_SST_TNG) {
                ctx->ddr_base = pci_resource_start(pci, 0);
                /* check that the relocated IMR base matches with FW Binary */
                ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
@@ -173,7 +173,7 @@ static void intel_sst_remove(struct pci_dev *pci)
 
 /* PCI Routines */
 static const struct pci_device_id intel_sst_ids[] = {
-       { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
+       { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
        { 0, }
 };
 
index 862a19ae54299f071391fd533a9be91ef27d1800..288221db7323f600c7007aa4b18f991e1750d01a 100644 (file)
@@ -173,10 +173,11 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
        u32 length;
        int pvt_id, ret = 0;
        struct sst_block *block = NULL;
+       u8 bytes_block = bytes->block;
 
        dev_dbg(sst_drv_ctx->dev,
                "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
-               bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
+               bytes->type, bytes->ipc_msg, bytes_block, bytes->task_id,
                bytes->pipe_id, bytes->len);
 
        if (sst_create_ipc_msg(&msg, true))
@@ -185,12 +186,12 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
        pvt_id = sst_assign_pvt_id(sst_drv_ctx);
        sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
                        bytes->task_id, 1, pvt_id);
-       msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
+       msg->mrfld_header.p.header_high.part.res_rqd = bytes_block;
        length = bytes->len;
        msg->mrfld_header.p.header_low_payload = length;
        dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
        memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
-       if (bytes->block) {
+       if (bytes_block) {
                block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
                if (block == NULL) {
                        kfree(msg);
@@ -203,7 +204,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
        dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
                        msg->mrfld_header.p.header_low_payload);
 
-       if (bytes->block) {
+       if (bytes_block) {
                ret = sst_wait_timeout(sst_drv_ctx, block);
                if (ret) {
                        dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
@@ -216,7 +217,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
                 * copy the reply and send back
                 * we need to update only sz and payload
                 */
-               if (bytes->block) {
+               if (bytes_block) {
                        unsigned char *r = block->data;
 
                        dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
@@ -224,7 +225,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
                        memcpy(bytes->bytes, r, bytes->len);
                }
        }
-       if (bytes->block)
+       if (bytes_block)
                sst_free_block(sst_drv_ctx, block);
 out:
        test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
index 60f8fb0bff95b1b3331b478a8de6f95a47076b61..59a13feec57b2543d8f22d84c358ffd69d527e66 100644 (file)
@@ -135,6 +135,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
                },
                .tplg_filename = "max98927-tplg.bin",
        },
+       {
+               .id = "10EC5663",
+               .drv_name = "avs_rt5663",
+               .mach_params = {
+                       .i2s_link_mask = AVS_SSP(1),
+               },
+               .tplg_filename = "rt5663-tplg.bin",
+       },
        {
                .id = "MX98373",
                .drv_name = "avs_max98373",
@@ -159,6 +167,14 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
                },
                .tplg_filename = "da7219-tplg.bin",
        },
+       {
+               .id = "ESSX8336",
+               .drv_name = "avs_es8336",
+               .mach_params = {
+                       .i2s_link_mask = AVS_SSP(0),
+               },
+               .tplg_filename = "es8336-tplg.bin",
+       },
        {},
 };
 
@@ -263,14 +279,14 @@ struct avs_acpi_boards {
 };
 
 #define AVS_MACH_ENTRY(_id, _mach) \
-       { .id = (_id), .machs = (_mach), }
+       { .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }
 
 /* supported I2S boards per platform */
 static const struct avs_acpi_boards i2s_boards[] = {
-       AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */
-       AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */
-       AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */
-       AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */
+       AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),
+       AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),
+       AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),
+       AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),
        {},
 };
 
index e4c230efe8d792278ea860ede96d644a214c32e9..07353d37ecae16b9ebab635e9131eeffade70b74 100644 (file)
@@ -22,6 +22,16 @@ config SND_SOC_INTEL_AVS_MACH_DMIC
          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_ES8336
+       tristate "es8336 I2S board"
+       depends on X86 && I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_ES8316
+       help
+         This adds support for AVS with ES8336 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_HDAUDIO
        tristate "HD-Audio generic board"
        select SND_SOC_HDA
@@ -115,6 +125,16 @@ config SND_SOC_INTEL_AVS_MACH_RT298
           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_RT5663
+       tristate "rt5663 in I2S mode"
+       depends on I2C
+       depends on MFD_INTEL_LPSS || COMPILE_TEST
+       select SND_SOC_RT5663
+       help
+          This adds support for ASoC machine driver with RT5663 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
index b81343420370fddfc93844df6a077d6c71957653..34347bcd1e7d8aa6df990671bf2fbfd2c08f683a 100644 (file)
@@ -2,6 +2,7 @@
 
 snd-soc-avs-da7219-objs := da7219.o
 snd-soc-avs-dmic-objs := dmic.o
+snd-soc-avs-es8336-objs := es8336.o
 snd-soc-avs-hdaudio-objs := hdaudio.o
 snd-soc-avs-i2s-test-objs := i2s_test.o
 snd-soc-avs-max98927-objs := max98927.o
@@ -12,11 +13,13 @@ snd-soc-avs-probe-objs := probe.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-rt5663-objs := rt5663.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_ES8336) += snd-soc-avs-es8336.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_MAX98927) += snd-soc-avs-max98927.o
@@ -27,5 +30,6 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.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_RT5663) += snd-soc-avs-rt5663.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
index 964a763732abd7534b4e99ac390c2f5f8875a143..85014d98f7e8ab79ea083777f24d78b9611e259a 100644 (file)
@@ -22,6 +22,7 @@
 static const struct snd_kcontrol_new card_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static int platform_clock_control(struct snd_soc_dapm_widget *w,
@@ -55,6 +56,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
 static const struct snd_soc_dapm_widget card_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
                            SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
 };
@@ -68,6 +70,22 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
 
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headset Mic", NULL, "Platform Clock" },
+       { "Line Out", NULL, "Platform Clock" },
+};
+
+static const struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Line Out",
+               .mask = SND_JACK_LINEOUT,
+       },
 };
 
 static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
@@ -75,7 +93,9 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
        struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
        struct snd_soc_component *component = codec_dai->component;
        struct snd_soc_card *card = runtime->card;
+       struct snd_soc_jack_pin *pins;
        struct snd_soc_jack *jack;
+       int num_pins;
        int clk_freq;
        int ret;
 
@@ -91,14 +111,20 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
+       num_pins = ARRAY_SIZE(card_headset_pins);
+       pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
+
        /*
         * Headset buttons map to the google Reference headset.
         * These can be configured by userspace.
         */
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0 |
-                                   SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                                   SND_JACK_BTN_3 | SND_JACK_LINEOUT, jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+                                        jack, pins, num_pins);
        if (ret) {
                dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
new file mode 100644 (file)
index 0000000..0a023f8
--- /dev/null
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2023 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/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/processor.h>
+#include <linux/slab.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include <asm/intel-family.h>
+
+#define ES8336_CODEC_DAI       "ES8316 HiFi"
+
+struct avs_card_drvdata {
+       struct snd_soc_jack jack;
+       struct gpio_desc *gpiod;
+};
+
+static const struct acpi_gpio_params enable_gpio = { 0, 0, true };
+
+static const struct acpi_gpio_mapping speaker_gpios[] = {
+       { "speaker-enable-gpios", &enable_gpio, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
+       { }
+};
+
+static int avs_es8336_speaker_power_event(struct snd_soc_dapm_widget *w,
+                                         struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_card *card = w->dapm->card;
+       struct avs_card_drvdata *data;
+       bool speaker_en;
+
+       data = snd_soc_card_get_drvdata(card);
+       /* As enable_gpio has active_low=true, logic is inverted. */
+       speaker_en = !SND_SOC_DAPM_EVENT_ON(event);
+
+       gpiod_set_value_cansleep(data->gpiod, speaker_en);
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget card_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,
+                           avs_es8336_speaker_power_event,
+                           SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+
+       /*
+        * There is no separate speaker output instead the speakers are muxed to
+        * the HP outputs. The mux is controlled by the "Speaker Power" widget.
+        */
+       {"Speaker", NULL, "HPOL"},
+       {"Speaker", NULL, "HPOR"},
+       {"Speaker", NULL, "Speaker Power"},
+
+       /* Mic route map */
+       {"MIC1", NULL, "Internal Mic"},
+       {"MIC2", NULL, "Headset Mic"},
+};
+
+static const struct snd_kcontrol_new card_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static struct snd_soc_jack_pin card_headset_pins[] = {
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+       struct snd_soc_component *component = codec_dai->component;
+       struct snd_soc_card *card = runtime->card;
+       struct snd_soc_jack_pin *pins;
+       struct avs_card_drvdata *data;
+       struct gpio_desc *gpiod;
+       int num_pins, ret;
+
+       data = 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,
+                                        &data->jack, pins, num_pins);
+       if (ret)
+               return ret;
+
+       ret = devm_acpi_dev_add_driver_gpios(codec_dai->dev, speaker_gpios);
+       if (ret)
+               dev_warn(codec_dai->dev, "Unable to add GPIO mapping table\n");
+
+       gpiod = gpiod_get_optional(codec_dai->dev, "speaker-enable", GPIOD_OUT_LOW);
+       if (IS_ERR(gpiod))
+               return dev_err_probe(codec_dai->dev, PTR_ERR(gpiod), "Get gpiod failed: %ld\n",
+                                    PTR_ERR(gpiod));
+
+       data->gpiod = gpiod;
+       snd_jack_set_key(data->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+       snd_soc_component_set_jack(component, &data->jack, NULL);
+
+       card->dapm.idle_bias_off = true;
+
+       return 0;
+}
+
+static void avs_es8336_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+       struct avs_card_drvdata *data = snd_soc_card_get_drvdata(runtime->card);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
+
+       snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
+       gpiod_put(data->gpiod);
+}
+
+static int avs_es8336_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_freq;
+       int ret;
+
+       switch (boot_cpu_data.x86_model) {
+       case INTEL_FAM6_KABYLAKE_L:
+       case INTEL_FAM6_KABYLAKE:
+               clk_freq = 24000000;
+               break;
+       default:
+               clk_freq = 19200000;
+               break;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 1, clk_freq, SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               dev_err(runtime->dev, "Set codec sysclk failed: %d\n", ret);
+
+       return ret;
+}
+
+static const struct snd_soc_ops avs_es8336_ops = {
+       .hw_params = avs_es8336_hw_params,
+};
+
+static int avs_es8336_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 SSPN to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_3LE);
+
+       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-ESSX8336:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, ES8336_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_CBC_CFC;
+       dl->init = avs_es8336_codec_init;
+       dl->exit = avs_es8336_codec_exit;
+       dl->be_hw_params_fixup = avs_es8336_be_fixup;
+       dl->ops = &avs_es8336_ops;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, ES8336_CODEC_DAI);
+
+       return snd_soc_component_set_jack(codec_dai->component, NULL, 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, ES8336_CODEC_DAI);
+       struct avs_card_drvdata *data = snd_soc_card_get_drvdata(card);
+
+       return snd_soc_component_set_jack(codec_dai->component, &data->jack, NULL);
+}
+
+static int avs_es8336_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct avs_card_drvdata *data;
+       struct snd_soc_card *card;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int 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;
+       }
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!data || !card)
+               return -ENOMEM;
+
+       card->name = "avs_es8336";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       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 = card_routes;
+       card->num_dapm_routes = ARRAY_SIZE(card_routes);
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, data);
+
+       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_es8336_driver = {
+       .probe = avs_es8336_probe,
+       .driver = {
+               .name = "avs_es8336",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_es8336_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_es8336");
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
new file mode 100644 (file)
index 0000000..770b36d
--- /dev/null
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2022-2023 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/input.h>
+#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/rt5663.h"
+
+#define RT5663_CODEC_DAI       "rt5663-aif"
+
+struct rt5663_private {
+       struct snd_soc_jack jack;
+};
+
+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_routes[] = {
+       /* HP jack connectors */
+       { "Headphone Jack", NULL, "HPOL" },
+       { "Headphone Jack", NULL, "HPOR" },
+
+       /* Mic jacks */
+       { "IN1P", NULL, "Headset Mic" },
+       { "IN1N", NULL, "Headset Mic" },
+};
+
+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_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       struct snd_soc_card *card = runtime->card;
+       struct rt5663_private *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_jack_pin *pins;
+       struct snd_soc_jack *jack;
+       int num_pins, ret;
+
+       jack = &priv->jack;
+       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 Jack", 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(asoc_rtd_to_codec(runtime, 0)->component, jack, NULL);
+
+       return 0;
+}
+
+static void avs_rt5663_codec_exit(struct snd_soc_pcm_runtime *runtime)
+{
+       snd_soc_component_set_jack(asoc_rtd_to_codec(runtime, 0)->component, NULL, NULL);
+}
+
+static int
+avs_rt5663_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 SSPN to 24 bit */
+       snd_mask_none(fmt);
+       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+       return 0;
+}
+
+static int avs_rt5663_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;
+
+       /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
+       rt5663_sel_asrc_clk_src(codec_dai->component,
+                               RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+                               RT5663_CLK_SEL_I2S1_ASRC);
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
+
+       return ret;
+}
+
+static const struct snd_soc_ops avs_rt5663_ops = {
+       .hw_params = avs_rt5663_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-10EC5663:00");
+       dl->codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, RT5663_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_CBC_CFC;
+       dl->init = avs_rt5663_codec_init;
+       dl->exit = avs_rt5663_codec_exit;
+       dl->be_hw_params_fixup = avs_rt5663_be_fixup;
+       dl->nonatomic = 1;
+       dl->no_pcm = 1;
+       dl->dpcm_capture = 1;
+       dl->dpcm_playback = 1;
+       dl->ops = &avs_rt5663_ops;
+
+       *dai_link = dl;
+
+       return 0;
+}
+
+static int avs_card_suspend_pre(struct snd_soc_card *card)
+{
+       struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT5663_CODEC_DAI);
+
+       return snd_soc_component_set_jack(codec_dai->component, NULL, 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, RT5663_CODEC_DAI);
+       struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card);
+
+       return snd_soc_component_set_jack(codec_dai->component, jack, NULL);
+}
+
+static int avs_rt5663_probe(struct platform_device *pdev)
+{
+       struct snd_soc_dai_link *dai_link;
+       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_card *card;
+       struct rt5663_private *priv;
+       struct device *dev = &pdev->dev;
+       const char *pname;
+       int 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;
+       }
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!priv || !card)
+               return -ENOMEM;
+
+       card->name = "avs_rt5663";
+       card->dev = dev;
+       card->owner = THIS_MODULE;
+       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 = card_routes;
+       card->num_dapm_routes = ARRAY_SIZE(card_routes);
+       card->fully_routed = true;
+       snd_soc_card_set_drvdata(card, priv);
+
+       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_rt5663_driver = {
+       .probe = avs_rt5663_probe,
+       .driver = {
+               .name = "avs_rt5663",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(avs_rt5663_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:avs_rt5663");
index 7142a67900bfee1ec06df3f5535574c09df8f833..b93468ae097736790ea8d64f5534f527fbc050a6 100644 (file)
@@ -79,14 +79,31 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
        { "IN1P", NULL, "Headset Mic" },
 };
 
+static struct snd_soc_jack_pin card_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 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;
+       struct snd_soc_jack_pin *pins;
+       struct snd_soc_jack *jack;
+       int num_pins, ret;
 
        jack = snd_soc_card_get_drvdata(card);
+       num_pins = ARRAY_SIZE(card_jack_pins);
+
+       pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+       if (!pins)
+               return -ENOMEM;
 
        /* Need to enable ASRC function for 24MHz mclk rate */
        if ((avs_rt5682_quirk & AVS_RT5682_MCLK_EN) &&
@@ -95,12 +112,10 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
                                        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);
+
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 |
+                                        SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack,
+                                        pins, num_pins);
        if (ret) {
                dev_err(card->dev, "Headset Jack creation failed: %d\n", ret);
                return ret;
@@ -130,39 +145,36 @@ avs_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_para
 {
        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;
+       int pll_source, freq_in, freq_out;
+       int ret;
 
        if (avs_rt5682_quirk & AVS_RT5682_MCLK_EN) {
-               clk_id = RT5682_PLL1_S_MCLK;
+               pll_source = RT5682_PLL1_S_MCLK;
                if (avs_rt5682_quirk & AVS_RT5682_MCLK_24MHZ)
-                       clk_freq = 24000000;
+                       freq_in = 24000000;
                else
-                       clk_freq = 19200000;
+                       freq_in = 19200000;
        } else {
-               clk_id = RT5682_PLL1_S_BCLK1;
-               clk_freq = params_rate(params) * 50;
+               pll_source = RT5682_PLL1_S_BCLK1;
+               freq_in = params_rate(params) * 50;
        }
 
-       pll_out = params_rate(params) * 512;
+       freq_out = params_rate(params) * 512;
 
-       ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
+       ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, pll_source, freq_in, freq_out);
        if (ret < 0)
-               dev_err(runtime->dev, "snd_soc_dai_set_pll err = %d\n", ret);
+               dev_err(runtime->dev, "Set PLL failed: %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);
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, freq_out, SND_SOC_CLOCK_IN);
        if (ret < 0)
-               dev_err(runtime->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+               dev_err(runtime->dev, "Set sysclk failed: %d\n", ret);
 
-       /* slot_width should equal or large than data length, set them be the same */
+       /* slot_width should be equal or larger than data length. */
        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;
-       }
+       if (ret < 0)
+               dev_err(runtime->dev, "Set TDM slot failed: %d\n", ret);
 
-       return 0;
+       return ret;
 }
 
 static const struct snd_soc_ops avs_rt5682_ops = {
@@ -220,6 +232,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
        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_CBC_CFC;
        dl->init = avs_rt5682_codec_init;
        dl->exit = avs_rt5682_codec_exit;
        dl->be_hw_params_fixup = avs_rt5682_be_fixup;
index 6375018507288cbc0ca2176700d958afc4d6ab29..859b217fc761ba29e7ca80dca259d18cb0ee5ce4 100644 (file)
@@ -745,14 +745,14 @@ static const struct avs_spec apl_desc = {
 };
 
 static const struct pci_device_id avs_ids[] = {
-       { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
-       { PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
-       { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
-       { PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
-       { PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
-       { PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
-       { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
-       { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
+       { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL_H, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_APL, &apl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_GML, &apl_desc) },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, avs_ids);
index 275928281c6c63809fccd7d29381a890db0b7735..4cab8c6c457666ad5960bd156e296228654a18cc 100644 (file)
@@ -249,7 +249,7 @@ static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr
        return count;
 }
 
-static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
+static const struct snd_soc_cdai_ops avs_probe_cdai_ops = {
        .startup = avs_probe_compr_open,
        .shutdown = avs_probe_compr_free,
        .set_params = avs_probe_compr_set_params,
@@ -257,6 +257,10 @@ static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
        .pointer = avs_probe_compr_pointer,
 };
 
+static const struct snd_soc_dai_ops avs_probe_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static const struct snd_compress_ops avs_probe_compress_ops = {
        .copy = avs_probe_compr_copy,
 };
@@ -264,8 +268,8 @@ static const struct snd_compress_ops avs_probe_compress_ops = {
 static struct snd_soc_dai_driver probe_cpu_dais[] = {
 {
        .name = "Probe Extraction CPU DAI",
-       .compress_new = snd_soc_new_compress,
-       .cops = &avs_probe_dai_ops,
+       .cops = &avs_probe_cdai_ops,
+       .ops  = &avs_probe_dai_ops,
        .capture = {
                .stream_name = "Probe Extraction",
                .channels_min = 1,
index cdb4ec50026178a3fecbc2047d4cabbb6efdee92..45d0eb2a8e710540f21ed0b71d90af74242f43a7 100644 (file)
@@ -1388,12 +1388,12 @@ static int avs_route_load(struct snd_soc_component *comp, int index,
                port = __ffs(mach->mach_params.i2s_link_mask);
 
                snprintf(buf, len, route->source, port);
-               strncpy((char *)route->source, buf, len);
+               strscpy((char *)route->source, buf, len);
                snprintf(buf, len, route->sink, port);
-               strncpy((char *)route->sink, buf, len);
+               strscpy((char *)route->sink, buf, len);
                if (route->control) {
                        snprintf(buf, len, route->control, port);
-                       strncpy((char *)route->control, buf, len);
+                       strscpy((char *)route->control, buf, len);
                }
        }
 
index f472f603ab750e39dbf532e9449ae4f337fcf3bd..0ae6eecc8851917d6188688eab9428c368d25f77 100644 (file)
@@ -475,7 +475,7 @@ endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC
 
 if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL
 config SND_SOC_INTEL_SOF_RT5682_MACH
-       tristate "SOF with rt5682 codec in I2S Mode"
+       tristate "SOF with rt5650/rt5682 codec in I2S Mode"
        depends on I2C && ACPI
        depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\
                    (MFD_INTEL_LPSS || COMPILE_TEST)) ||\
@@ -485,6 +485,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
        select SND_SOC_RT1011
        select SND_SOC_RT1015
        select SND_SOC_RT1015P
+       select SND_SOC_RT5645
        select SND_SOC_RT5682_I2C
        select SND_SOC_RT5682S
        select SND_SOC_DMIC
@@ -494,7 +495,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
        select SND_SOC_INTEL_SOF_REALTEK_COMMON
        help
           This adds support for ASoC machine driver for SOF platforms
-          with rt5682 codec.
+          with rt5650 or rt5682 codec.
           Say Y if you have such a device.
           If unsure select "N".
 
@@ -670,14 +671,15 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
        select SND_SOC_RT711_SDCA_SDW
        select SND_SOC_RT712_SDCA_SDW
        select SND_SOC_RT712_SDCA_DMIC_SDW
+       select SND_SOC_RT715_SDW
+       select SND_SOC_RT715_SDCA_SDW
        select SND_SOC_RT1308_SDW
        select SND_SOC_RT1308
        select SND_SOC_RT1316_SDW
        select SND_SOC_RT1318_SDW
-       select SND_SOC_RT715_SDW
-       select SND_SOC_RT715_SDCA_SDW
        select SND_SOC_RT5682_SDW
        select SND_SOC_CS42L42_SDW
+       select SND_SOC_CS35L56_SDW
        select SND_SOC_DMIC
        select SND_SOC_INTEL_HDA_DSP_COMMON
        select SND_SOC_INTEL_SOF_MAXIM_COMMON
index 931415d9cf6fa553d453d6c06ff2820c6727d9ac..a570b5b40f22e762397fe9b1ac3a70bd31e3364d 100644 (file)
@@ -42,7 +42,7 @@ snd-soc-sof-sdw-objs += sof_sdw.o                             \
                        sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o   \
                        sof_sdw_rt712_sdca.o sof_sdw_rt715.o    \
                        sof_sdw_rt715_sdca.o sof_sdw_dmic.o     \
-                       sof_sdw_cs42l42.o \
+                       sof_sdw_cs42l42.o sof_sdw_cs_amp.o      \
                        sof_sdw_hdmi.o
 obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o
 obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o
index b7687a93a923470a788a70b6e0e37555d794e46c..036579331d8fbec1f29defe9c7500116e7193ce6 100644 (file)
@@ -187,6 +187,9 @@ static int card_suspend_pre(struct snd_soc_card *card)
 {
        struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
 
+       if (!codec_dai)
+               return 0;
+
        return snd_soc_component_set_jack(codec_dai->component, NULL, NULL);
 }
 
@@ -194,6 +197,9 @@ static int card_resume_post(struct snd_soc_card *card)
 {
        struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, "rt286-aif1");
 
+       if (!codec_dai)
+               return 0;
+
        return snd_soc_component_set_jack(codec_dai->component, &card_headset, NULL);
 }
 
index c593995facaa9bcf3aabfa342477c7ad96566e81..cbfff466c5c86355c2e145fc72ceac9a28ffa7ec 100644 (file)
@@ -90,6 +90,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
 static const struct snd_kcontrol_new broxton_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static const struct snd_kcontrol_new max98357a_controls[] = {
@@ -104,6 +105,7 @@ static const struct snd_kcontrol_new max98390_controls[] = {
 static const struct snd_soc_dapm_widget broxton_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
        SND_SOC_DAPM_SPK("HDMI1", NULL),
        SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -150,6 +152,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headset Mic", NULL, "Platform Clock" },
+       { "Line Out", NULL, "Platform Clock" },
 };
 
 static const struct snd_soc_dapm_route max98357a_routes[] = {
@@ -194,6 +197,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
                .pin    = "Headset Mic",
                .mask   = SND_JACK_MICROPHONE,
        },
+       {
+               .pin    = "Line Out",
+               .mask   = SND_JACK_LINEOUT,
+       },
 };
 
 static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
index f2382d4cb76f20ac37cfef1901a5257a75f41860..5c9e06ed1a535ed94875032138efa3e7d49c2f93 100644 (file)
@@ -131,6 +131,7 @@ static const struct snd_soc_dapm_widget byt_wm5102_widgets[] = {
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_MIC("Internal Mic", NULL),
        SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
                            platform_clock_control, SND_SOC_DAPM_PRE_PMU |
                            SND_SOC_DAPM_POST_PMD),
@@ -144,6 +145,7 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
        {"Headset Mic", NULL, "Platform Clock"},
        {"Internal Mic", NULL, "Platform Clock"},
        {"Speaker", NULL, "Platform Clock"},
+       {"Line Out", NULL, "Platform Clock"},
 
        {"Speaker", NULL, "SPKOUTLP"},
        {"Speaker", NULL, "SPKOUTLN"},
@@ -177,6 +179,7 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Internal Mic"),
        SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static struct snd_soc_jack_pin byt_wm5102_pins[] = {
@@ -188,6 +191,10 @@ static struct snd_soc_jack_pin byt_wm5102_pins[] = {
                .pin    = "Headset Mic",
                .mask   = SND_JACK_MICROPHONE,
        },
+       {
+               .pin    = "Line Out",
+               .mask   = SND_JACK_LINEOUT,
+       },
 };
 
 static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
index 18365ce6bcbafa40d139db3c343feb3d28e3c3a1..97149513076f9f6a0ae077066c8988630cb7deca 100644 (file)
@@ -83,12 +83,14 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Spk"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static const struct snd_soc_dapm_widget kabylake_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_SPK("Spk", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
        SND_SOC_DAPM_SPK("HDMI1", NULL),
        SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -107,6 +109,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
                .pin    = "Headset Mic",
                .mask   = SND_JACK_MICROPHONE,
        },
+       {
+               .pin    = "Line Out",
+               .mask   = SND_JACK_LINEOUT,
+       },
 };
 
 static const struct snd_soc_dapm_route kabylake_map[] = {
@@ -147,6 +153,7 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
 
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headset Mic", NULL, "Platform Clock" },
+       { "Line Out", NULL, "Platform Clock" },
 };
 
 static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
index ad4223fee0c51fe7c793d415a6568bb88bc98bca..a1f8234c77bd249b0f5da59e0e830d315637322b 100644 (file)
@@ -102,6 +102,7 @@ static const struct snd_kcontrol_new kabylake_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Left Spk"),
        SOC_DAPM_PIN_SWITCH("Right Spk"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static const struct snd_soc_dapm_widget kabylake_widgets[] = {
@@ -109,6 +110,7 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_SPK("Left Spk", NULL),
        SND_SOC_DAPM_SPK("Right Spk", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_MIC("SoC DMIC", NULL),
        SND_SOC_DAPM_SPK("HDMI1", NULL),
        SND_SOC_DAPM_SPK("HDMI2", NULL),
@@ -127,6 +129,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
                .pin    = "Headset Mic",
                .mask   = SND_JACK_MICROPHONE,
        },
+       {
+               .pin    = "Line Out",
+               .mask   = SND_JACK_MICROPHONE,
+       },
 };
 
 static const struct snd_soc_dapm_route kabylake_map[] = {
@@ -182,6 +188,7 @@ static const struct snd_soc_dapm_route kabylake_ssp1_map[] = {
 
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headset Mic", NULL, "Platform Clock" },
+       { "Line Out", NULL, "Platform Clock" },
 };
 
 static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
index 740aa11cb019e99454a093d2cd140d4ca608fbb3..bbd47e7e4343021672f99d2cf99d057038d4f0f6 100644 (file)
@@ -65,6 +65,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
 static const struct snd_kcontrol_new controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
        SOC_DAPM_PIN_SWITCH("Left Spk"),
        SOC_DAPM_PIN_SWITCH("Right Spk"),
 };
@@ -72,6 +73,7 @@ static const struct snd_kcontrol_new controls[] = {
 static const struct snd_kcontrol_new m98360a_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
        SOC_DAPM_PIN_SWITCH("Spk"),
 };
 
@@ -79,6 +81,7 @@ static const struct snd_kcontrol_new m98360a_controls[] = {
 static const struct snd_soc_dapm_widget widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
 
        SND_SOC_DAPM_SPK("Left Spk", NULL),
        SND_SOC_DAPM_SPK("Right Spk", NULL),
@@ -98,6 +101,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headset Mic", NULL, "Platform Clock" },
+       { "Line Out", NULL, "Platform Clock" },
 
        { "Left Spk", NULL, "Left BE_OUT" },
        { "Right Spk", NULL, "Right BE_OUT" },
@@ -110,6 +114,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static const struct snd_soc_dapm_widget max98360a_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
 
        SND_SOC_DAPM_SPK("Spk", NULL),
 
@@ -128,6 +133,7 @@ static const struct snd_soc_dapm_route max98360a_map[] = {
 
        { "Headphone Jack", NULL, "Platform Clock" },
        { "Headset Mic", NULL, "Platform Clock" },
+       { "Line Out", NULL, "Platform Clock" },
 
        {"Spk", NULL, "Speaker"},
 
@@ -144,6 +150,10 @@ static struct snd_soc_jack_pin jack_pins[] = {
                .pin    = "Headset Mic",
                .mask   = SND_JACK_MICROPHONE,
        },
+       {
+               .pin    = "Line Out",
+               .mask   = SND_JACK_LINEOUT,
+       },
 };
 
 static struct snd_soc_jack headset;
index d6c38d8ea2ffb4ac5fdafc6186c14be14e343234..f8a3e8a91761aaf6903c4f1f50fcc1b1c00a463d 100644 (file)
@@ -798,6 +798,16 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
                                        SOF_ES8336_JD_INVERTED),
        },
+       {
+               .name = "rpl_es83x6_c1_h02",
+               .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) |
+                                       SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+                                       SOF_HDMI_CAPTURE_1_SSP(0) |
+                                       SOF_HDMI_CAPTURE_2_SSP(2) |
+                                       SOF_SSP_HDMI_CAPTURE_PRESENT |
+                                       SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK |
+                                       SOF_ES8336_JD_INVERTED),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index 112e89951da08b9c9a315372869a21471e722b42..628b6d5d3ee4277e244f77dca65aa958aede8bd8 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-dai.h>
 #include <uapi/sound/asound.h>
 #include "sof_maxim_common.h"
 
+/* helper function to get the number of specific codec */
+static unsigned int get_num_codecs(const char *hid)
+{
+       struct acpi_device *adev;
+       unsigned int dev_num = 0;
+
+       for_each_acpi_dev_match(adev, hid, NULL, -1)
+               dev_num++;
+
+       return dev_num;
+}
+
 #define MAX_98373_PIN_NAME 16
 
 const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
@@ -168,17 +181,6 @@ static struct snd_soc_codec_conf max_98390_codec_conf[] = {
                .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
                .name_prefix = "Left",
        },
-};
-
-static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = {
-       {
-               .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME),
-               .name_prefix = "Right",
-       },
-       {
-               .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME),
-               .name_prefix = "Left",
-       },
        {
                .dlc = COMP_CODEC_CONF(MAX_98390_DEV2_NAME),
                .name_prefix = "Tweeter Right",
@@ -189,19 +191,7 @@ static struct snd_soc_codec_conf max_98390_4spk_codec_conf[] = {
        },
 };
 
-struct snd_soc_dai_link_component max_98390_components[] = {
-       {
-               .name = MAX_98390_DEV0_NAME,
-               .dai_name = MAX_98390_CODEC_DAI,
-       },
-       {
-               .name = MAX_98390_DEV1_NAME,
-               .dai_name = MAX_98390_CODEC_DAI,
-       },
-};
-EXPORT_SYMBOL_NS(max_98390_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
-
-struct snd_soc_dai_link_component max_98390_4spk_components[] = {
+static struct snd_soc_dai_link_component max_98390_components[] = {
        {
                .name = MAX_98390_DEV0_NAME,
                .dai_name = MAX_98390_CODEC_DAI,
@@ -219,62 +209,56 @@ struct snd_soc_dai_link_component max_98390_4spk_components[] = {
                .dai_name = MAX_98390_CODEC_DAI,
        },
 };
-EXPORT_SYMBOL_NS(max_98390_4spk_components, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+static const struct {
+       unsigned int tx;
+       unsigned int rx;
+} max_98390_tdm_mask[] = {
+       {.tx = 0x01, .rx = 0x3},
+       {.tx = 0x02, .rx = 0x3},
+       {.tx = 0x04, .rx = 0x3},
+       {.tx = 0x08, .rx = 0x3},
+};
 
 static int max_98390_hw_params(struct snd_pcm_substream *substream,
                               struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
        struct snd_soc_dai *codec_dai;
-       int i;
+       int i, ret;
 
        for_each_rtd_codec_dais(rtd, i, codec_dai) {
-               if (i >= ARRAY_SIZE(max_98390_4spk_components)) {
+               if (i >= ARRAY_SIZE(max_98390_tdm_mask)) {
                        dev_err(codec_dai->dev, "invalid codec index %d\n", i);
                        return -ENODEV;
                }
 
-               if (!strcmp(codec_dai->component->name, MAX_98390_DEV0_NAME)) {
-                       /* DEV0 tdm slot configuration Right */
-                       snd_soc_dai_set_tdm_slot(codec_dai, 0x01, 3, 4, 32);
-               }
-               if (!strcmp(codec_dai->component->name, MAX_98390_DEV1_NAME)) {
-                       /* DEV1 tdm slot configuration Left */
-                       snd_soc_dai_set_tdm_slot(codec_dai, 0x02, 3, 4, 32);
-               }
-
-               if (!strcmp(codec_dai->component->name, MAX_98390_DEV2_NAME)) {
-                       /* DEVi2 tdm slot configuration Tweeter Right */
-                       snd_soc_dai_set_tdm_slot(codec_dai, 0x04, 3, 4, 32);
-               }
-               if (!strcmp(codec_dai->component->name, MAX_98390_DEV3_NAME)) {
-                       /* DEV3 tdm slot configuration Tweeter Left */
-                       snd_soc_dai_set_tdm_slot(codec_dai, 0x08, 3, 4, 32);
+               ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx,
+                                              max_98390_tdm_mask[i].rx, 4,
+                                              params_width(params));
+               if (ret < 0) {
+                       dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n",
+                               ret);
+                       return ret;
                }
        }
        return 0;
 }
 
-int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
+static int max_98390_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
+       unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
        int ret;
 
-       /* add regular speakers dapm route */
-       ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
-                                     ARRAY_SIZE(max_98390_dapm_routes));
-       if (ret) {
-               dev_err(rtd->dev, "unable to add Left/Right Speaker dapm, ret %d\n", ret);
-               return ret;
-       }
-
-       /* add widgets/controls/dapm for tweeter speakers */
-       if (acpi_dev_present("MX98390", "3", -1)) {
+       switch (num_codecs) {
+       case 4:
+               /* add widgets/controls/dapm for tweeter speakers */
                ret = snd_soc_dapm_new_controls(&card->dapm, max_98390_tt_dapm_widgets,
                                                ARRAY_SIZE(max_98390_tt_dapm_widgets));
-
                if (ret) {
-                       dev_err(rtd->dev, "unable to add tweeter dapm controls, ret %d\n", ret);
+                       dev_err(rtd->dev, "unable to add tweeter dapm widgets, ret %d\n",
+                               ret);
                        /* Don't need to add routes if widget addition failed */
                        return ret;
                }
@@ -282,33 +266,79 @@ int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd)
                ret = snd_soc_add_card_controls(card, max_98390_tt_kcontrols,
                                                ARRAY_SIZE(max_98390_tt_kcontrols));
                if (ret) {
-                       dev_err(rtd->dev, "unable to add tweeter card controls, ret %d\n", ret);
+                       dev_err(rtd->dev, "unable to add tweeter controls, ret %d\n",
+                               ret);
                        return ret;
                }
 
                ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_tt_dapm_routes,
                                              ARRAY_SIZE(max_98390_tt_dapm_routes));
-               if (ret)
-                       dev_err(rtd->dev,
-                               "unable to add Tweeter Left/Right Speaker dapm, ret %d\n", ret);
+               if (ret) {
+                       dev_err(rtd->dev, "unable to add tweeter dapm routes, ret %d\n",
+                               ret);
+                       return ret;
+               }
+
+               fallthrough;
+       case 2:
+               /* add regular speakers dapm route */
+               ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes,
+                                             ARRAY_SIZE(max_98390_dapm_routes));
+               if (ret) {
+                       dev_err(rtd->dev, "unable to add dapm routes, ret %d\n",
+                               ret);
+                       return ret;
+               }
+               break;
+       default:
+               dev_err(rtd->dev, "invalid codec number %d\n", num_codecs);
+               return -EINVAL;
        }
+
        return ret;
 }
-EXPORT_SYMBOL_NS(max_98390_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON);
 
-const struct snd_soc_ops max_98390_ops = {
+static const struct snd_soc_ops max_98390_ops = {
        .hw_params = max_98390_hw_params,
 };
-EXPORT_SYMBOL_NS(max_98390_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON);
 
-void max_98390_set_codec_conf(struct snd_soc_card *card, int ch)
+void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link)
+{
+       unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
+
+       link->codecs = max_98390_components;
+
+       switch (num_codecs) {
+       case 2:
+       case 4:
+               link->num_codecs = num_codecs;
+               break;
+       default:
+               dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
+                       MAX_98390_ACPI_HID);
+               break;
+       }
+
+       link->init = max_98390_init;
+       link->ops = &max_98390_ops;
+}
+EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON);
+
+void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card)
 {
-       if (ch == ARRAY_SIZE(max_98390_4spk_codec_conf)) {
-               card->codec_conf = max_98390_4spk_codec_conf;
-               card->num_configs = ARRAY_SIZE(max_98390_4spk_codec_conf);
-       } else {
-               card->codec_conf = max_98390_codec_conf;
-               card->num_configs = ARRAY_SIZE(max_98390_codec_conf);
+       unsigned int num_codecs = get_num_codecs(MAX_98390_ACPI_HID);
+
+       card->codec_conf = max_98390_codec_conf;
+
+       switch (num_codecs) {
+       case 2:
+       case 4:
+               card->num_configs = num_codecs;
+               break;
+       default:
+               dev_err(dev, "invalid codec number %d for %s\n", num_codecs,
+                       MAX_98390_ACPI_HID);
+               break;
        }
 }
 EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON);
index 7a8c53049e4d56ba553aefeb5d44506ed36905d0..a095b47b856b14f67d0f43a0231fd9230a5658e6 100644 (file)
@@ -27,18 +27,15 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd);
 /*
  * Maxim MAX98390
  */
-#define MAX_98390_CODEC_DAI     "max98390-aif1"
-#define MAX_98390_DEV0_NAME     "i2c-MX98390:00"
-#define MAX_98390_DEV1_NAME     "i2c-MX98390:01"
-#define MAX_98390_DEV2_NAME     "i2c-MX98390:02"
-#define MAX_98390_DEV3_NAME     "i2c-MX98390:03"
-
-extern struct snd_soc_dai_link_component max_98390_components[2];
-extern struct snd_soc_dai_link_component max_98390_4spk_components[4];
-extern const struct snd_soc_ops max_98390_ops;
-
-void max_98390_set_codec_conf(struct snd_soc_card *card, int ch);
-int max_98390_spk_codec_init(struct snd_soc_pcm_runtime *rtd);
+#define MAX_98390_ACPI_HID     "MX98390"
+#define MAX_98390_CODEC_DAI    "max98390-aif1"
+#define MAX_98390_DEV0_NAME    "i2c-" MAX_98390_ACPI_HID ":00"
+#define MAX_98390_DEV1_NAME    "i2c-" MAX_98390_ACPI_HID ":01"
+#define MAX_98390_DEV2_NAME    "i2c-" MAX_98390_ACPI_HID ":02"
+#define MAX_98390_DEV3_NAME    "i2c-" MAX_98390_ACPI_HID ":03"
+
+void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link);
+void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card);
 
 /*
  * Maxim MAX98357A/MAX98360A
index 4fc6e1c6aef319a045f939fa3d53b3ec8c77483d..46b7ecf6f9f1a6786bb56e48ebca0c523d121f57 100644 (file)
@@ -684,6 +684,16 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_BT_OFFLOAD_SSP(2) |
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
        },
+       {
+               .name = "rpl_nau8318_8825",
+               .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_NAU8318_SPEAKER_AMP_PRESENT |
+                                       SOF_NAU8825_SSP_AMP(1) |
+                                       SOF_NAU8825_NUM_HDMIDEV(4) |
+                                       SOF_BT_OFFLOAD_SSP(2) |
+                                       SOF_SSP_BT_OFFLOAD_PRESENT),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index 7c034d671cf3caa9c57144a9685f7824f3973bb8..fae091b9b55c50ffbed9ff00d4cd0b83230d659f 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/soc-acpi.h>
 #include "../../codecs/rt5682.h"
 #include "../../codecs/rt5682s.h"
+#include "../../codecs/rt5645.h"
 #include "../../codecs/hdac_hdmi.h"
 #include "../common/soc-intel-quirks.h"
 #include "hda_dsp_common.h"
 #define SOF_SSP_BT_OFFLOAD_PRESENT             BIT(22)
 #define SOF_RT5682S_HEADPHONE_CODEC_PRESENT    BIT(23)
 #define SOF_MAX98390_SPEAKER_AMP_PRESENT       BIT(24)
-#define SOF_MAX98390_TWEETER_SPEAKER_PRESENT   BIT(25)
 #define SOF_RT1019_SPEAKER_AMP_PRESENT BIT(26)
+#define SOF_RT5650_HEADPHONE_CODEC_PRESENT     BIT(27)
 
+/* HDMI capture*/
+#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT  27
+#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27))
+#define SOF_HDMI_CAPTURE_SSP_MASK(quirk)   \
+       (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK)
 
 /* Default: MCLK on, MCLK 19.2M, SSP0  */
 static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
@@ -193,23 +199,6 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = {
                                        SOF_RT5682_SSP_AMP(2) |
                                        SOF_RT5682_NUM_HDMIDEV(4)),
        },
-       {
-               .callback = sof_rt5682_quirk_cb,
-               .matches = {
-                       DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
-                       DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S_4SPK"),
-               },
-               .driver_data = (void *)(SOF_RT5682_MCLK_EN |
-                                       SOF_RT5682_SSP_CODEC(0) |
-                                       SOF_SPEAKER_AMP_PRESENT |
-                                       SOF_MAX98390_SPEAKER_AMP_PRESENT |
-                                       SOF_MAX98390_TWEETER_SPEAKER_PRESENT |
-                                       SOF_RT5682_SSP_AMP(1) |
-                                       SOF_RT5682_NUM_HDMIDEV(4) |
-                                       SOF_BT_OFFLOAD_SSP(2) |
-                                       SOF_SSP_BT_OFFLOAD_PRESENT),
-
-       },
        {
                .callback = sof_rt5682_quirk_cb,
                .matches = {
@@ -305,6 +294,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
        struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
        struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
        struct snd_soc_jack *jack;
+       int extra_jack_data;
        int ret;
 
        /* need to enable ASRC function for 24MHz mclk rate */
@@ -315,7 +305,16 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
                                                 RT5682S_DA_STEREO1_FILTER |
                                                 RT5682S_AD_STEREO1_FILTER,
                                                 RT5682S_CLK_SEL_I2S1_ASRC);
-               else
+               else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) {
+                       rt5645_sel_asrc_clk_src(component,
+                                               RT5645_DA_STEREO_FILTER |
+                                               RT5645_AD_STEREO_FILTER,
+                                               RT5645_CLK_SEL_I2S1_ASRC);
+                       rt5645_sel_asrc_clk_src(component,
+                                               RT5645_DA_MONO_L_FILTER |
+                                               RT5645_DA_MONO_R_FILTER,
+                                               RT5645_CLK_SEL_I2S2_ASRC);
+               } else
                        rt5682_sel_asrc_clk_src(component,
                                                RT5682_DA_STEREO1_FILTER |
                                                RT5682_AD_STEREO1_FILTER,
@@ -365,7 +364,12 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
        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 (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) {
+               extra_jack_data = SND_JACK_MICROPHONE | SND_JACK_BTN_0;
+               ret = snd_soc_component_set_jack(component, jack, &extra_jack_data);
+       } else
+               ret = snd_soc_component_set_jack(component, jack, NULL);
 
        if (ret) {
                dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
@@ -402,6 +406,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
 
                if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT)
                        pll_source = RT5682S_PLL_S_MCLK;
+               else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT)
+                       pll_source = RT5645_PLL1_S_MCLK;
                else
                        pll_source = RT5682_PLL1_S_MCLK;
 
@@ -422,6 +428,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
        } else {
                if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT)
                        pll_source = RT5682S_PLL_S_BCLK1;
+               else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT)
+                       pll_source = RT5645_PLL1_S_BCLK1;
                else
                        pll_source = RT5682_PLL1_S_BCLK1;
 
@@ -431,6 +439,9 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
        if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) {
                pll_id = RT5682S_PLL2;
                clk_id = RT5682S_SCLK_S_PLL2;
+       } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) {
+               pll_id = 0; /* not used in codec driver */
+               clk_id = RT5645_SCLK_S_PLL1;
        } else {
                pll_id = RT5682_PLL1;
                clk_id = RT5682_SCLK_S_PLL1;
@@ -559,11 +570,30 @@ static const struct snd_soc_dapm_route sof_map[] = {
        { "IN1P", NULL, "Headset Mic" },
 };
 
+static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = {
+       /* speaker */
+       { "Left Spk", NULL, "SPOL" },
+       { "Right Spk", NULL, "SPOR" },
+};
+
 static const struct snd_soc_dapm_route dmic_map[] = {
        /* digital mics */
        {"DMic", NULL, "SoC DMIC"},
 };
 
+static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       int ret;
+
+       ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes,
+                                     ARRAY_SIZE(rt5650_spk_dapm_routes));
+       if (ret)
+               dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret);
+
+       return ret;
+}
+
 static int dmic_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
@@ -614,6 +644,17 @@ static struct snd_soc_dai_link_component rt5682s_component[] = {
        }
 };
 
+static struct snd_soc_dai_link_component rt5650_components[] = {
+       {
+               .name = "i2c-10EC5650:00",
+               .dai_name = "rt5645-aif1",
+       },
+       {
+               .name = "i2c-10EC5650:00",
+               .dai_name = "rt5645-aif2",
+       }
+};
+
 static struct snd_soc_dai_link_component dmic_component[] = {
        {
                .name = "dmic-codec",
@@ -634,6 +675,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        struct snd_soc_dai_link_component *cpus;
        struct snd_soc_dai_link *links;
        int i, id = 0;
+       int hdmi_id_offset = 0;
 
        links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links,
                            sizeof(struct snd_soc_dai_link), GFP_KERNEL);
@@ -652,6 +694,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        if (sof_rt5682_quirk & SOF_RT5682S_HEADPHONE_CODEC_PRESENT) {
                links[id].codecs = rt5682s_component;
                links[id].num_codecs = ARRAY_SIZE(rt5682s_component);
+       } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) {
+               links[id].codecs = &rt5650_components[0];
+               links[id].num_codecs = 1;
        } else {
                links[id].codecs = rt5682_component;
                links[id].num_codecs = ARRAY_SIZE(rt5682_component);
@@ -793,17 +838,12 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                        sof_rt1011_dai_link(&links[id]);
                } else if (sof_rt5682_quirk &
                                SOF_MAX98390_SPEAKER_AMP_PRESENT) {
-                       if (sof_rt5682_quirk &
-                               SOF_MAX98390_TWEETER_SPEAKER_PRESENT) {
-                               links[id].codecs = max_98390_4spk_components;
-                               links[id].num_codecs = ARRAY_SIZE(max_98390_4spk_components);
-                       } else {
-                               links[id].codecs = max_98390_components;
-                               links[id].num_codecs = ARRAY_SIZE(max_98390_components);
-                       }
-                       links[id].init = max_98390_spk_codec_init;
-                       links[id].ops = &max_98390_ops;
-
+                       max_98390_dai_link(dev, &links[id]);
+               } else if (sof_rt5682_quirk & SOF_RT5650_HEADPHONE_CODEC_PRESENT) {
+                       links[id].codecs = &rt5650_components[1];
+                       links[id].num_codecs = 1;
+                       links[id].init = rt5650_spk_init;
+                       links[id].ops = &sof_rt5682_ops;
                } else {
                        max_98357a_dai_link(&links[id]);
                }
@@ -857,6 +897,34 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                links[id].num_cpus = 1;
        }
 
+       /* HDMI-In SSP */
+       if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) {
+               unsigned long hdmi_in_ssp = (sof_rt5682_quirk &
+                               SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >>
+                               SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT;
+               int port = 0;
+
+               for_each_set_bit(port, &hdmi_in_ssp, 32) {
+                       links[id].cpus = &cpus[id];
+                       links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
+                                                                 "SSP%d Pin", port);
+                       if (!links[id].cpus->dai_name)
+                               return NULL;
+                       links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", port);
+                       if (!links[id].name)
+                               return NULL;
+                       links[id].id = id + hdmi_id_offset;
+                       links[id].codecs = &asoc_dummy_dlc;
+                       links[id].num_codecs = 1;
+                       links[id].platforms = platform_component;
+                       links[id].num_platforms = ARRAY_SIZE(platform_component);
+                       links[id].dpcm_capture = 1;
+                       links[id].no_pcm = 1;
+                       links[id].num_cpus = 1;
+                       id++;
+               }
+       }
+
        return links;
 devm_err:
        return NULL;
@@ -890,6 +958,12 @@ static int sof_audio_probe(struct platform_device *pdev)
        /* Detect the headset codec variant */
        if (acpi_dev_present("RTL5682", NULL, -1))
                sof_rt5682_quirk |= SOF_RT5682S_HEADPHONE_CODEC_PRESENT;
+       else if (acpi_dev_present("10EC5650", NULL, -1)) {
+               sof_rt5682_quirk |= SOF_RT5650_HEADPHONE_CODEC_PRESENT;
+
+               sof_audio_card_rt5682.name = devm_kstrdup(&pdev->dev, "rt5650",
+                                                         GFP_KERNEL);
+       }
 
        if (soc_intel_is_byt() || soc_intel_is_cht()) {
                is_legacy_cpu = 1;
@@ -951,17 +1025,17 @@ static int sof_audio_probe(struct platform_device *pdev)
        else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT)
                sof_rt1015p_codec_conf(&sof_audio_card_rt5682);
        else if (sof_rt5682_quirk & SOF_MAX98390_SPEAKER_AMP_PRESENT) {
-               if (sof_rt5682_quirk & SOF_MAX98390_TWEETER_SPEAKER_PRESENT)
-                       max_98390_set_codec_conf(&sof_audio_card_rt5682,
-                                                ARRAY_SIZE(max_98390_4spk_components));
-               else
-                       max_98390_set_codec_conf(&sof_audio_card_rt5682,
-                                                ARRAY_SIZE(max_98390_components));
+               max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682);
        }
 
        if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
                sof_audio_card_rt5682.num_links++;
 
+       if (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK)
+               sof_audio_card_rt5682.num_links +=
+                       hweight32((sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >>
+                                       SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT);
+
        dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
                                              dmic_be_num, hdmi_num, ctx->idisp_codec);
        if (!dai_links)
@@ -1128,6 +1202,22 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_BT_OFFLOAD_SSP(2) |
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
        },
+       {
+               .name = "adl_rt5682_c1_h02",
+               .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_SSP_CODEC(1) |
+                                       SOF_RT5682_NUM_HDMIDEV(3) |
+                                       /* SSP 0 and SSP 2 are used for HDMI IN */
+                                       SOF_HDMI_CAPTURE_SSP_MASK(0x5)),
+       },
+       {
+               .name = "rpl_mx98357_rt5682",
+               .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT5682_SSP_AMP(2) |
+                                       SOF_RT5682_NUM_HDMIDEV(4)),
+       },
        {
                .name = "rpl_mx98360_rt5682",
                .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
@@ -1178,6 +1268,14 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_RT5682_SSP_AMP(0) |
                                        SOF_RT5682_NUM_HDMIDEV(3)),
        },
+       {
+               .name = "jsl_rt5650",
+               .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
+                                       SOF_RT5682_MCLK_24MHZ |
+                                       SOF_RT5682_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_RT5682_SSP_AMP(1)),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index dbee8c98ff0122b1a5cfec54e6cf4a4683766cc7..5a1c750e6ae6aeb368b53c7d6f801119960502b0 100644 (file)
@@ -307,6 +307,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                .driver_data = (void *)(SOF_SDW_TGL_HDMI |
                                        SOF_SDW_FOUR_SPK),
        },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
        {
                .callback = sof_sdw_quirk_cb,
                .matches = {
@@ -467,7 +477,9 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
                },
-               .driver_data = (void *)(SOF_SDW_PCH_DMIC),
+               .driver_data = (void *)(SOF_SDW_PCH_DMIC |
+                                       SOF_BT_OFFLOAD_SSP(1) |
+                                       SOF_SSP_BT_OFFLOAD_PRESENT),
        },
        /* LunarLake devices */
        {
@@ -476,7 +488,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
                },
-               .driver_data = (void *)(RT711_JD2_100K),
+               .driver_data = (void *)(RT711_JD2),
        },
        {}
 };
@@ -511,9 +523,8 @@ int sdw_prepare(struct snd_pcm_substream *substream)
        dai = asoc_rtd_to_cpu(rtd, 0);
 
        sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
        if (IS_ERR(sdw_stream)) {
-               dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
+               dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
                return PTR_ERR(sdw_stream);
        }
 
@@ -531,9 +542,8 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
        dai = asoc_rtd_to_cpu(rtd, 0);
 
        sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
        if (IS_ERR(sdw_stream)) {
-               dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
+               dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
                return PTR_ERR(sdw_stream);
        }
 
@@ -555,7 +565,7 @@ int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
        }
 
        if (ret)
-               dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
+               dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
 
        return ret;
 }
@@ -619,9 +629,8 @@ int sdw_hw_free(struct snd_pcm_substream *substream)
        dai = asoc_rtd_to_cpu(rtd, 0);
 
        sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
-
        if (IS_ERR(sdw_stream)) {
-               dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
+               dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
                return PTR_ERR(sdw_stream);
        }
 
@@ -894,6 +903,19 @@ static struct sof_sdw_codec_info codec_info_list[] = {
                },
                .dai_num = 1,
        },
+       {
+               .part_id = 0x3556,
+               .dais = {
+                       {
+                               .direction = {true, true},
+                               .dai_name = "cs35l56-sdw1",
+                               .dai_type = SOF_SDW_DAI_TYPE_AMP,
+                               .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
+                               .init = sof_sdw_cs_amp_init,
+                       },
+               },
+               .dai_num = 1,
+       },
        {
                .part_id = 0x4242,
                .dais = {
@@ -940,10 +962,10 @@ static struct sof_sdw_codec_info codec_info_list[] = {
                .version_id = 0,
                .dais = {
                        {
-                               .direction = {true, false},
+                               .direction = {true, true},
                                .dai_name = "sdw-mockup-aif1",
                                .dai_type = SOF_SDW_DAI_TYPE_AMP,
-                               .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID},
+                               .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID},
                                .init = NULL,
                        },
                },
@@ -965,7 +987,7 @@ static struct sof_sdw_codec_info codec_info_list[] = {
        },
 };
 
-static inline int find_codec_info_part(u64 adr)
+static inline int find_codec_info_part(const u64 adr)
 {
        unsigned int part_id, sdw_version;
        int i;
@@ -994,14 +1016,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id)
                return -EINVAL;
 
        for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
-               if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
-                           ACPI_ID_LEN))
-                       break;
-
-       if (i == ARRAY_SIZE(codec_info_list))
-               return -EINVAL;
+               if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
+                       return i;
 
-       return i;
+       return -EINVAL;
 }
 
 /*
@@ -1009,10 +1027,10 @@ static inline int find_codec_info_acpi(const u8 *acpi_id)
  * Since some sdw slaves may be aggregated, the CPU DAI number
  * may be larger than the number of BE dailinks.
  */
-static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
-                               int *sdw_be_num, int *sdw_cpu_dai_num)
+static int get_dailink_info(struct device *dev,
+                           const struct snd_soc_acpi_link_adr *adr_link,
+                           int *sdw_be_num, int *sdw_cpu_dai_num, int *codecs_num)
 {
-       const struct snd_soc_acpi_link_adr *link;
        bool group_visited[SDW_MAX_GROUPS];
        bool no_aggregation;
        int i;
@@ -1022,27 +1040,45 @@ static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_li
        *sdw_cpu_dai_num = 0;
        *sdw_be_num  = 0;
 
-       if (!links)
+       if (!adr_link)
                return -EINVAL;
 
        for (i = 0; i < SDW_MAX_GROUPS; i++)
                group_visited[i] = false;
 
-       for (link = links; link->num_adr; link++) {
+       for (; adr_link->num_adr; adr_link++) {
                const struct snd_soc_acpi_endpoint *endpoint;
                struct sof_sdw_codec_info *codec_info;
                int codec_index;
                int stream;
                u64 adr;
 
-               for (i = 0; i < link->num_adr; i++) {
-                       adr = link->adr_d[i].adr;
+               /* make sure the link mask has a single bit set */
+               if (!is_power_of_2(adr_link->mask))
+                       return -EINVAL;
+
+               for (i = 0; i < adr_link->num_adr; i++) {
+                       adr = adr_link->adr_d[i].adr;
                        codec_index = find_codec_info_part(adr);
                        if (codec_index < 0)
                                return codec_index;
+
                        codec_info = &codec_info_list[codec_index];
 
-                       endpoint = link->adr_d[i].endpoints;
+                       *codecs_num += codec_info->dai_num;
+
+                       if (!adr_link->adr_d[i].name_prefix) {
+                               dev_err(dev, "codec 0x%llx does not have a name prefix\n",
+                                       adr_link->adr_d[i].adr);
+                               return -EINVAL;
+                       }
+
+                       endpoint = adr_link->adr_d[i].endpoints;
+                       if (endpoint->aggregated && !endpoint->group_id) {
+                               dev_err(dev, "invalid group id on link %x\n",
+                                       adr_link->mask);
+                               return -EINVAL;
+                       }
 
                        for (j = 0; j < codec_info->dai_num; j++) {
                                /* count DAI number for playback and capture */
@@ -1090,17 +1126,16 @@ static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links
        dai_links->ops = ops;
 }
 
-static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
+static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
                             unsigned int sdw_version,
                             unsigned int mfg_id,
                             unsigned int part_id,
                             unsigned int class_id,
-                            int index_in_link
-                           )
+                            int index_in_link)
 {
        int i;
 
-       for (i = 0; i < link->num_adr; i++) {
+       for (i = 0; i < adr_link->num_adr; i++) {
                unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
                u64 adr;
 
@@ -1108,7 +1143,7 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
                if (i == index_in_link)
                        continue;
 
-               adr = link->adr_d[i].adr;
+               adr = adr_link->adr_d[i].adr;
 
                sdw1_version = SDW_VERSION(adr);
                mfg1_id = SDW_MFG_ID(adr);
@@ -1125,83 +1160,50 @@ static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
        return true;
 }
 
-static int create_codec_dai_name(struct device *dev,
-                                const struct snd_soc_acpi_link_adr *link,
-                                struct snd_soc_dai_link_component *codec,
-                                int offset,
-                                struct snd_soc_codec_conf *codec_conf,
-                                int codec_count,
-                                int *codec_conf_index,
-                                int adr_index,
-                                int dai_index)
+static int fill_sdw_codec_dlc(struct device *dev,
+                             const struct snd_soc_acpi_link_adr *adr_link,
+                             struct snd_soc_dai_link_component *codec,
+                             int adr_index, int dai_index)
 {
-       int _codec_index = -1;
-       int i;
-
-       /* sanity check */
-       if (*codec_conf_index + link->num_adr - adr_index > codec_count) {
-               dev_err(dev, "codec_conf: out-of-bounds access requested\n");
-               return -EINVAL;
-       }
-
-       for (i = adr_index; i < link->num_adr; i++) {
-               unsigned int sdw_version, unique_id, mfg_id;
-               unsigned int link_id, part_id, class_id;
-               int codec_index, comp_index;
-               char *codec_str;
-               u64 adr;
-
-               adr = link->adr_d[i].adr;
-
-               sdw_version = SDW_VERSION(adr);
-               link_id = SDW_DISCO_LINK_ID(adr);
-               unique_id = SDW_UNIQUE_ID(adr);
-               mfg_id = SDW_MFG_ID(adr);
-               part_id = SDW_PART_ID(adr);
-               class_id = SDW_CLASS_ID(adr);
-
-               comp_index = i - adr_index + offset;
-               if (is_unique_device(link, sdw_version, mfg_id, part_id,
-                                    class_id, i)) {
-                       codec_str = "sdw:%01x:%04x:%04x:%02x";
-                       codec[comp_index].name =
-                               devm_kasprintf(dev, GFP_KERNEL, codec_str,
-                                              link_id, mfg_id, part_id,
-                                              class_id);
-               } else {
-                       codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
-                       codec[comp_index].name =
-                               devm_kasprintf(dev, GFP_KERNEL, codec_str,
-                                              link_id, mfg_id, part_id,
-                                              class_id, unique_id);
-               }
-
-               if (!codec[comp_index].name)
-                       return -ENOMEM;
-
-               codec_index = find_codec_info_part(adr);
-               if (codec_index < 0)
-                       return codec_index;
-               if (_codec_index != -1 && codec_index != _codec_index) {
-                       dev_dbg(dev, "Different devices on the same sdw link\n");
-                       break;
-               }
-               _codec_index = codec_index;
+       unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id;
+       u64 adr = adr_link->adr_d[adr_index].adr;
+       int codec_index;
 
-               codec[comp_index].dai_name =
-                       codec_info_list[codec_index].dais[dai_index].dai_name;
+       codec_index = find_codec_info_part(adr);
+       if (codec_index < 0)
+               return codec_index;
 
-               codec_conf[*codec_conf_index].dlc = codec[comp_index];
-               codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
+       sdw_version = SDW_VERSION(adr);
+       link_id = SDW_DISCO_LINK_ID(adr);
+       unique_id = SDW_UNIQUE_ID(adr);
+       mfg_id = SDW_MFG_ID(adr);
+       part_id = SDW_PART_ID(adr);
+       class_id = SDW_CLASS_ID(adr);
+
+       if (codec_info_list[codec_index].codec_name)
+               codec->name = devm_kstrdup(dev,
+                                          codec_info_list[codec_index].codec_name,
+                                          GFP_KERNEL);
+       else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id,
+                                 class_id, adr_index))
+               codec->name = devm_kasprintf(dev, GFP_KERNEL,
+                                            "sdw:%01x:%04x:%04x:%02x", link_id,
+                                            mfg_id, part_id, class_id);
+       else
+               codec->name = devm_kasprintf(dev, GFP_KERNEL,
+                                            "sdw:%01x:%04x:%04x:%02x:%01x", link_id,
+                                            mfg_id, part_id, class_id, unique_id);
+
+       if (!codec->name)
+               return -ENOMEM;
 
-               ++*codec_conf_index;
-       }
+       codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name;
 
        return 0;
 }
 
 static int set_codec_init_func(struct snd_soc_card *card,
-                              const struct snd_soc_acpi_link_adr *link,
+                              const struct snd_soc_acpi_link_adr *adr_link,
                               struct snd_soc_dai_link *dai_links,
                               bool playback, int group_id, int adr_index, int dai_index)
 {
@@ -1212,34 +1214,34 @@ static int set_codec_init_func(struct snd_soc_card *card,
                 * Initialize the codec. If codec is part of an aggregated
                 * group (group_id>0), initialize all codecs belonging to
                 * same group.
-                * The first link should start with link->adr_d[adr_index]
+                * The first link should start with adr_link->adr_d[adr_index]
                 * because that is the device that we want to initialize and
                 * we should end immediately if it is not aggregated (group_id=0)
                 */
-               for ( ; i < link->num_adr; i++) {
+               for ( ; i < adr_link->num_adr; i++) {
                        int codec_index;
 
-                       codec_index = find_codec_info_part(link->adr_d[i].adr);
-
+                       codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
                        if (codec_index < 0)
                                return codec_index;
 
                        /* The group_id is > 0 iff the codec is aggregated */
-                       if (link->adr_d[i].endpoints->group_id != group_id)
+                       if (adr_link->adr_d[i].endpoints->group_id != group_id)
                                continue;
 
                        if (codec_info_list[codec_index].dais[dai_index].init)
                                codec_info_list[codec_index].dais[dai_index].init(card,
-                                               link,
+                                               adr_link,
                                                dai_links,
                                                &codec_info_list[codec_index],
                                                playback);
                        if (!group_id)
                                return 0;
                }
+
                i = 0;
-               link++;
-       } while (link->mask);
+               adr_link++;
+       } while (adr_link->mask);
 
        return 0;
 }
@@ -1261,73 +1263,45 @@ static int set_codec_init_func(struct snd_soc_card *card,
 static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
                          struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
                          int *codec_num, unsigned int *group_id,
-                         bool *group_generated, int adr_index)
+                         int adr_index)
 {
-       const struct snd_soc_acpi_adr_device *adr_d;
-       const struct snd_soc_acpi_link_adr *adr_next;
-       bool no_aggregation;
-       int index = 0;
+       bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
        int i;
 
-       no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
-       adr_d = &adr_link->adr_d[adr_index];
-
-       /* make sure the link mask has a single bit set */
-       if (!is_power_of_2(adr_link->mask))
-               return -EINVAL;
-
-       cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
-       if (!adr_d->endpoints->aggregated || no_aggregation) {
+       if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) {
+               cpu_dai_id[0] = ffs(adr_link->mask) - 1;
                *cpu_dai_num = 1;
                *codec_num = 1;
                *group_id = 0;
                return 0;
        }
 
-       *group_id = adr_d->endpoints->group_id;
-
-       /* Count endpoints with the same group_id in the adr_link */
        *codec_num = 0;
-       for (i = 0; i < adr_link->num_adr; i++) {
-               if (adr_link->adr_d[i].endpoints->aggregated &&
-                   adr_link->adr_d[i].endpoints->group_id == *group_id)
-                       (*codec_num)++;
-       }
+       *cpu_dai_num = 0;
+       *group_id = adr_link->adr_d[adr_index].endpoints->group_id;
 
-       /* gather other link ID of slaves in the same group */
-       for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
-               adr_next++) {
-               const struct snd_soc_acpi_endpoint *endpoint;
+       /* Count endpoints with the same group_id in the adr_link */
+       for (; adr_link && adr_link->num_adr; adr_link++) {
+               unsigned int link_codecs = 0;
 
-               endpoint = adr_next->adr_d->endpoints;
-               if (!endpoint->aggregated ||
-                   endpoint->group_id != *group_id)
-                       continue;
+               for (i = 0; i < adr_link->num_adr; i++) {
+                       if (adr_link->adr_d[i].endpoints->aggregated &&
+                           adr_link->adr_d[i].endpoints->group_id == *group_id)
+                               link_codecs++;
+               }
 
-               /* make sure the link mask has a single bit set */
-               if (!is_power_of_2(adr_next->mask))
-                       return -EINVAL;
+               if (link_codecs) {
+                       *codec_num += link_codecs;
 
-               if (index >= SDW_MAX_CPU_DAIS) {
-                       dev_err(dev, " cpu_dai_id array overflows");
-                       return -EINVAL;
-               }
+                       if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) {
+                               dev_err(dev, "cpu_dai_id array overflowed\n");
+                               return -EINVAL;
+                       }
 
-               cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
-               for (i = 0; i < adr_next->num_adr; i++) {
-                       if (adr_next->adr_d[i].endpoints->aggregated &&
-                           adr_next->adr_d[i].endpoints->group_id == *group_id)
-                               (*codec_num)++;
+                       cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1;
                }
        }
 
-       /*
-        * indicate CPU DAIs for this group have been generated
-        * to avoid generating CPU DAIs for this group again.
-        */
-       group_generated[*group_id] = true;
-       *cpu_dai_num = index;
-
        return 0;
 }
 
@@ -1344,37 +1318,36 @@ static void set_dailink_map(struct snd_soc_dai_link_codec_ch_map *sdw_codec_ch_m
 
 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
 
-static int create_sdw_dailink(struct snd_soc_card *card,
-                             struct device *dev, int *link_index,
+static int create_sdw_dailink(struct snd_soc_card *card, int *link_index,
                              struct snd_soc_dai_link *dai_links,
                              int sdw_be_num, int sdw_cpu_dai_num,
                              struct snd_soc_dai_link_component *cpus,
-                             const struct snd_soc_acpi_link_adr *link,
-                             int *cpu_id, bool *group_generated,
-                             struct snd_soc_codec_conf *codec_conf,
-                             int codec_count, int *link_id,
+                             const struct snd_soc_acpi_link_adr *adr_link,
+                             int *cpu_id, struct snd_soc_codec_conf *codec_conf,
+                             int codec_count, int *be_id,
                              int *codec_conf_index,
                              bool *ignore_pch_dmic,
                              bool append_dai_type,
                              int adr_index,
                              int dai_index)
 {
-       const struct snd_soc_acpi_link_adr *link_next;
+       struct device *dev = card->dev;
+       const struct snd_soc_acpi_link_adr *adr_link_next;
        struct snd_soc_dai_link_component *codecs;
        struct sof_sdw_codec_info *codec_info;
        int cpu_dai_id[SDW_MAX_CPU_DAIS];
        int cpu_dai_num, cpu_dai_index;
        unsigned int group_id;
-       int codec_idx = 0;
+       int codec_dlc_index = 0;
        int codec_index;
        int codec_num;
        int stream;
        int i = 0;
+       int j, k;
        int ret;
-       int k;
 
-       ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
-                            &group_id, group_generated, adr_index);
+       ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
+                            &group_id, adr_index);
        if (ret)
                return ret;
 
@@ -1383,32 +1356,50 @@ static int create_sdw_dailink(struct snd_soc_card *card,
                return -ENOMEM;
 
        /* generate codec name on different links in the same group */
-       for (link_next = link; link_next && link_next->num_adr &&
-            i < cpu_dai_num; link_next++) {
-               const struct snd_soc_acpi_endpoint *endpoints;
-
-               endpoints = link_next->adr_d->endpoints;
-               if (group_id && (!endpoints->aggregated ||
-                                endpoints->group_id != group_id))
-                       continue;
-
+       j = adr_index;
+       for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr &&
+            i < cpu_dai_num; adr_link_next++) {
                /* skip the link excluded by this processed group */
-               if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
+               if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1)
                        continue;
 
-               ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
-                                           codec_conf, codec_count, codec_conf_index,
-                                           adr_index, dai_index);
-               if (ret < 0)
-                       return ret;
+               /* j reset after loop, adr_index only applies to first link */
+               for (; j < adr_link_next->num_adr; j++) {
+                       const struct snd_soc_acpi_endpoint *endpoints;
+
+                       endpoints = adr_link_next->adr_d[j].endpoints;
+
+                       if (group_id && (!endpoints->aggregated ||
+                                        endpoints->group_id != group_id))
+                               continue;
+
+                       /* sanity check */
+                       if (*codec_conf_index >= codec_count) {
+                               dev_err(dev, "codec_conf array overflowed\n");
+                               return -EINVAL;
+                       }
+
+                       ret = fill_sdw_codec_dlc(dev, adr_link_next,
+                                                &codecs[codec_dlc_index],
+                                                j, dai_index);
+                       if (ret)
+                               return ret;
+
+                       codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index];
+                       codec_conf[*codec_conf_index].name_prefix =
+                                       adr_link_next->adr_d[j].name_prefix;
+
+                       codec_dlc_index++;
+                       (*codec_conf_index)++;
+               }
+               j = 0;
 
                /* check next link to create codec dai in the processed group */
                i++;
-               codec_idx += link_next->num_adr;
        }
 
        /* find codec info to create BE DAI */
-       codec_index = find_codec_info_part(link->adr_d[adr_index].adr);
+       codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr);
        if (codec_index < 0)
                return codec_index;
        codec_info = &codec_info_list[codec_index];
@@ -1431,9 +1422,9 @@ static int create_sdw_dailink(struct snd_soc_card *card,
                if (!codec_info->dais[dai_index].direction[stream])
                        continue;
 
-               *link_id = codec_info->dais[dai_index].dailink[stream];
-               if (*link_id < 0) {
-                       dev_err(dev, "Invalid dailink id %d\n", *link_id);
+               *be_id = codec_info->dais[dai_index].dailink[stream];
+               if (*be_id < 0) {
+                       dev_err(dev, "Invalid dailink id %d\n", *be_id);
                        return -EINVAL;
                }
 
@@ -1466,7 +1457,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
                                return -ENOMEM;
 
                        if (cpu_dai_index >= sdw_cpu_dai_num) {
-                               dev_err(dev, "invalid cpu dai index %d",
+                               dev_err(dev, "invalid cpu dai index %d\n",
                                        cpu_dai_index);
                                return -EINVAL;
                        }
@@ -1479,18 +1470,18 @@ static int create_sdw_dailink(struct snd_soc_card *card,
                 * not be larger than sdw_be_num
                 */
                if (*link_index >= sdw_be_num) {
-                       dev_err(dev, "invalid dai link index %d", *link_index);
+                       dev_err(dev, "invalid dai link index %d\n", *link_index);
                        return -EINVAL;
                }
 
                if (*cpu_id >= sdw_cpu_dai_num) {
-                       dev_err(dev, " invalid cpu dai index %d", *cpu_id);
+                       dev_err(dev, "invalid cpu dai index %d\n", *cpu_id);
                        return -EINVAL;
                }
 
                playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
                capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
-               init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
+               init_dai_link(dev, dai_links + *link_index, (*be_id)++, name,
                              playback, capture,
                              cpus + *cpu_id, cpu_dai_num,
                              codecs, codec_num,
@@ -1504,10 +1495,10 @@ static int create_sdw_dailink(struct snd_soc_card *card,
 
                set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num);
                dai_links[*link_index].codec_ch_maps = sdw_codec_ch_maps;
-               ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
+               ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++,
                                          playback, group_id, adr_index, dai_index);
                if (ret < 0) {
-                       dev_err(dev, "failed to init codec %d", codec_index);
+                       dev_err(dev, "failed to init codec %d\n", codec_index);
                        return ret;
                }
 
@@ -1519,65 +1510,26 @@ static int create_sdw_dailink(struct snd_soc_card *card,
 
 #define IDISP_CODEC_MASK       0x4
 
-static int sof_card_codec_conf_alloc(struct device *dev,
-                                    struct snd_soc_acpi_mach_params *mach_params,
-                                    struct snd_soc_codec_conf **codec_conf,
-                                    int *codec_conf_count)
+static int sof_card_dai_links_create(struct snd_soc_card *card)
 {
-       const struct snd_soc_acpi_link_adr *adr_link;
-       struct snd_soc_codec_conf *c_conf;
-       int num_codecs = 0;
-       int codec_index;
-       int i;
-
-       adr_link = mach_params->links;
-       if (!adr_link)
-               return -EINVAL;
-
-       /* generate DAI links by each sdw link */
-       for (; adr_link->num_adr; adr_link++) {
-               for (i = 0; i < adr_link->num_adr; i++) {
-                       if (!adr_link->adr_d[i].name_prefix) {
-                               dev_err(dev, "codec 0x%llx does not have a name prefix\n",
-                                       adr_link->adr_d[i].adr);
-                               return -EINVAL;
-                       }
-                       codec_index = find_codec_info_part(adr_link->adr_d[i].adr);
-                       if (codec_index < 0)
-                               return codec_index;
-                       num_codecs += codec_info_list[codec_index].dai_num;
-               }
-       }
-
-       c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
-       if (!c_conf)
-               return -ENOMEM;
-
-       *codec_conf = c_conf;
-       *codec_conf_count = num_codecs;
-
-       return 0;
-}
-
-static int sof_card_dai_links_create(struct device *dev,
-                                    struct snd_soc_acpi_mach *mach,
-                                    struct snd_soc_card *card)
-{
-       int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
+       struct device *dev = card->dev;
+       struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
+       int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0;
        struct mc_private *ctx = snd_soc_card_get_drvdata(card);
        struct snd_soc_dai_link_component *idisp_components;
        struct snd_soc_dai_link_component *ssp_components;
-       struct snd_soc_acpi_mach_params *mach_params;
-       const struct snd_soc_acpi_link_adr *adr_link;
+       struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
+       const struct snd_soc_acpi_link_adr *adr_link = mach_params->links;
+       bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION);
        struct snd_soc_dai_link_component *cpus;
        struct snd_soc_codec_conf *codec_conf;
        bool append_dai_type = false;
        bool ignore_pch_dmic = false;
-       int codec_conf_count;
+       int codec_conf_num = 0;
        int codec_conf_index = 0;
-       bool group_generated[SDW_MAX_GROUPS];
+       bool group_generated[SDW_MAX_GROUPS] = { };
        int ssp_codec_index, ssp_mask;
-       struct snd_soc_dai_link *links;
+       struct snd_soc_dai_link *dai_links;
        int num_links, link_index = 0;
        char *name, *cpu_name;
        int total_cpu_dai_num;
@@ -1585,30 +1537,15 @@ static int sof_card_dai_links_create(struct device *dev,
        int i, j, be_id = 0;
        int codec_index;
        int cpu_id = 0;
-       int comp_num;
        int ret;
 
-       mach_params = &mach->mach_params;
-
-       /* allocate codec conf, will be populated when dailinks are created */
-       ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
-       if (ret < 0)
+       ret = get_dailink_info(dev, adr_link, &sdw_be_num, &sdw_cpu_dai_num,
+                              &codec_conf_num);
+       if (ret < 0) {
+               dev_err(dev, "failed to get sdw link info %d\n", ret);
                return ret;
-
-       /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
-       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
-               codec_info_list[i].amp_num = 0;
-
-       if (mach_params->codec_mask & IDISP_CODEC_MASK) {
-               ctx->idisp_codec = true;
-
-               if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
-                       hdmi_num = SOF_TGL_HDMI_COUNT;
-               else
-                       hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
        }
 
-       ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
        /*
         * on generic tgl platform, I2S or sdw mode is supported
         * based on board rework. A ACPI device is registered in
@@ -1616,54 +1553,52 @@ static int sof_card_dai_links_create(struct device *dev,
         * Here check ACPI ID to confirm I2S is supported.
         */
        ssp_codec_index = find_codec_info_acpi(mach->id);
-       ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
-       comp_num = hdmi_num + ssp_num;
+       if (ssp_codec_index >= 0) {
+               ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
+               ssp_num = hweight_long(ssp_mask);
+       }
 
-       ret = get_sdw_dailink_info(dev, mach_params->links,
-                                  &sdw_be_num, &sdw_cpu_dai_num);
-       if (ret < 0) {
-               dev_err(dev, "failed to get sdw link info %d", ret);
-               return ret;
+       if (mach_params->codec_mask & IDISP_CODEC_MASK) {
+               ctx->idisp_codec = true;
+
+               if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
+                       hdmi_num = SOF_TGL_HDMI_COUNT;
+               else
+                       hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
        }
 
        /* enable dmic01 & dmic16k */
-       dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
-       comp_num += dmic_num;
+       if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num)
+               dmic_num = 2;
 
        if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
-               comp_num++;
+               bt_num = 1;
 
-       dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
-               dmic_num, ctx->idisp_codec ? hdmi_num : 0);
+       dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
+               sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num);
 
        /* allocate BE dailinks */
-       num_links = comp_num + sdw_be_num;
-       links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
+       num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
+       dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
+       if (!dai_links)
+               return -ENOMEM;
 
        /* allocated CPU DAIs */
-       total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
-       cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
-                           GFP_KERNEL);
+       total_cpu_dai_num = sdw_cpu_dai_num + ssp_num + dmic_num + hdmi_num + bt_num;
+       cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus), GFP_KERNEL);
+       if (!cpus)
+               return -ENOMEM;
 
-       if (!links || !cpus)
+       /* allocate codec conf, will be populated when dailinks are created */
+       codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf),
+                                 GFP_KERNEL);
+       if (!codec_conf)
                return -ENOMEM;
 
        /* SDW */
        if (!sdw_be_num)
                goto SSP;
 
-       adr_link = mach_params->links;
-       if (!adr_link)
-               return -EINVAL;
-
-       /*
-        * SoundWire Slaves aggregated in the same group may be
-        * located on different hardware links. Clear array to indicate
-        * CPU DAIs for this group have not been generated.
-        */
-       for (i = 0; i < SDW_MAX_GROUPS; i++)
-               group_generated[i] = false;
-
        for (i = 0; i < SDW_MAX_LINKS; i++)
                sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE;
 
@@ -1702,11 +1637,6 @@ out:
                        const struct snd_soc_acpi_endpoint *endpoint;
 
                        endpoint = adr_link->adr_d[i].endpoints;
-                       if (endpoint->aggregated && !endpoint->group_id) {
-                               dev_err(dev, "invalid group id on link %x",
-                                       adr_link->mask);
-                               continue;
-                       }
 
                        /* this group has been generated */
                        if (endpoint->aggregated &&
@@ -1719,17 +1649,20 @@ out:
                                return codec_index;
 
                        for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) {
-                               ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
-                                                        sdw_cpu_dai_num, cpus, adr_link,
-                                                        &cpu_id, group_generated,
-                                                        codec_conf, codec_conf_count,
+                               ret = create_sdw_dailink(card, &link_index, dai_links,
+                                                        sdw_be_num, sdw_cpu_dai_num, cpus,
+                                                        adr_link, &cpu_id,
+                                                        codec_conf, codec_conf_num,
                                                         &be_id, &codec_conf_index,
                                                         &ignore_pch_dmic, append_dai_type, i, j);
                                if (ret < 0) {
-                                       dev_err(dev, "failed to create dai link %d", link_index);
+                                       dev_err(dev, "failed to create dai link %d\n", link_index);
                                        return ret;
                                }
                        }
+
+                       if (aggregation && endpoint->aggregated)
+                               group_generated[endpoint->group_id] = true;
                }
        }
 
@@ -1773,13 +1706,13 @@ SSP:
 
                playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
                capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
-               init_dai_link(dev, links + link_index, be_id, name,
+               init_dai_link(dev, dai_links + link_index, be_id, name,
                              playback, capture,
                              cpus + cpu_id, 1,
                              ssp_components, 1,
                              NULL, info->ops);
 
-               ret = info->dais[0].init(card, NULL, links + link_index, info, 0);
+               ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0);
                if (ret < 0)
                        return ret;
 
@@ -1794,7 +1727,7 @@ DMIC:
                        goto HDMI;
                }
                cpus[cpu_id].dai_name = "DMIC01 Pin";
-               init_dai_link(dev, links + link_index, be_id, "dmic01",
+               init_dai_link(dev, dai_links + link_index, be_id, "dmic01",
                              0, 1, // DMIC only supports capture
                              cpus + cpu_id, 1,
                              dmic_component, 1,
@@ -1802,7 +1735,7 @@ DMIC:
                INC_ID(be_id, cpu_id, link_index);
 
                cpus[cpu_id].dai_name = "DMIC16k Pin";
-               init_dai_link(dev, links + link_index, be_id, "dmic16k",
+               init_dai_link(dev, dai_links + link_index, be_id, "dmic16k",
                              0, 1, // DMIC only supports capture
                              cpus + cpu_id, 1,
                              dmic_component, 1,
@@ -1845,7 +1778,7 @@ HDMI:
                        return -ENOMEM;
 
                cpus[cpu_id].dai_name = cpu_name;
-               init_dai_link(dev, links + link_index, be_id, name,
+               init_dai_link(dev, dai_links + link_index, be_id, name,
                              1, 0, // HDMI only supports playback
                              cpus + cpu_id, 1,
                              idisp_components + i, 1,
@@ -1866,15 +1799,15 @@ HDMI:
                        return -ENOMEM;
 
                cpus[cpu_id].dai_name = cpu_name;
-               init_dai_link(dev, links + link_index, be_id, name, 1, 1,
-                               cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
+               init_dai_link(dev, dai_links + link_index, be_id, name, 1, 1,
+                             cpus + cpu_id, 1, &asoc_dummy_dlc, 1, NULL, NULL);
        }
 
-       card->dai_link = links;
+       card->dai_link = dai_links;
        card->num_links = num_links;
 
        card->codec_conf = codec_conf;
-       card->num_configs = codec_conf_count;
+       card->num_configs = codec_conf_num;
 
        return 0;
 }
@@ -1913,15 +1846,15 @@ static struct snd_soc_card card_sof_sdw = {
 static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card,
                                                       const char *dai_name)
 {
-       struct snd_soc_dai_link *link;
+       struct snd_soc_dai_link *dai_link;
        int i;
        int j;
 
-       for_each_card_prelinks(card, i, link) {
-               for (j = 0; j < link->num_codecs; j++) {
+       for_each_card_prelinks(card, i, dai_link) {
+               for (j = 0; j < dai_link->num_codecs; j++) {
                        /* Check each codec in a link */
-                       if (!strcmp(link->codecs[j].dai_name, dai_name))
-                               return link;
+                       if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
+                               return dai_link;
                }
        }
        return NULL;
@@ -1929,7 +1862,7 @@ static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card
 
 static void mc_dailink_exit_loop(struct snd_soc_card *card)
 {
-       struct snd_soc_dai_link *link;
+       struct snd_soc_dai_link *dai_link;
        int ret;
        int i, j;
 
@@ -1942,10 +1875,11 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card)
                         * We don't need to call .exit function if there is no matched
                         * dai link found.
                         */
-                       link = mc_find_codec_dai_used(card, codec_info_list[i].dais[j].dai_name);
-                       if (link) {
+                       dai_link = mc_find_codec_dai_used(card,
+                                                         codec_info_list[i].dais[j].dai_name);
+                       if (dai_link) {
                                /* Do the .exit function if the codec dai is used in the link */
-                               ret = codec_info_list[i].dais[j].exit(card, link);
+                               ret = codec_info_list[i].dais[j].exit(card, dai_link);
                                if (ret)
                                        dev_warn(card->dev,
                                                 "codec exit failed %d\n",
@@ -1959,34 +1893,38 @@ static void mc_dailink_exit_loop(struct snd_soc_card *card)
 static int mc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &card_sof_sdw;
-       struct snd_soc_acpi_mach *mach;
+       struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
        struct mc_private *ctx;
        int amp_num = 0, i;
        int ret;
 
-       dev_dbg(&pdev->dev, "Entry\n");
+       card->dev = &pdev->dev;
+
+       dev_dbg(card->dev, "Entry\n");
 
-       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
+       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+       snd_soc_card_set_drvdata(card, ctx);
+
        dmi_check_system(sof_sdw_quirk_table);
 
        if (quirk_override != -1) {
-               dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
+               dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
                         sof_sdw_quirk, quirk_override);
                sof_sdw_quirk = quirk_override;
        }
-       log_quirks(&pdev->dev);
 
-       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+       log_quirks(card->dev);
 
-       card->dev = &pdev->dev;
-       snd_soc_card_set_drvdata(card, ctx);
+       /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
+       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
+               codec_info_list[i].amp_num = 0;
 
-       mach = pdev->dev.platform_data;
-       ret = sof_card_dai_links_create(&pdev->dev, mach,
-                                       card);
+       ret = sof_card_dai_links_create(card);
        if (ret < 0)
                return ret;
 
@@ -2017,7 +1955,7 @@ static int mc_probe(struct platform_device *pdev)
        card->long_name = sdw_card_long_name;
 
        /* Register the card */
-       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       ret = devm_snd_soc_register_card(card->dev, card);
        if (ret) {
                dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
                mc_dailink_exit_loop(card);
@@ -2036,6 +1974,12 @@ static void mc_remove(struct platform_device *pdev)
        mc_dailink_exit_loop(card);
 }
 
+static const struct platform_device_id mc_id_table[] = {
+       { "sof_sdw", },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, mc_id_table);
+
 static struct platform_driver sof_sdw_driver = {
        .driver = {
                .name = "sof_sdw",
@@ -2043,6 +1987,7 @@ static struct platform_driver sof_sdw_driver = {
        },
        .probe = mc_probe,
        .remove_new = mc_remove,
+       .id_table = mc_id_table,
 };
 
 module_platform_driver(sof_sdw_driver);
@@ -2052,6 +1997,5 @@ MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sof_sdw");
 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);
index 37402170d5f9a4025315daa64a9a656b0605c27a..2f4fe6bc3d5d061d5e65c2130d9e7884b759b3ad 100644 (file)
@@ -80,6 +80,7 @@ struct sof_sdw_dai_info {
 struct sof_sdw_codec_info {
        const int part_id;
        const int version_id;
+       const char *codec_name;
        int amp_num;
        const u8 acpi_id[ACPI_ID_LEN];
        const bool ignore_pch_dmic;
@@ -205,4 +206,10 @@ int sof_sdw_cs42l42_init(struct snd_soc_card *card,
                         struct sof_sdw_codec_info *info,
                         bool playback);
 
+/* CS AMP support */
+int sof_sdw_cs_amp_init(struct snd_soc_card *card,
+                       const struct snd_soc_acpi_link_adr *link,
+                       struct snd_soc_dai_link *dai_links,
+                       struct sof_sdw_codec_info *info,
+                       bool playback);
 #endif
index c4a16e4c9f69c047605d37d10802ab23604e9183..ad130d913415e090be14d97e5c998e2151672bb7 100644 (file)
@@ -99,9 +99,9 @@ static int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd)
        jack = &ctx->sdw_headset;
 
        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_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);
 
        ret = snd_soc_component_set_jack(component, jack, NULL);
 
diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c
new file mode 100644 (file)
index 0000000..98f6546
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2023 Intel Corporation
+
+/*
+ *  sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
+#include "sof_sdw_common.h"
+
+#define CODEC_NAME_SIZE        8
+
+static int cs_spk_init(struct snd_soc_pcm_runtime *rtd)
+{
+       const char *dai_name = rtd->dai_link->codecs->dai_name;
+       struct snd_soc_card *card = rtd->card;
+       char codec_name[CODEC_NAME_SIZE];
+
+       snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name);
+       card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+                                         "%s spk:%s",
+                                         card->components, codec_name);
+       if (!card->components)
+               return -ENOMEM;
+
+       return 0;
+}
+
+
+int sof_sdw_cs_amp_init(struct snd_soc_card *card,
+                       const struct snd_soc_acpi_link_adr *link,
+                       struct snd_soc_dai_link *dai_links,
+                       struct sof_sdw_codec_info *info,
+                       bool playback)
+{
+       /* Count amp number and do init on playback link only. */
+       if (!playback)
+               return 0;
+
+       info->amp_num++;
+       dai_links->init = cs_spk_init;
+
+       return 0;
+}
index 0aef718e82b2757d3802d57aa663fd6a1b31068c..5aa16fd3939b9f7639c1a9256adafa41a216a2a4 100644 (file)
@@ -472,6 +472,15 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_NO_OF_HDMI_PLAYBACK(3) |
                                        SOF_HDMI_PLAYBACK_PRESENT),
        },
+       {
+               .name = "rpl_lt6911_hdmi_ssp",
+               .driver_data = (kernel_ulong_t)(SOF_NO_OF_HDMI_CAPTURE_SSP(2) |
+                                       SOF_HDMI_CAPTURE_1_SSP(0) |
+                                       SOF_HDMI_CAPTURE_2_SSP(2) |
+                                       SOF_SSP_HDMI_CAPTURE_PRESENT |
+                                       SOF_NO_OF_HDMI_PLAYBACK(3) |
+                                       SOF_HDMI_PLAYBACK_PRESENT),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index 30ca5416c9a3f6610710ec26a0723d9c07ccc11d..f1a5cb825ff1f2e12549909b70433bcc664035b0 100644 (file)
@@ -684,6 +684,10 @@ static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
        return 0;
 }
 
+static const struct snd_soc_dai_ops catpt_dai_ops = {
+       .pcm_new = catpt_dai_pcm_new,
+};
+
 static struct snd_soc_dai_driver dai_drivers[] = {
 /* FE DAIs */
 {
@@ -764,7 +768,6 @@ static struct snd_soc_dai_driver dai_drivers[] = {
 {
        .name = "ssp0-port",
        .id = CATPT_SSP_IFACE_0,
-       .pcm_new = catpt_dai_pcm_new,
        .playback = {
                .channels_min = 1,
                .channels_max = 8,
@@ -773,11 +776,11 @@ static struct snd_soc_dai_driver dai_drivers[] = {
                .channels_min = 1,
                .channels_max = 8,
        },
+       .ops = &catpt_dai_ops,
 },
 {
        .name = "ssp1-port",
        .id = CATPT_SSP_IFACE_1,
-       .pcm_new = catpt_dai_pcm_new,
        .playback = {
                .channels_min = 1,
                .channels_max = 8,
@@ -786,6 +789,7 @@ static struct snd_soc_dai_driver dai_drivers[] = {
                .channels_min = 1,
                .channels_max = 8,
        },
+       .ops = &catpt_dai_ops,
 },
 };
 
index bcd66e0094b4bc2c2e8215dfe0f9e12fb9d79ec5..8e995edf4c10da3e5328009eb1c027fb29e03f77 100644 (file)
@@ -568,6 +568,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
                .quirk_data = &adl_max98390_amp,
                .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg",
        },
+       {
+               .comp_ids = &adl_rt5682_rt5682s_hp,
+               .drv_name = "adl_rt5682_c1_h02",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &adl_lt6911_hdmi,
+               .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg",
+       },
        {
                .comp_ids = &adl_rt5682_rt5682s_hp,
                .drv_name = "adl_rt5682",
index f5c7e1bbded0623b9264c65500095772e317d425..f56bd7d656e979adcc93f4803f0cda6aeb77c454 100644 (file)
@@ -34,6 +34,11 @@ static const struct snd_soc_acpi_codecs mx98360a_spk = {
        .codecs = {"MX98360A"}
 };
 
+static struct snd_soc_acpi_codecs rt5650_spk = {
+       .num_codecs = 1,
+       .codecs = {"10EC5650"}
+};
+
 static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = {
        .num_codecs = 2,
        .codecs = {"10EC5682", "RTL5682"},
@@ -98,6 +103,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
                                        SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
                                        SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
        },
+       {
+               .id = "10EC5650",
+               .drv_name = "jsl_rt5650",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &rt5650_spk,
+               .sof_tplg_filename = "sof-jsl-rt5650.tplg",
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines);
index ed9821adc1d9dde7d327833d892d27a7547bc1cb..0304246d292238323d917902e241013662a4c44a 100644 (file)
@@ -161,6 +161,33 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = {
+       {
+               .adr = 0x000130025D131801ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_l_endpoint,
+               .name_prefix = "rt1318-1"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = {
+       {
+               .adr = 0x000232025D131801ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_r_endpoint,
+               .name_prefix = "rt1318-2"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
+       {
+               .adr = 0x000030025D071401ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt714"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt714_1_adr[] = {
        {
                .adr = 0x000130025D071401ull,
@@ -232,6 +259,25 @@ static const struct snd_soc_acpi_link_adr mtl_3_in_1_sdca[] = {
        {}
 };
 
+static const struct snd_soc_acpi_link_adr mtl_sdw_rt1318_l12_rt714_l0[] = {
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+               .adr_d = rt1318_1_group1_adr,
+       },
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+               .adr_d = rt1318_2_group1_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt714_0_adr),
+               .adr_d = rt714_0_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = {
        {
                .adr = 0x000230019F836300ull,
@@ -298,6 +344,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
        },
+       {
+               .link_mask = GENMASK(2, 0),
+               .links = mtl_sdw_rt1318_l12_rt714_l0,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg"
+       },
        {
                .link_mask = GENMASK(3, 0),
                .links = mtl_3_in_1_sdca,
index 302a08018572155134d0c980ed8a5c129f3e2f78..122673c1dae27073a350465ff06a14a0130c056f 100644 (file)
@@ -308,6 +308,15 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] =
        {}
 };
 
+static const struct snd_soc_acpi_link_adr rpl_sdca_rvp[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+               .adr_d = rt711_sdca_0_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_link_adr rplp_crb[] = {
        {
                .mask = BIT(2),
@@ -322,6 +331,16 @@ static const struct snd_soc_acpi_codecs rpl_rt5682_hp = {
        .codecs = {"10EC5682", "RTL5682"},
 };
 
+static const struct snd_soc_acpi_codecs rpl_essx_83x6 = {
+       .num_codecs = 3,
+       .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
+};
+
+static const struct snd_soc_acpi_codecs rpl_max98357a_amp = {
+       .num_codecs = 1,
+       .codecs = {"MX98357A"}
+};
+
 static const struct snd_soc_acpi_codecs rpl_max98360a_amp = {
        .num_codecs = 1,
        .codecs = {"MX98360A"},
@@ -332,12 +351,29 @@ static const struct snd_soc_acpi_codecs rpl_max98373_amp = {
        .codecs = {"MX98373"}
 };
 
+static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = {
+       .num_codecs = 1,
+       .codecs = {"INTC10B0"}
+};
+
+static const struct snd_soc_acpi_codecs rpl_nau8318_amp = {
+       .num_codecs = 1,
+       .codecs = {"NVTN2012"}
+};
+
 static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = {
        .num_codecs = 1,
        .codecs = {"RTL1019"}
 };
 
 struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
+       {
+               .comp_ids = &rpl_rt5682_hp,
+               .drv_name = "rpl_mx98357_rt5682",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &rpl_max98357a_amp,
+               .sof_tplg_filename = "sof-rpl-max98357a-rt5682.tplg",
+       },
        {
                .comp_ids = &rpl_rt5682_hp,
                .drv_name = "rpl_mx98360_rt5682",
@@ -352,6 +388,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
                .quirk_data = &rpl_max98373_amp,
                .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg",
        },
+       {
+               .id = "10508825",
+               .drv_name = "rpl_nau8318_8825",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &rpl_nau8318_amp,
+               .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg",
+       },
        {
                .comp_ids = &rpl_rt5682_hp,
                .drv_name = "rpl_rt1019_rt5682",
@@ -359,6 +402,26 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = {
                .quirk_data = &rpl_rt1019p_amp,
                .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg",
        },
+       {
+               .comp_ids = &rpl_essx_83x6,
+               .drv_name = "rpl_es83x6_c1_h02",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &rpl_lt6911_hdmi,
+               .sof_tplg_filename = "sof-rpl-es83x6-ssp1-hdmi-ssp02.tplg",
+       },
+       {
+               .comp_ids = &rpl_essx_83x6,
+               .drv_name = "sof-essx8336",
+               .sof_tplg_filename = "sof-rpl-es83x6", /* the tplg suffix is added at run time */
+               .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER |
+                                       SND_SOC_ACPI_TPLG_INTEL_SSP_MSB |
+                                       SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER,
+       },
+       {
+               .id = "INTC10B0",
+               .drv_name = "rpl_lt6911_hdmi_ssp",
+               .sof_tplg_filename = "sof-rpl-nocodec-hdmi-ssp02.tplg"
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines);
@@ -413,6 +476,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-rpl-rt711-l0.tplg",
        },
+       {
+               .link_mask = 0x1, /* link0 required */
+               .links = rpl_sdca_rvp,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-rpl-rt711-l0.tplg",
+       },
        {
                .link_mask = 0x4, /* link2 required */
                .links = rplp_crb,
index b4893365d01d5e537e805c9c8fd03b6b23b625a7..6b06b7b5ede86927d446f2c512f5239348a58b1e 100644 (file)
@@ -733,6 +733,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops kmb_dai_ops = {
+       .probe          = kmb_probe,
        .startup        = kmb_dai_startup,
        .trigger        = kmb_dai_trigger,
        .hw_params      = kmb_dai_hw_params,
@@ -755,7 +756,6 @@ static struct snd_soc_dai_driver intel_kmb_hdmi_dai[] = {
                                    SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE),
                },
                .ops = &kmb_dai_ops,
-               .probe = kmb_probe,
        },
 };
 
@@ -787,7 +787,6 @@ static struct snd_soc_dai_driver intel_kmb_i2s_dai[] = {
                                    SNDRV_PCM_FMTBIT_S16_LE),
                },
                .ops = &kmb_dai_ops,
-               .probe = kmb_probe,
        },
 };
 
@@ -807,7 +806,6 @@ static struct snd_soc_dai_driver intel_kmb_tdm_dai[] = {
                                    SNDRV_PCM_FMTBIT_S16_LE),
                },
                .ops = &kmb_dai_ops,
-               .probe = kmb_probe,
        },
 };
 
index d31509298a0a5d4459d3254c983af9ed0bddd84a..fc2eb04da17213a57968d5b1e201610cbed5d6fa 100644 (file)
@@ -169,7 +169,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
 
 static const struct skl_dsp_ops dsp_ops[] = {
        {
-               .id = 0x9d70,
+               .id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
                .num_cores = 2,
                .loader_ops = skl_get_loader_ops,
                .init = skl_sst_dsp_init,
@@ -177,7 +177,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = skl_sst_dsp_cleanup
        },
        {
-               .id = 0x9d71,
+               .id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
                .num_cores = 2,
                .loader_ops = skl_get_loader_ops,
                .init = skl_sst_dsp_init,
@@ -185,7 +185,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = skl_sst_dsp_cleanup
        },
        {
-               .id = 0x5a98,
+               .id = PCI_DEVICE_ID_INTEL_HDA_APL,
                .num_cores = 2,
                .loader_ops = bxt_get_loader_ops,
                .init = bxt_sst_dsp_init,
@@ -193,7 +193,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = bxt_sst_dsp_cleanup
        },
        {
-               .id = 0x3198,
+               .id = PCI_DEVICE_ID_INTEL_HDA_GML,
                .num_cores = 2,
                .loader_ops = bxt_get_loader_ops,
                .init = bxt_sst_dsp_init,
@@ -201,7 +201,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = bxt_sst_dsp_cleanup
        },
        {
-               .id = 0x9dc8,
+               .id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
                .num_cores = 4,
                .loader_ops = bxt_get_loader_ops,
                .init = cnl_sst_dsp_init,
@@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = cnl_sst_dsp_cleanup
        },
        {
-               .id = 0xa348,
+               .id = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
                .num_cores = 4,
                .loader_ops = bxt_get_loader_ops,
                .init = cnl_sst_dsp_init,
@@ -217,7 +217,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = cnl_sst_dsp_cleanup
        },
        {
-               .id = 0x02c8,
+               .id = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
                .num_cores = 4,
                .loader_ops = bxt_get_loader_ops,
                .init = cnl_sst_dsp_init,
@@ -225,7 +225,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
                .cleanup = cnl_sst_dsp_cleanup
        },
        {
-               .id = 0x06c8,
+               .id = PCI_DEVICE_ID_INTEL_HDA_CML_H,
                .num_cores = 4,
                .loader_ops = bxt_get_loader_ops,
                .init = cnl_sst_dsp_init,
index a4209d88b0c6c75f11929361c585acfa27bbb9a0..ac3dc8c63c260d681251ecb67ba90ca8389884cb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <sound/hdaudio.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include "skl.h"
@@ -152,7 +153,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
         * The recommended SDxFMT programming sequence for BXT
         * platforms is to couple the stream before writing the format
         */
-       if (IS_BXT(skl->pci)) {
+       if (HDA_CONTROLLER_IS_APL(skl->pci)) {
                snd_hdac_ext_stream_decouple(bus, stream, false);
                err = snd_hdac_stream_setup(hdac_stream(stream));
                snd_hdac_ext_stream_decouple(bus, stream, true);
index 998bd0232cf1d4b66020bfeb8d8fc5bb6604e301..77408a981b9773874f4dd1610de772f971d6c6cf 100644 (file)
@@ -608,8 +608,8 @@ struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
 static void init_skl_xtal_rate(int pci_id)
 {
        switch (pci_id) {
-       case 0x9d70:
-       case 0x9d71:
+       case PCI_DEVICE_ID_INTEL_HDA_SKL_LP:
+       case PCI_DEVICE_ID_INTEL_HDA_KBL_LP:
                skl_clk_src[0].rate = 24000000;
                return;
 
@@ -1145,44 +1145,28 @@ static void skl_remove(struct pci_dev *pci)
 /* PCI IDs */
 static const struct pci_device_id skl_ids[] = {
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
-       /* Sunrise Point-LP */
-       { PCI_DEVICE(0x8086, 0x9d70),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
-       /* BXT-P */
-       { PCI_DEVICE(0x8086, 0x5a98),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
-       /* KBL */
-       { PCI_DEVICE(0x8086, 0x9D71),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
-       /* GLK */
-       { PCI_DEVICE(0x8086, 0x3198),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
-       /* CNL */
-       { PCI_DEVICE(0x8086, 0x9dc8),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
-       /* CFL */
-       { PCI_DEVICE(0x8086, 0xa348),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP)
-       /* CML-LP */
-       { PCI_DEVICE(0x8086, 0x02c8),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) },
 #endif
 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H)
-       /* CML-H */
-       { PCI_DEVICE(0x8086, 0x06c8),
-               .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) },
 #endif
        { 0, }
 };
index 578af21769c9db7cfa7ce1f04c8185e2b948c058..51761953161589f5851123ecaa3406a33076dda2 100644 (file)
@@ -328,6 +328,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
+       .probe = jz4740_i2s_dai_probe,
        .startup = jz4740_i2s_startup,
        .shutdown = jz4740_i2s_shutdown,
        .trigger = jz4740_i2s_trigger,
@@ -341,7 +342,6 @@ static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
                         SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_driver jz4740_i2s_dai = {
-       .probe = jz4740_i2s_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -384,7 +384,6 @@ static const struct i2s_soc_info x1000_i2s_soc_info = {
 };
 
 static struct snd_soc_dai_driver jz4770_i2s_dai = {
-       .probe = jz4740_i2s_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
index 9ded163297477d186c4f2f1121c8e71f4f2e0942..406ee8db1a3c5ffdb78246f236f799676164e903 100644 (file)
@@ -208,7 +208,7 @@ static struct platform_driver loongson_audio_driver = {
        .driver = {
                .name = "loongson-asoc-card",
                .pm = &snd_soc_pm_ops,
-               .of_match_table = of_match_ptr(loongson_asoc_dt_ids),
+               .of_match_table = loongson_asoc_dt_ids,
        },
 };
 module_platform_driver(loongson_audio_driver);
index b919f0fe8361525b286b40d7ea5acf3b7f645392..d45228a3a558b0322c00954277b657805b54727d 100644 (file)
@@ -204,13 +204,6 @@ static int loongson_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        return 0;
 }
 
-static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
-       .trigger        = loongson_i2s_trigger,
-       .hw_params      = loongson_i2s_hw_params,
-       .set_sysclk     = loongson_i2s_set_dai_sysclk,
-       .set_fmt        = loongson_i2s_set_fmt,
-};
-
 static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct loongson_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
@@ -222,9 +215,16 @@ static int loongson_i2s_dai_probe(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops loongson_i2s_dai_ops = {
+       .probe          = loongson_i2s_dai_probe,
+       .trigger        = loongson_i2s_trigger,
+       .hw_params      = loongson_i2s_hw_params,
+       .set_sysclk     = loongson_i2s_set_dai_sysclk,
+       .set_fmt        = loongson_i2s_set_fmt,
+};
+
 struct snd_soc_dai_driver loongson_i2s_dai = {
        .name = "loongson-i2s",
-       .probe = loongson_i2s_dai_probe,
        .playback = {
                .stream_name = "CPU-Playback",
                .channels_min = 1,
index 90db67e0ce4fb8b3be64deba1837bc5c5d16f911..8d1bc88144866fd08a51fbf93b84eecf471d4b2f 100644 (file)
@@ -54,6 +54,26 @@ config SND_SOC_MT6797_MT6351
          Select Y if you have such device.
          If unsure select "N".
 
+config SND_SOC_MT7986
+       tristate "ASoC support for Mediatek MT7986 chip"
+       depends on ARCH_MEDIATEK
+       select SND_SOC_MEDIATEK
+       help
+         This adds ASoC platform driver support for MediaTek MT7986 chip
+         that can be used with other codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
+config SND_SOC_MT7986_WM8960
+       tristate "ASoc Audio driver for MT7986 with WM8960 codec"
+       depends on SND_SOC_MT7986 && I2C
+       select SND_SOC_WM8960
+       help
+         This adds support for ASoC machine driver for MediaTek MT7986
+         boards with the WM8960 codecs.
+         Select Y if you have such device.
+         If unsure select "N".
+
 config SND_SOC_MT8173
        tristate "ASoC support for Mediatek MT8173 chip"
        depends on ARCH_MEDIATEK
index 3de38cfc69e5f2a59f181445a30cb2fa3422acc9..3938e7f75c2ec679f33cad62b0183a2a48fa728a 100644 (file)
@@ -2,6 +2,7 @@
 obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
 obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
+obj-$(CONFIG_SND_SOC_MT7986) += mt7986/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
 obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
 obj-$(CONFIG_SND_SOC_MT8186) += mt8186/
diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile
new file mode 100644 (file)
index 0000000..fc4c825
--- /dev/null
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# platform driver
+snd-soc-mt7986-afe-objs := \
+       mt7986-afe-pcm.o \
+       mt7986-dai-etdm.o
+
+obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
+obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
new file mode 100644 (file)
index 0000000..fc3bb31
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt7986-afe-common.h  --  MediaTek 7986 audio driver definitions
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ *          Maso Huang <maso.huang@mediatek.com>
+ */
+
+#ifndef _MT_7986_AFE_COMMON_H_
+#define _MT_7986_AFE_COMMON_H_
+
+#include <sound/soc.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/regmap.h>
+#include "../common/mtk-base-afe.h"
+
+enum {
+       MT7986_MEMIF_DL1,
+       MT7986_MEMIF_VUL12,
+       MT7986_MEMIF_NUM,
+       MT7986_DAI_ETDM = MT7986_MEMIF_NUM,
+       MT7986_DAI_NUM,
+};
+
+enum {
+       MT7986_IRQ_0,
+       MT7986_IRQ_1,
+       MT7986_IRQ_2,
+       MT7986_IRQ_NUM,
+};
+
+struct mt7986_afe_private {
+       struct clk_bulk_data *clks;
+       int num_clks;
+
+       int pm_runtime_bypass_reg_ctl;
+
+       /* dai */
+       void *dai_priv[MT7986_DAI_NUM];
+};
+
+unsigned int mt7986_afe_rate_transform(struct device *dev,
+                                      unsigned int rate);
+
+/* dai register */
+int mt7986_dai_etdm_register(struct mtk_base_afe *afe);
+#endif
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
new file mode 100644 (file)
index 0000000..d497e11
--- /dev/null
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC AFE platform driver for MT7986
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ *          Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
+
+enum {
+       MTK_AFE_RATE_8K = 0,
+       MTK_AFE_RATE_11K = 1,
+       MTK_AFE_RATE_12K = 2,
+       MTK_AFE_RATE_16K = 4,
+       MTK_AFE_RATE_22K = 5,
+       MTK_AFE_RATE_24K = 6,
+       MTK_AFE_RATE_32K = 8,
+       MTK_AFE_RATE_44K = 9,
+       MTK_AFE_RATE_48K = 10,
+       MTK_AFE_RATE_88K = 13,
+       MTK_AFE_RATE_96K = 14,
+       MTK_AFE_RATE_176K = 17,
+       MTK_AFE_RATE_192K = 18,
+};
+
+enum {
+       CLK_INFRA_AUD_BUS_CK = 0,
+       CLK_INFRA_AUD_26M_CK,
+       CLK_INFRA_AUD_L_CK,
+       CLK_INFRA_AUD_AUD_CK,
+       CLK_INFRA_AUD_EG2_CK,
+       CLK_NUM
+};
+
+static const char *aud_clks[CLK_NUM] = {
+       [CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
+       [CLK_INFRA_AUD_26M_CK] = "aud_26m_ck",
+       [CLK_INFRA_AUD_L_CK] = "aud_l_ck",
+       [CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
+       [CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
+};
+
+unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_AFE_RATE_8K;
+       case 11025:
+               return MTK_AFE_RATE_11K;
+       case 12000:
+               return MTK_AFE_RATE_12K;
+       case 16000:
+               return MTK_AFE_RATE_16K;
+       case 22050:
+               return MTK_AFE_RATE_22K;
+       case 24000:
+               return MTK_AFE_RATE_24K;
+       case 32000:
+               return MTK_AFE_RATE_32K;
+       case 44100:
+               return MTK_AFE_RATE_44K;
+       case 48000:
+               return MTK_AFE_RATE_48K;
+       case 88200:
+               return MTK_AFE_RATE_88K;
+       case 96000:
+               return MTK_AFE_RATE_96K;
+       case 176400:
+               return MTK_AFE_RATE_176K;
+       case 192000:
+               return MTK_AFE_RATE_192K;
+       default:
+               dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
+                        __func__, rate, MTK_AFE_RATE_48K);
+               return MTK_AFE_RATE_48K;
+       }
+}
+
+static const struct snd_pcm_hardware mt7986_afe_hardware = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                  SNDRV_PCM_FMTBIT_S24_LE |
+                  SNDRV_PCM_FMTBIT_S32_LE,
+       .period_bytes_min = 256,
+       .period_bytes_max = 4 * 48 * 1024,
+       .periods_min = 2,
+       .periods_max = 256,
+       .buffer_bytes_max = 8 * 48 * 1024,
+       .fifo_size = 0,
+};
+
+static int mt7986_memif_fs(struct snd_pcm_substream *substream,
+                          unsigned int rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+       return mt7986_afe_rate_transform(afe->dev, rate);
+}
+
+static int mt7986_irq_fs(struct snd_pcm_substream *substream,
+                        unsigned int rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
+       struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+
+       return mt7986_afe_rate_transform(afe->dev, rate);
+}
+
+#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                      SNDRV_PCM_RATE_88200 |\
+                      SNDRV_PCM_RATE_96000 |\
+                      SNDRV_PCM_RATE_176400 |\
+                      SNDRV_PCM_RATE_192000)
+
+#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                        SNDRV_PCM_FMTBIT_S24_LE |\
+                        SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = {
+       /* FE DAIs: memory intefaces to CPU */
+       {
+               .name = "DL1",
+               .id = MT7986_MEMIF_DL1,
+               .playback = {
+                       .stream_name = "DL1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+       {
+               .name = "UL1",
+               .id = MT7986_MEMIF_VUL12,
+               .capture = {
+                       .stream_name = "UL1",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_PCM_RATES,
+                       .formats = MTK_PCM_FORMATS,
+               },
+               .ops = &mtk_afe_fe_ops,
+       },
+};
+
+static const struct snd_kcontrol_new o018_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
+};
+
+static const struct snd_kcontrol_new o019_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = {
+       /* DL */
+       SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* UL */
+       SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
+                          o018_mix, ARRAY_SIZE(o018_mix)),
+       SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
+                          o019_mix, ARRAY_SIZE(o019_mix)),
+};
+
+static const struct snd_soc_dapm_route mt7986_memif_routes[] = {
+       {"I032", NULL, "DL1"},
+       {"I033", NULL, "DL1"},
+       {"UL1", NULL, "O018"},
+       {"UL1", NULL, "O019"},
+       {"O018", "I150_Switch", "I150"},
+       {"O019", "I151_Switch", "I151"},
+};
+
+static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = {
+       .name = "mt7986-afe-pcm-dai",
+};
+
+static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = {
+       [MT7986_MEMIF_DL1] = {
+               .name = "DL1",
+               .id = MT7986_MEMIF_DL1,
+               .reg_ofs_base = AFE_DL0_BASE,
+               .reg_ofs_cur = AFE_DL0_CUR,
+               .reg_ofs_end = AFE_DL0_END,
+               .reg_ofs_base_msb = AFE_DL0_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
+               .reg_ofs_end_msb = AFE_DL0_END_MSB,
+               .fs_reg = AFE_DL0_CON0,
+               .fs_shift =  DL0_MODE_SFT,
+               .fs_maskbit =  DL0_MODE_MASK,
+               .mono_reg = AFE_DL0_CON0,
+               .mono_shift = DL0_MONO_SFT,
+               .enable_reg = AFE_DL0_CON0,
+               .enable_shift = DL0_ON_SFT,
+               .hd_reg = AFE_DL0_CON0,
+               .hd_shift = DL0_HD_MODE_SFT,
+               .hd_align_reg = AFE_DL0_CON0,
+               .hd_align_mshift = DL0_HALIGN_SFT,
+               .pbuf_reg = AFE_DL0_CON0,
+               .pbuf_shift = DL0_PBUF_SIZE_SFT,
+               .minlen_reg = AFE_DL0_CON0,
+               .minlen_shift = DL0_MINLEN_SFT,
+       },
+       [MT7986_MEMIF_VUL12] = {
+               .name = "VUL12",
+               .id = MT7986_MEMIF_VUL12,
+               .reg_ofs_base = AFE_VUL0_BASE,
+               .reg_ofs_cur = AFE_VUL0_CUR,
+               .reg_ofs_end = AFE_VUL0_END,
+               .reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
+               .reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
+               .reg_ofs_end_msb = AFE_VUL0_END_MSB,
+               .fs_reg = AFE_VUL0_CON0,
+               .fs_shift = VUL0_MODE_SFT,
+               .fs_maskbit = VUL0_MODE_MASK,
+               .mono_reg = AFE_VUL0_CON0,
+               .mono_shift = VUL0_MONO_SFT,
+               .enable_reg = AFE_VUL0_CON0,
+               .enable_shift = VUL0_ON_SFT,
+               .hd_reg = AFE_VUL0_CON0,
+               .hd_shift = VUL0_HD_MODE_SFT,
+               .hd_align_reg = AFE_VUL0_CON0,
+               .hd_align_mshift = VUL0_HALIGN_SFT,
+       },
+};
+
+static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = {
+       [MT7986_IRQ_0] = {
+               .id = MT7986_IRQ_0,
+               .irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ0_MCU_CFG0,
+               .irq_fs_shift = IRQ_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ0_MCU_CFG0,
+               .irq_en_shift = IRQ_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ0_MCU_CLR_SFT,
+       },
+       [MT7986_IRQ_1] = {
+               .id = MT7986_IRQ_1,
+               .irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ1_MCU_CFG0,
+               .irq_fs_shift = IRQ_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ1_MCU_CFG0,
+               .irq_en_shift = IRQ_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ1_MCU_CLR_SFT,
+       },
+       [MT7986_IRQ_2] = {
+               .id = MT7986_IRQ_2,
+               .irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
+               .irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
+               .irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
+               .irq_fs_reg = AFE_IRQ2_MCU_CFG0,
+               .irq_fs_shift = IRQ_MCU_MODE_SFT,
+               .irq_fs_maskbit = IRQ_MCU_MODE_MASK,
+               .irq_en_reg = AFE_IRQ2_MCU_CFG0,
+               .irq_en_shift = IRQ_MCU_ON_SFT,
+               .irq_clr_reg = AFE_IRQ_MCU_CLR,
+               .irq_clr_shift = IRQ2_MCU_CLR_SFT,
+       },
+};
+
+static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       /*
+        * Those auto-gen regs are read-only, so put it as volatile because
+        * volatile registers cannot be cached, which means that they cannot
+        * be set when power is off
+        */
+
+       switch (reg) {
+       case AFE_DL0_CUR_MSB:
+       case AFE_DL0_CUR:
+       case AFE_DL0_RCH_MON:
+       case AFE_DL0_LCH_MON:
+       case AFE_VUL0_CUR_MSB:
+       case AFE_VUL0_CUR:
+       case AFE_IRQ_MCU_STATUS:
+       case AFE_MEMIF_RD_MON:
+       case AFE_MEMIF_WR_MON:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config mt7986_afe_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .volatile_reg = mt7986_is_volatile_reg,
+       .max_register = AFE_MAX_REGISTER,
+       .num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
+};
+
+static int mt7986_init_clock(struct mtk_base_afe *afe)
+{
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+       int ret, i;
+
+       afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM,
+                               sizeof(*afe_priv->clks), GFP_KERNEL);
+       if (!afe_priv->clks)
+               return -ENOMEM;
+       afe_priv->num_clks = CLK_NUM;
+
+       for (i = 0; i < afe_priv->num_clks; i++)
+               afe_priv->clks[i].id = aud_clks[i];
+
+       ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks);
+       if (ret)
+               return dev_err_probe(afe->dev, ret, "Failed to get clocks\n");
+
+       return 0;
+}
+
+static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev)
+{
+       struct mtk_base_afe *afe = dev;
+       struct mtk_base_afe_irq *irq;
+       u32 mcu_en, status, status_mcu;
+       int i, ret;
+       irqreturn_t irq_ret = IRQ_HANDLED;
+
+       /* get irq that is sent to MCU */
+       regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
+
+       ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
+       /* only care IRQ which is sent to MCU */
+       status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
+
+       if (ret || status_mcu == 0) {
+               dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
+                       __func__, ret, status, mcu_en);
+
+               irq_ret = IRQ_NONE;
+               goto err_irq;
+       }
+
+       for (i = 0; i < MT7986_MEMIF_NUM; i++) {
+               struct mtk_base_afe_memif *memif = &afe->memif[i];
+
+               if (!memif->substream)
+                       continue;
+
+               if (memif->irq_usage < 0)
+                       continue;
+
+               irq = &afe->irqs[memif->irq_usage];
+
+               if (status_mcu & (1 << irq->irq_data->irq_en_shift))
+                       snd_pcm_period_elapsed(memif->substream);
+       }
+
+err_irq:
+       /* clear irq */
+       regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
+
+       return irq_ret;
+}
+
+static int mt7986_afe_runtime_suspend(struct device *dev)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dev);
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+
+       if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+               goto skip_regmap;
+
+       /* disable clk*/
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
+       regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0);
+       regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0);
+
+       /* make sure all irq status are cleared, twice intended */
+       regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
+
+skip_regmap:
+       clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
+
+       return 0;
+}
+
+static int mt7986_afe_runtime_resume(struct device *dev)
+{
+       struct mtk_base_afe *afe = dev_get_drvdata(dev);
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+       if (ret)
+               return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+
+       if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
+               return 0;
+
+       /* enable clk*/
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
+       regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
+                          AUD_APLL2_EN);
+       regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
+                          AUD_26M_EN);
+
+       return 0;
+}
+
+static int mt7986_afe_component_probe(struct snd_soc_component *component)
+{
+       return mtk_afe_add_sub_dai_control(component);
+}
+
+static const struct snd_soc_component_driver mt7986_afe_component = {
+       .name = AFE_PCM_NAME,
+       .probe = mt7986_afe_component_probe,
+       .pointer        = mtk_afe_pcm_pointer,
+       .pcm_construct  = mtk_afe_pcm_new,
+};
+
+static int mt7986_dai_memif_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mt7986_memif_dai_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver);
+
+       dai->dapm_widgets = mt7986_memif_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets);
+       dai->dapm_routes = mt7986_memif_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes);
+
+       return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+       mt7986_dai_etdm_register,
+       mt7986_dai_memif_register,
+};
+
+static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct mtk_base_afe *afe;
+       struct mt7986_afe_private *afe_priv;
+       struct device *dev;
+       int i, irq_id, ret;
+
+       afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+       if (!afe)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, afe);
+
+       afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+                                         GFP_KERNEL);
+       if (!afe->platform_priv)
+               return -ENOMEM;
+
+       afe_priv = afe->platform_priv;
+       afe->dev = &pdev->dev;
+       dev = afe->dev;
+
+       afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(afe->base_addr))
+               return PTR_ERR(afe->base_addr);
+
+       /* initial audio related clock */
+       ret = mt7986_init_clock(afe);
+       if (ret)
+               return dev_err_probe(dev, ret, "Cannot initialize clocks\n");
+
+       ret = devm_pm_runtime_enable(dev);
+       if (ret)
+               return ret;
+
+       /* enable clock for regcache get default value from hw */
+       afe_priv->pm_runtime_bypass_reg_ctl = true;
+       pm_runtime_get_sync(&pdev->dev);
+
+       afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
+                     &mt7986_afe_regmap_config);
+
+       pm_runtime_put_sync(&pdev->dev);
+       if (IS_ERR(afe->regmap))
+               return PTR_ERR(afe->regmap);
+
+       afe_priv->pm_runtime_bypass_reg_ctl = false;
+
+       /* init memif */
+       afe->memif_size = MT7986_MEMIF_NUM;
+       afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+                                 GFP_KERNEL);
+       if (!afe->memif)
+               return -ENOMEM;
+
+       for (i = 0; i < afe->memif_size; i++) {
+               afe->memif[i].data = &memif_data[i];
+               afe->memif[i].irq_usage = -1;
+       }
+
+       mutex_init(&afe->irq_alloc_lock);
+
+       /* irq initialize */
+       afe->irqs_size = MT7986_IRQ_NUM;
+       afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+                                GFP_KERNEL);
+       if (!afe->irqs)
+               return -ENOMEM;
+
+       for (i = 0; i < afe->irqs_size; i++)
+               afe->irqs[i].irq_data = &irq_data[i];
+
+       /* request irq */
+       irq_id = platform_get_irq(pdev, 0);
+       if (irq_id < 0) {
+               ret = irq_id;
+               return dev_err_probe(dev, ret, "No irq found\n");
+       }
+       ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler,
+                              IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to request irq for asys-isr\n");
+
+       /* init sub_dais */
+       INIT_LIST_HEAD(&afe->sub_dais);
+
+       for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+               ret = dai_register_cbs[i](afe);
+               if (ret)
+                       return dev_err_probe(dev, ret, "DAI register failed, i: %d\n", i);
+       }
+
+       /* init dai_driver and component_driver */
+       ret = mtk_afe_combine_sub_dai(afe);
+       if (ret)
+               return dev_err_probe(dev, ret, "mtk_afe_combine_sub_dai fail\n");
+
+       afe->mtk_afe_hardware = &mt7986_afe_hardware;
+       afe->memif_fs = mt7986_memif_fs;
+       afe->irq_fs = mt7986_irq_fs;
+
+       afe->runtime_resume = mt7986_afe_runtime_resume;
+       afe->runtime_suspend = mt7986_afe_runtime_suspend;
+
+       /* register component */
+       ret = devm_snd_soc_register_component(&pdev->dev,
+                                             &mt7986_afe_component,
+                                             NULL, 0);
+       if (ret)
+               return dev_err_probe(dev, ret, "Cannot register AFE component\n");
+
+       ret = devm_snd_soc_register_component(afe->dev,
+                                             &mt7986_afe_pcm_dai_component,
+                                             afe->dai_drivers,
+                                             afe->num_dai_drivers);
+       if (ret)
+               return dev_err_probe(dev, ret, "Cannot register PCM DAI component\n");
+
+       return 0;
+}
+
+static void mt7986_afe_pcm_dev_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               mt7986_afe_runtime_suspend(&pdev->dev);
+}
+
+static const struct of_device_id mt7986_afe_pcm_dt_match[] = {
+       { .compatible = "mediatek,mt7986-afe" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match);
+
+static const struct dev_pm_ops mt7986_afe_pm_ops = {
+       SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend,
+                          mt7986_afe_runtime_resume, NULL)
+};
+
+static struct platform_driver mt7986_afe_pcm_driver = {
+       .driver = {
+                  .name = "mt7986-audio",
+                  .of_match_table = mt7986_afe_pcm_dt_match,
+                  .pm = &mt7986_afe_pm_ops,
+       },
+       .probe = mt7986_afe_pcm_dev_probe,
+       .remove_new = mt7986_afe_pcm_dev_remove,
+};
+module_platform_driver(mt7986_afe_pcm_driver);
+
+MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
new file mode 100644 (file)
index 0000000..e523d33
--- /dev/null
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI eTDM Control
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ *          Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
+
+#define HOPPING_CLK  0
+#define APLL_CLK     1
+#define MTK_DAI_ETDM_FORMAT_I2S   0
+#define MTK_DAI_ETDM_FORMAT_DSPA  4
+#define MTK_DAI_ETDM_FORMAT_DSPB  5
+
+enum {
+       MTK_ETDM_RATE_8K = 0,
+       MTK_ETDM_RATE_12K = 1,
+       MTK_ETDM_RATE_16K = 2,
+       MTK_ETDM_RATE_24K = 3,
+       MTK_ETDM_RATE_32K = 4,
+       MTK_ETDM_RATE_48K = 5,
+       MTK_ETDM_RATE_96K = 7,
+       MTK_ETDM_RATE_192K = 9,
+       MTK_ETDM_RATE_11K = 16,
+       MTK_ETDM_RATE_22K = 17,
+       MTK_ETDM_RATE_44K = 18,
+       MTK_ETDM_RATE_88K = 19,
+       MTK_ETDM_RATE_176K = 20,
+};
+
+struct mtk_dai_etdm_priv {
+       bool bck_inv;
+       bool lrck_inv;
+       bool slave_mode;
+       unsigned int format;
+};
+
+static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate)
+{
+       switch (rate) {
+       case 8000:
+               return MTK_ETDM_RATE_8K;
+       case 11025:
+               return MTK_ETDM_RATE_11K;
+       case 12000:
+               return MTK_ETDM_RATE_12K;
+       case 16000:
+               return MTK_ETDM_RATE_16K;
+       case 22050:
+               return MTK_ETDM_RATE_22K;
+       case 24000:
+               return MTK_ETDM_RATE_24K;
+       case 32000:
+               return MTK_ETDM_RATE_32K;
+       case 44100:
+               return MTK_ETDM_RATE_44K;
+       case 48000:
+               return MTK_ETDM_RATE_48K;
+       case 88200:
+               return MTK_ETDM_RATE_88K;
+       case 96000:
+               return MTK_ETDM_RATE_96K;
+       case 176400:
+               return MTK_ETDM_RATE_176K;
+       case 192000:
+               return MTK_ETDM_RATE_192K;
+       default:
+               dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
+                        __func__, rate, MTK_ETDM_RATE_48K);
+               return MTK_ETDM_RATE_48K;
+       }
+}
+
+static int get_etdm_wlen(unsigned int bitwidth)
+{
+       return bitwidth <= 16 ? 16 : 32;
+}
+
+/* dai component */
+/* interconnection */
+
+static const struct snd_kcontrol_new o124_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new o125_mix[] = {
+       SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
+
+       /* DL */
+       SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* UL */
+       SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)),
+       SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
+       {"I150", NULL, "ETDM Capture"},
+       {"I151", NULL, "ETDM Capture"},
+       {"ETDM Playback", NULL, "O124"},
+       {"ETDM Playback", NULL, "O125"},
+       {"O124", "I032_Switch", "I032"},
+       {"O125", "I033_Switch", "I033"},
+};
+
+/* dai ops */
+static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+       int ret;
+
+       ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+       if (ret)
+               return dev_err_probe(afe->dev, ret, "Failed to enable clocks\n");
+
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
+
+       return 0;
+}
+
+static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
+                          CLK_OUT5_PDN);
+       regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
+                          CLK_IN5_PDN);
+
+       clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
+}
+
+static unsigned int get_etdm_ch_fixup(unsigned int channels)
+{
+       if (channels > 16)
+               return 24;
+       else if (channels > 8)
+               return 16;
+       else if (channels > 4)
+               return 8;
+       else if (channels > 2)
+               return 4;
+       else
+               return 2;
+}
+
+static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
+                              struct snd_pcm_hw_params *params,
+                              struct snd_soc_dai *dai,
+                              int stream)
+{
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
+       unsigned int rate = params_rate(params);
+       unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate);
+       unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate);
+       unsigned int channels = params_channels(params);
+       unsigned int bit_width = params_width(params);
+       unsigned int wlen = get_etdm_wlen(bit_width);
+       unsigned int val = 0;
+       unsigned int mask = 0;
+
+       dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
+                __func__, stream, rate, bit_width);
+
+       /* CON0 */
+       mask |= ETDM_BIT_LEN_MASK;
+       val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1);
+       mask |= ETDM_WRD_LEN_MASK;
+       val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1);
+       mask |= ETDM_FMT_MASK;
+       val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format);
+       mask |= ETDM_CH_NUM_MASK;
+       val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1);
+       mask |= RELATCH_SRC_MASK;
+       val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK);
+
+       switch (stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               /* set ETDM_OUT5_CON0 */
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
+
+               /* set ETDM_OUT5_CON4 */
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+                                  OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+                                  OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
+                                  OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
+
+               /* set ETDM_OUT5_CON5 */
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
+                                  ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
+               break;
+       case SNDRV_PCM_STREAM_CAPTURE:
+               /* set ETDM_IN5_CON0 */
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
+                                  ETDM_SYNC_MASK, ETDM_SYNC);
+
+               /* set ETDM_IN5_CON2 */
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
+                                  IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
+
+               /* set ETDM_IN5_CON3 */
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
+                                  IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
+
+               /* set ETDM_IN5_CON4 */
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
+                                  IN_RELATCH_MASK, IN_RELATCH(afe_rate));
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+       mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
+       mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
+
+       return 0;
+}
+
+static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+
+       dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+                                  ETDM_EN);
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+                                  ETDM_EN);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
+                                  0);
+               regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
+                                  0);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+       struct mt7986_afe_private *afe_priv = afe->platform_priv;
+       struct mtk_dai_etdm_priv *etdm_data;
+       void *priv_data;
+
+       switch (dai->id) {
+       case MT7986_DAI_ETDM:
+               break;
+       default:
+               dev_warn(afe->dev, "%s(), id %d not support\n",
+                        __func__, dai->id);
+               return -EINVAL;
+       }
+
+       priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
+                                GFP_KERNEL);
+       if (!priv_data)
+               return -ENOMEM;
+
+       afe_priv->dai_priv[dai->id] = priv_data;
+       etdm_data = afe_priv->dai_priv[dai->id];
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               etdm_data->bck_inv = false;
+               etdm_data->lrck_inv = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               etdm_data->bck_inv = false;
+               etdm_data->lrck_inv = true;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               etdm_data->bck_inv = true;
+               etdm_data->lrck_inv = false;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               etdm_data->bck_inv = true;
+               etdm_data->lrck_inv = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               etdm_data->slave_mode = true;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               etdm_data->slave_mode = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+       .startup = mtk_dai_etdm_startup,
+       .shutdown = mtk_dai_etdm_shutdown,
+       .hw_params = mtk_dai_etdm_hw_params,
+       .trigger = mtk_dai_etdm_trigger,
+       .set_fmt = mtk_dai_etdm_set_fmt,
+};
+
+/* dai driver */
+#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
+                       SNDRV_PCM_RATE_88200 |\
+                       SNDRV_PCM_RATE_96000 |\
+                       SNDRV_PCM_RATE_176400 |\
+                       SNDRV_PCM_RATE_192000)
+
+#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                         SNDRV_PCM_FMTBIT_S24_LE |\
+                         SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
+       {
+               .name = "ETDM",
+               .id = MT7986_DAI_ETDM,
+               .capture = {
+                       .stream_name = "ETDM Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ETDM_RATES,
+                       .formats = MTK_ETDM_FORMATS,
+               },
+               .playback = {
+                       .stream_name = "ETDM Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = MTK_ETDM_RATES,
+                       .formats = MTK_ETDM_FORMATS,
+               },
+               .ops = &mtk_dai_etdm_ops,
+               .symmetric_rate = 1,
+               .symmetric_sample_bits = 1,
+       },
+};
+
+int mt7986_dai_etdm_register(struct mtk_base_afe *afe)
+{
+       struct mtk_base_afe_dai *dai;
+
+       dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
+       list_add(&dai->list, &afe->sub_dais);
+
+       dai->dai_drivers = mtk_dai_etdm_driver;
+       dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
+
+       dai->dapm_widgets = mtk_dai_etdm_widgets;
+       dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
+       dai->dapm_routes = mtk_dai_etdm_routes;
+       dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
+
+       return 0;
+}
diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h
new file mode 100644 (file)
index 0000000..c2b2007
--- /dev/null
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * mt7986-reg.h  --  MediaTek 7986 audio driver reg definition
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ *          Maso Huang <maso.huang@mediatek.com>
+ */
+
+#ifndef _MT7986_REG_H_
+#define _MT7986_REG_H_
+
+#define AUDIO_TOP_CON2                  0x0008
+#define AUDIO_TOP_CON4                  0x0010
+#define AUDIO_ENGEN_CON0                0x0014
+#define AFE_IRQ_MCU_EN                  0x0100
+#define AFE_IRQ_MCU_STATUS              0x0120
+#define AFE_IRQ_MCU_CLR                 0x0128
+#define AFE_IRQ0_MCU_CFG0               0x0140
+#define AFE_IRQ0_MCU_CFG1               0x0144
+#define AFE_IRQ1_MCU_CFG0               0x0148
+#define AFE_IRQ1_MCU_CFG1               0x014c
+#define AFE_IRQ2_MCU_CFG0               0x0150
+#define AFE_IRQ2_MCU_CFG1               0x0154
+#define ETDM_IN5_CON0                   0x13f0
+#define ETDM_IN5_CON1                   0x13f4
+#define ETDM_IN5_CON2                   0x13f8
+#define ETDM_IN5_CON3                   0x13fc
+#define ETDM_IN5_CON4                   0x1400
+#define ETDM_OUT5_CON0                  0x1570
+#define ETDM_OUT5_CON4                  0x1580
+#define ETDM_OUT5_CON5                  0x1584
+#define ETDM_4_7_COWORK_CON0            0x15e0
+#define ETDM_4_7_COWORK_CON1            0x15e4
+#define AFE_CONN018_1                   0x1b44
+#define AFE_CONN018_4                   0x1b50
+#define AFE_CONN019_1                   0x1b64
+#define AFE_CONN019_4                   0x1b70
+#define AFE_CONN124_1                   0x2884
+#define AFE_CONN124_4                   0x2890
+#define AFE_CONN125_1                   0x28a4
+#define AFE_CONN125_4                   0x28b0
+#define AFE_CONN_RS_0                   0x3920
+#define AFE_CONN_RS_3                   0x392c
+#define AFE_CONN_16BIT_0                0x3960
+#define AFE_CONN_16BIT_3                0x396c
+#define AFE_CONN_24BIT_0                0x3980
+#define AFE_CONN_24BIT_3                0x398c
+#define AFE_MEMIF_CON0                  0x3d98
+#define AFE_MEMIF_RD_MON                0x3da0
+#define AFE_MEMIF_WR_MON                0x3da4
+#define AFE_DL0_BASE_MSB                0x3e40
+#define AFE_DL0_BASE                    0x3e44
+#define AFE_DL0_CUR_MSB                 0x3e48
+#define AFE_DL0_CUR                     0x3e4c
+#define AFE_DL0_END_MSB                 0x3e50
+#define AFE_DL0_END                     0x3e54
+#define AFE_DL0_RCH_MON                 0x3e58
+#define AFE_DL0_LCH_MON                 0x3e5c
+#define AFE_DL0_CON0                    0x3e60
+#define AFE_VUL0_BASE_MSB               0x4220
+#define AFE_VUL0_BASE                   0x4224
+#define AFE_VUL0_CUR_MSB                0x4228
+#define AFE_VUL0_CUR                    0x422c
+#define AFE_VUL0_END_MSB                0x4230
+#define AFE_VUL0_END                    0x4234
+#define AFE_VUL0_CON0                   0x4238
+
+#define AFE_MAX_REGISTER AFE_VUL0_CON0
+#define AFE_IRQ_STATUS_BITS             0x7
+#define AFE_IRQ_CNT_SHIFT               0
+#define AFE_IRQ_CNT_MASK               0xffffff
+
+/* AUDIO_TOP_CON2 */
+#define CLK_OUT5_PDN                    BIT(14)
+#define CLK_OUT5_PDN_MASK               BIT(14)
+#define CLK_IN5_PDN                     BIT(7)
+#define CLK_IN5_PDN_MASK                BIT(7)
+
+/* AUDIO_TOP_CON4 */
+#define PDN_APLL_TUNER2                 BIT(12)
+#define PDN_APLL_TUNER2_MASK            BIT(12)
+
+/* AUDIO_ENGEN_CON0 */
+#define AUD_APLL2_EN                    BIT(3)
+#define AUD_APLL2_EN_MASK               BIT(3)
+#define AUD_26M_EN                      BIT(0)
+#define AUD_26M_EN_MASK                 BIT(0)
+
+/* AFE_DL0_CON0 */
+#define DL0_ON_SFT                      28
+#define DL0_ON_MASK                     0x1
+#define DL0_ON_MASK_SFT                 BIT(28)
+#define DL0_MINLEN_SFT                  20
+#define DL0_MINLEN_MASK                 0xf
+#define DL0_MINLEN_MASK_SFT             (0xf << 20)
+#define DL0_MODE_SFT                    8
+#define DL0_MODE_MASK                   0x1f
+#define DL0_MODE_MASK_SFT               (0x1f << 8)
+#define DL0_PBUF_SIZE_SFT               5
+#define DL0_PBUF_SIZE_MASK              0x3
+#define DL0_PBUF_SIZE_MASK_SFT          (0x3 << 5)
+#define DL0_MONO_SFT                    4
+#define DL0_MONO_MASK                   0x1
+#define DL0_MONO_MASK_SFT               BIT(4)
+#define DL0_HALIGN_SFT                  2
+#define DL0_HALIGN_MASK                 0x1
+#define DL0_HALIGN_MASK_SFT             BIT(2)
+#define DL0_HD_MODE_SFT                 0
+#define DL0_HD_MODE_MASK                0x3
+#define DL0_HD_MODE_MASK_SFT            (0x3 << 0)
+
+/* AFE_VUL0_CON0 */
+#define VUL0_ON_SFT                     28
+#define VUL0_ON_MASK                    0x1
+#define VUL0_ON_MASK_SFT                BIT(28)
+#define VUL0_MODE_SFT                   8
+#define VUL0_MODE_MASK                  0x1f
+#define VUL0_MODE_MASK_SFT              (0x1f << 8)
+#define VUL0_MONO_SFT                   4
+#define VUL0_MONO_MASK                  0x1
+#define VUL0_MONO_MASK_SFT              BIT(4)
+#define VUL0_HALIGN_SFT                 2
+#define VUL0_HALIGN_MASK                0x1
+#define VUL0_HALIGN_MASK_SFT            BIT(2)
+#define VUL0_HD_MODE_SFT                0
+#define VUL0_HD_MODE_MASK               0x3
+#define VUL0_HD_MODE_MASK_SFT           (0x3 << 0)
+
+/* AFE_IRQ_MCU_CON */
+#define IRQ_MCU_MODE_SFT                4
+#define IRQ_MCU_MODE_MASK               0x1f
+#define IRQ_MCU_MODE_MASK_SFT           (0x1f << 4)
+#define IRQ_MCU_ON_SFT                  0
+#define IRQ_MCU_ON_MASK                 0x1
+#define IRQ_MCU_ON_MASK_SFT             BIT(0)
+#define IRQ0_MCU_CLR_SFT                0
+#define IRQ0_MCU_CLR_MASK               0x1
+#define IRQ0_MCU_CLR_MASK_SFT           BIT(0)
+#define IRQ1_MCU_CLR_SFT                1
+#define IRQ1_MCU_CLR_MASK               0x1
+#define IRQ1_MCU_CLR_MASK_SFT           BIT(1)
+#define IRQ2_MCU_CLR_SFT                2
+#define IRQ2_MCU_CLR_MASK               0x1
+#define IRQ2_MCU_CLR_MASK_SFT           BIT(2)
+
+/* ETDM_IN5_CON2 */
+#define IN_CLK_SRC(x)                   ((x) << 10)
+#define IN_CLK_SRC_SFT                  10
+#define IN_CLK_SRC_MASK                 GENMASK(12, 10)
+
+/* ETDM_IN5_CON3 */
+#define IN_SEL_FS(x)                    ((x) << 26)
+#define IN_SEL_FS_SFT                   26
+#define IN_SEL_FS_MASK                  GENMASK(30, 26)
+
+/* ETDM_IN5_CON4 */
+#define IN_RELATCH(x)                   ((x) << 20)
+#define IN_RELATCH_SFT                  20
+#define IN_RELATCH_MASK                 GENMASK(24, 20)
+#define IN_CLK_INV                      BIT(18)
+#define IN_CLK_INV_MASK                 BIT(18)
+
+/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
+#define RELATCH_SRC_MASK                GENMASK(30, 28)
+#define ETDM_CH_NUM_MASK                GENMASK(27, 23)
+#define ETDM_WRD_LEN_MASK               GENMASK(20, 16)
+#define ETDM_BIT_LEN_MASK               GENMASK(15, 11)
+#define ETDM_FMT_MASK                   GENMASK(8, 6)
+#define ETDM_SYNC                       BIT(1)
+#define ETDM_SYNC_MASK                  BIT(1)
+#define ETDM_EN                         BIT(0)
+#define ETDM_EN_MASK                    BIT(0)
+
+/* ETDM_OUT5_CON4 */
+#define OUT_RELATCH(x)                  ((x) << 24)
+#define OUT_RELATCH_SFT                 24
+#define OUT_RELATCH_MASK                GENMASK(28, 24)
+#define OUT_CLK_SRC(x)                  ((x) << 6)
+#define OUT_CLK_SRC_SFT                 6
+#define OUT_CLK_SRC_MASK                GENMASK(8, 6)
+#define OUT_SEL_FS(x)                   (x)
+#define OUT_SEL_FS_SFT                  0
+#define OUT_SEL_FS_MASK                 GENMASK(4, 0)
+
+/* ETDM_OUT5_CON5 */
+#define ETDM_CLK_DIV                    BIT(12)
+#define ETDM_CLK_DIV_MASK               BIT(12)
+#define OUT_CLK_INV                     BIT(9)
+#define OUT_CLK_INV_MASK                BIT(9)
+
+/* ETDM_4_7_COWORK_CON0 */
+#define OUT_SEL(x)                      ((x) << 12)
+#define OUT_SEL_SFT                     12
+#define OUT_SEL_MASK                    GENMASK(15, 12)
+#endif
diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
new file mode 100644 (file)
index 0000000..364d13b
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mt7986-wm8960.c  --  MT7986-WM8960 ALSA SoC machine driver
+ *
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ *          Maso Huang <maso.huang@mediatek.com>
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include "mt7986-afe-common.h"
+
+struct mt7986_wm8960_priv {
+       struct device_node *platform_node;
+       struct device_node *codec_node;
+};
+
+static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+};
+
+static const struct snd_kcontrol_new mt7986_wm8960_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("AMIC"),
+};
+
+SND_SOC_DAILINK_DEFS(playback,
+       DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
+       DAILINK_COMP_ARRAY(COMP_DUMMY()),
+       DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(capture,
+       DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
+       DAILINK_COMP_ARRAY(COMP_DUMMY()),
+       DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+SND_SOC_DAILINK_DEFS(codec,
+       DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
+       DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
+       DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
+       /* FE */
+       {
+               .name = "wm8960-playback",
+               .stream_name = "wm8960-playback",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+                           SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               SND_SOC_DAILINK_REG(playback),
+       },
+       {
+               .name = "wm8960-capture",
+               .stream_name = "wm8960-capture",
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+                           SND_SOC_DPCM_TRIGGER_POST},
+               .dynamic = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(capture),
+       },
+       /* BE */
+       {
+               .name = "wm8960-codec",
+               .no_pcm = 1,
+               .dai_fmt = SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS |
+                       SND_SOC_DAIFMT_GATED,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               SND_SOC_DAILINK_REG(codec),
+       },
+};
+
+static struct snd_soc_card mt7986_wm8960_card = {
+       .name = "mt7986-wm8960",
+       .owner = THIS_MODULE,
+       .dai_link = mt7986_wm8960_dai_links,
+       .num_links = ARRAY_SIZE(mt7986_wm8960_dai_links),
+       .controls = mt7986_wm8960_controls,
+       .num_controls = ARRAY_SIZE(mt7986_wm8960_controls),
+       .dapm_widgets = mt7986_wm8960_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets),
+};
+
+static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &mt7986_wm8960_card;
+       struct snd_soc_dai_link *dai_link;
+       struct device_node *platform, *codec;
+       struct mt7986_wm8960_priv *priv;
+       int ret, i;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform = of_get_child_by_name(pdev->dev.of_node, "platform");
+
+       if (platform) {
+               priv->platform_node = of_parse_phandle(platform, "sound-dai", 0);
+               of_node_put(platform);
+
+               if (!priv->platform_node) {
+                       dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
+                       return -EINVAL;
+               }
+       } else {
+               dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for_each_card_prelinks(card, i, dai_link) {
+               if (dai_link->platforms->name)
+                       continue;
+               dai_link->platforms->of_node = priv->platform_node;
+       }
+
+       card->dev = &pdev->dev;
+
+       codec = of_get_child_by_name(pdev->dev.of_node, "codec");
+
+       if (codec) {
+               priv->codec_node = of_parse_phandle(codec, "sound-dai", 0);
+               of_node_put(codec);
+
+               if (!priv->codec_node) {
+                       of_node_put(priv->platform_node);
+                       dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
+                       return -EINVAL;
+               }
+       } else {
+               of_node_put(priv->platform_node);
+               dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
+               return -EINVAL;
+       }
+
+       for_each_card_prelinks(card, i, dai_link) {
+               if (dai_link->codecs->name)
+                       continue;
+               dai_link->codecs->of_node = priv->codec_node;
+       }
+
+       ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
+               goto err_of_node_put;
+       }
+
+       ret = devm_snd_soc_register_card(&pdev->dev, card);
+       if (ret) {
+               dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
+               goto err_of_node_put;
+       }
+
+err_of_node_put:
+       of_node_put(priv->codec_node);
+       of_node_put(priv->platform_node);
+       return ret;
+}
+
+static void mt7986_wm8960_machine_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct mt7986_wm8960_priv *priv = snd_soc_card_get_drvdata(card);
+
+       of_node_put(priv->codec_node);
+       of_node_put(priv->platform_node);
+}
+
+static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
+       {.compatible = "mediatek,mt7986-wm8960-sound"},
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match);
+
+static struct platform_driver mt7986_wm8960_machine = {
+       .driver = {
+               .name = "mt7986-wm8960",
+               .of_match_table = mt7986_wm8960_machine_dt_match,
+       },
+       .probe = mt7986_wm8960_machine_probe,
+       .remove_new = mt7986_wm8960_machine_remove,
+};
+
+module_platform_driver(mt7986_wm8960_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver");
+MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mt7986 wm8960 soc card");
index c2b0619b615891975b9b802274b1f24918886975..bfb2094758ff294cfd80d0b60f1dfa0d1424836a 100644 (file)
@@ -70,7 +70,7 @@ static int mt8173_max98090_init(struct snd_soc_pcm_runtime *runtime)
        struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component;
 
        /* enable jack detection */
-       ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADPHONE,
+       ret = snd_soc_card_jack_new_pins(card, "Headphone", SND_JACK_HEADSET,
                                         &mt8173_max98090_jack,
                                         mt8173_max98090_jack_pins,
                                         ARRAY_SIZE(mt8173_max98090_jack_pins));
index f803f121659de30850e4fa644a0924015863f301..e502cd1670ba128b047f6b7303edd30880af2468 100644 (file)
@@ -40,6 +40,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5514_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
 };
 
+static struct snd_soc_jack_pin mt8173_rt5650_rt5514_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int mt8173_rt5650_rt5514_hw_params(struct snd_pcm_substream *substream,
                                          struct snd_pcm_hw_params *params)
 {
@@ -82,11 +93,13 @@ static int mt8173_rt5650_rt5514_init(struct snd_soc_pcm_runtime *runtime)
                                RT5645_CLK_SEL_I2S1_ASRC);
 
        /* enable jack detection */
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &mt8173_rt5650_rt5514_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &mt8173_rt5650_rt5514_jack,
+                                        mt8173_rt5650_rt5514_jack_pins,
+                                        ARRAY_SIZE(mt8173_rt5650_rt5514_jack_pins));
        if (ret) {
                dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
                return ret;
index 8794720cea3a0a1ec4bcbaa094c05ee1d9cb4f5f..ffb094284bfb1b372111c820661a180093fe0949 100644 (file)
@@ -44,6 +44,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
 };
 
+static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
                                          struct snd_pcm_hw_params *params)
 {
@@ -95,11 +106,13 @@ static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
                                RT5677_CLK_SEL_I2S2_ASRC);
 
        /* enable jack detection */
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &mt8173_rt5650_rt5676_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &mt8173_rt5650_rt5676_jack,
+                                        mt8173_rt5650_rt5676_jack_pins,
+                                        ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins));
        if (ret) {
                dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
                return ret;
index 3ece4b5eaca29c914782e4de3e6155f0684c167e..18cf84bb25c76d9a16bc363ba62072c357cd0c4d 100644 (file)
@@ -54,6 +54,17 @@ static const struct snd_kcontrol_new mt8173_rt5650_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
 };
 
+static struct snd_soc_jack_pin mt8173_rt5650_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params)
 {
@@ -128,11 +139,13 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime)
        }
 
        /* enable jack detection */
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &mt8173_rt5650_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &mt8173_rt5650_jack,
+                                        mt8173_rt5650_jack_pins,
+                                        ARRAY_SIZE(mt8173_rt5650_jack_pins));
        if (ret) {
                dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
                return ret;
index 87bb04846991f8a4758fb450f97016f235b6c5c2..701fbcc0f2c9c3910ce2b30d147cd3e0d9c1e5df 100644 (file)
@@ -29,6 +29,21 @@ struct mt8183_da7219_max98357_priv {
        struct snd_soc_jack headset_jack, hdmi_jack;
 };
 
+static struct snd_soc_jack_pin mt8183_da7219_max98357_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin    = "Line Out",
+               .mask   = SND_JACK_LINEOUT,
+       },
+};
+
 static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
                                       struct snd_pcm_hw_params *params)
 {
@@ -572,13 +587,15 @@ mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
                        snd_soc_card_get_drvdata(component->card);
 
        /* Enable Headset and 4 Buttons Jack detection */
-       ret = snd_soc_card_jack_new(component->card,
-                                   "Headset Jack",
-                                   SND_JACK_HEADSET |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                                   SND_JACK_LINEOUT,
-                                   &priv->headset_jack);
+       ret = snd_soc_card_jack_new_pins(component->card,
+                                        "Headset Jack",
+                                        SND_JACK_HEADSET |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                        SND_JACK_LINEOUT,
+                                        &priv->headset_jack,
+                                        mt8183_da7219_max98357_jack_pins,
+                                        ARRAY_SIZE(mt8183_da7219_max98357_jack_pins));
        if (ret)
                return ret;
 
@@ -609,12 +626,18 @@ static struct snd_soc_codec_conf mt6358_codec_conf[] = {
 };
 
 static const struct snd_kcontrol_new mt8183_da7219_max98357_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Speakers"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static const
 struct snd_soc_dapm_widget mt8183_da7219_max98357_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_SPK("Line Out", NULL),
        SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
                             "aud_tdm_out_on", "aud_tdm_out_off"),
 };
@@ -657,14 +680,20 @@ static struct snd_soc_codec_conf mt8183_da7219_rt1015_codec_conf[] = {
 };
 
 static const struct snd_kcontrol_new mt8183_da7219_rt1015_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Left Spk"),
        SOC_DAPM_PIN_SWITCH("Right Spk"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static const
 struct snd_soc_dapm_widget mt8183_da7219_rt1015_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_SPK("Left Spk", NULL),
        SND_SOC_DAPM_SPK("Right Spk", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_PINCTRL("TDM_OUT_PINCTRL",
                             "aud_tdm_out_on", "aud_tdm_out_off"),
 };
index ce9aedde7e1eff1e8f8d935d881e87a427bbc59f..850f4d949d9785455da663853daab7de0e2a8580 100644 (file)
@@ -592,11 +592,38 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
        },
 };
 
+static const
+struct snd_kcontrol_new mt8183_mt6358_ts3a227_max98357_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
+static const
+struct snd_soc_dapm_widget mt8183_mt6358_ts3a227_max98357_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static struct snd_soc_jack_pin mt8183_mt6358_ts3a227_max98357_jack_pins[] = {
+       {
+               .pin    = "Headphone",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Headset Mic",
+               .mask   = SND_JACK_MICROPHONE,
+       },
+};
+
 static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = {
        .name = "mt8183_mt6358_ts3a227_max98357",
        .owner = THIS_MODULE,
        .dai_link = mt8183_mt6358_ts3a227_dai_links,
        .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+       .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+       .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+       .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
 };
 
 static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
@@ -604,6 +631,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_max98357b_card = {
        .owner = THIS_MODULE,
        .dai_link = mt8183_mt6358_ts3a227_dai_links,
        .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+       .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+       .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+       .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
 };
 
 static struct snd_soc_codec_conf mt8183_mt6358_ts3a227_rt1015_amp_conf[] = {
@@ -624,6 +655,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = {
        .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
        .codec_conf = mt8183_mt6358_ts3a227_rt1015_amp_conf,
        .num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf),
+       .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+       .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+       .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
 };
 
 static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = {
@@ -631,6 +666,10 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = {
        .owner = THIS_MODULE,
        .dai_link = mt8183_mt6358_ts3a227_dai_links,
        .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links),
+       .controls = mt8183_mt6358_ts3a227_max98357_snd_controls,
+       .num_controls = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_snd_controls),
+       .dapm_widgets = mt8183_mt6358_ts3a227_max98357_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dapm_widgets),
 };
 
 static int
@@ -641,12 +680,14 @@ mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component)
                        snd_soc_card_get_drvdata(component->card);
 
        /* Enable Headset and 4 Buttons Jack detection */
-       ret = snd_soc_card_jack_new(component->card,
-                                   "Headset Jack",
-                                   SND_JACK_HEADSET |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &priv->headset_jack);
+       ret = snd_soc_card_jack_new_pins(component->card,
+                                        "Headset Jack",
+                                        SND_JACK_HEADSET |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &priv->headset_jack,
+                                        mt8183_mt6358_ts3a227_max98357_jack_pins,
+                                        ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_jack_pins));
        if (ret)
                return ret;
 
index 539e3a023bc4e204bf63a284bf00f9ba22dce4bc..70ec101890d368d316f270c1a2e9892164f734b4 100644 (file)
@@ -13,8 +13,6 @@
 #include "mt8186-afe-clk.h"
 #include "mt8186-audsys-clk.h"
 
-static DEFINE_MUTEX(mutex_request_dram);
-
 static const char *aud_clks[CLK_NUM] = {
        [CLK_AFE] = "aud_afe_clk",
        [CLK_DAC] = "aud_dac_clk",
index a868a04ed4e7af15a0f7de48ae434ad36bb3ef25..b86159f70a33a2b18b4c4867584c617d579d8963 100644 (file)
@@ -2815,7 +2815,6 @@ 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;
@@ -2836,8 +2835,7 @@ static int mt8186_afe_pcm_dev_probe(struct platform_device *pdev)
        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);
+       afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(afe->base_addr))
                return PTR_ERR(afe->base_addr);
 
index 0432f9d89020809a5639343492d7d737735d926e..aa8e00bba19b27a4fb84afb4eeba695f431a42d7 100644 (file)
@@ -46,6 +46,10 @@ static struct snd_soc_jack_pin mt8186_jack_pins[] = {
                .pin = "Headset Mic",
                .mask = SND_JACK_MICROPHONE,
        },
+       {
+               .pin = "Line Out",
+               .mask = SND_JACK_LINEOUT,
+       },
 };
 
 static struct snd_soc_codec_conf mt8186_mt6366_da7219_max98357_codec_conf[] = {
@@ -964,6 +968,7 @@ mt8186_mt6366_da7219_max98357_widgets[] = {
        SND_SOC_DAPM_SPK("Speakers", NULL),
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_OUTPUT("HDMI1"),
        SND_SOC_DAPM_MIXER(SOF_DMA_DL1, SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -996,6 +1001,7 @@ mt8186_mt6366_da7219_max98357_controls[] = {
        SOC_DAPM_PIN_SWITCH("Speakers"),
        SOC_DAPM_PIN_SWITCH("Headphones"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
        SOC_DAPM_PIN_SWITCH("HDMI1"),
 };
 
index 6a24b339444b35652844aa8e1bbd96b847268225..5e14655c5617ed066f0c92d13592e9e15dabfa50 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
 #include <linux/pm_runtime.h>
 #include <linux/soc/mediatek/infracfg.h>
 #include <linux/reset.h>
@@ -3193,11 +3194,15 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
 {
        struct mtk_base_afe *afe;
        struct mt8188_afe_private *afe_priv;
-       struct device *dev;
+       struct device *dev = &pdev->dev;
        struct reset_control *rstc;
        struct regmap *infra_ao;
        int i, irq_id, ret;
 
+       ret = of_reserved_mem_device_init(dev);
+       if (ret)
+               dev_dbg(dev, "failed to assign memory region: %d\n", ret);
+
        ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
        if (ret)
                return ret;
@@ -3213,7 +3218,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
 
        afe_priv = afe->platform_priv;
        afe->dev = &pdev->dev;
-       dev = afe->dev;
 
        afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(afe->base_addr))
index ac69c23e0da1c02fcd23712b35ea08bb3613ff99..7c9e08e6a4f56def2436aeb5cd9d0e7692bc74c1 100644 (file)
@@ -723,6 +723,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
                },
                .dynamic = 1,
                .dpcm_playback = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .dpcm_merged_format = 1,
                SND_SOC_DAILINK_REG(playback2),
        },
        [DAI_LINK_DL3_FE] = {
@@ -734,6 +737,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
                },
                .dynamic = 1,
                .dpcm_playback = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .dpcm_merged_format = 1,
                SND_SOC_DAILINK_REG(playback3),
        },
        [DAI_LINK_DL6_FE] = {
@@ -745,6 +751,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
                },
                .dynamic = 1,
                .dpcm_playback = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .dpcm_merged_format = 1,
                SND_SOC_DAILINK_REG(playback6),
        },
        [DAI_LINK_DL7_FE] = {
@@ -833,6 +842,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
                },
                .dynamic = 1,
                .dpcm_capture = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .dpcm_merged_format = 1,
                SND_SOC_DAILINK_REG(capture4),
        },
        [DAI_LINK_UL5_FE] = {
@@ -844,6 +856,9 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
                },
                .dynamic = 1,
                .dpcm_capture = 1,
+               .dpcm_merged_chan = 1,
+               .dpcm_merged_rate = 1,
+               .dpcm_merged_format = 1,
                SND_SOC_DAILINK_REG(capture5),
        },
        [DAI_LINK_UL6_FE] = {
index eedb9165f91115294cc2b92d46c5b827d858adcf..fd4f9f8f032deabda2c852a20cd9f1ec92e8d67f 100644 (file)
@@ -2456,25 +2456,6 @@ static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai,
        return mtk_dai_etdm_cal_mclk(afe, freq, dai->id);
 }
 
-static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
-       .startup = mtk_dai_etdm_startup,
-       .shutdown = mtk_dai_etdm_shutdown,
-       .hw_params = mtk_dai_etdm_hw_params,
-       .trigger = mtk_dai_etdm_trigger,
-       .set_sysclk = mtk_dai_etdm_set_sysclk,
-       .set_fmt = mtk_dai_etdm_set_fmt,
-       .set_tdm_slot = mtk_dai_etdm_set_tdm_slot,
-};
-
-static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
-       .startup        = mtk_dai_hdmitx_dptx_startup,
-       .shutdown       = mtk_dai_hdmitx_dptx_shutdown,
-       .hw_params      = mtk_dai_hdmitx_dptx_hw_params,
-       .trigger        = mtk_dai_hdmitx_dptx_trigger,
-       .set_sysclk     = mtk_dai_hdmitx_dptx_set_sysclk,
-       .set_fmt        = mtk_dai_etdm_set_fmt,
-};
-
 /* dai driver */
 #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_384000)
 
@@ -2505,6 +2486,36 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {
+       .startup        = mtk_dai_hdmitx_dptx_startup,
+       .shutdown       = mtk_dai_hdmitx_dptx_shutdown,
+       .hw_params      = mtk_dai_hdmitx_dptx_hw_params,
+       .trigger        = mtk_dai_hdmitx_dptx_trigger,
+       .set_sysclk     = mtk_dai_hdmitx_dptx_set_sysclk,
+       .set_fmt        = mtk_dai_etdm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops2 = {
+       .probe          = mtk_dai_etdm_probe,
+       .startup        = mtk_dai_hdmitx_dptx_startup,
+       .shutdown       = mtk_dai_hdmitx_dptx_shutdown,
+       .hw_params      = mtk_dai_hdmitx_dptx_hw_params,
+       .trigger        = mtk_dai_hdmitx_dptx_trigger,
+       .set_sysclk     = mtk_dai_hdmitx_dptx_set_sysclk,
+       .set_fmt        = mtk_dai_etdm_set_fmt,
+};
+
+static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
+       .probe          = mtk_dai_etdm_probe,
+       .startup        = mtk_dai_etdm_startup,
+       .shutdown       = mtk_dai_etdm_shutdown,
+       .hw_params      = mtk_dai_etdm_hw_params,
+       .trigger        = mtk_dai_etdm_trigger,
+       .set_sysclk     = mtk_dai_etdm_set_sysclk,
+       .set_fmt        = mtk_dai_etdm_set_fmt,
+       .set_tdm_slot   = mtk_dai_etdm_set_tdm_slot,
+};
+
 static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
        {
                .name = "DPTX",
@@ -2529,7 +2540,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
                        .formats = MTK_ETDM_FORMATS,
                },
                .ops = &mtk_dai_etdm_ops,
-               .probe = mtk_dai_etdm_probe,
        },
        {
                .name = "ETDM2_IN",
@@ -2542,7 +2552,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
                        .formats = MTK_ETDM_FORMATS,
                },
                .ops = &mtk_dai_etdm_ops,
-               .probe = mtk_dai_etdm_probe,
        },
        {
                .name = "ETDM1_OUT",
@@ -2555,7 +2564,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
                        .formats = MTK_ETDM_FORMATS,
                },
                .ops = &mtk_dai_etdm_ops,
-               .probe = mtk_dai_etdm_probe,
        },
        {
                .name = "ETDM2_OUT",
@@ -2568,7 +2576,6 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
                        .formats = MTK_ETDM_FORMATS,
                },
                .ops = &mtk_dai_etdm_ops,
-               .probe = mtk_dai_etdm_probe,
        },
        {
                .name = "ETDM3_OUT",
@@ -2580,8 +2587,7 @@ static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
                        .rates = MTK_ETDM_RATES,
                        .formats = MTK_ETDM_FORMATS,
                },
-               .ops = &mtk_dai_hdmitx_dptx_ops,
-               .probe = mtk_dai_etdm_probe,
+               .ops = &mtk_dai_hdmitx_dptx_ops2,
        },
 };
 
index d0f0ada5f4bceaed57fc2c3ea86751ec3a039470..7b04b97f7b41c823d7c10252dc36482799edbd72 100644 (file)
@@ -103,6 +103,8 @@ static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = {
+       .probe          = meson_codec_glue_input_dai_probe,
+       .remove         = meson_codec_glue_input_dai_remove,
        .hw_params      = aiu_acodec_ctrl_input_hw_params,
        .set_fmt        = meson_codec_glue_input_set_fmt,
 };
@@ -130,8 +132,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = {
        .name = "ACODEC CTRL " xname,                           \
        .playback = AIU_ACODEC_STREAM(xname, "Playback", 8),    \
        .ops = &aiu_acodec_ctrl_input_ops,                      \
-       .probe = meson_codec_glue_input_dai_probe,              \
-       .remove = meson_codec_glue_input_dai_remove,            \
 }
 
 #define AIU_ACODEC_OUTPUT(xname) {                             \
index 84c10956c24143c172469b25f8c5ae10dc452fe6..ee0ef6301010c932532b077d57237e62bc9b83b6 100644 (file)
@@ -75,6 +75,8 @@ static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = {
 };
 
 static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = {
+       .probe          = meson_codec_glue_input_dai_probe,
+       .remove         = meson_codec_glue_input_dai_remove,
        .hw_params      = meson_codec_glue_input_hw_params,
        .set_fmt        = meson_codec_glue_input_set_fmt,
 };
@@ -102,8 +104,6 @@ static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = {
        .name = "CODEC CTRL " xname,                            \
        .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"),   \
        .ops = &aiu_codec_ctrl_input_ops,                       \
-       .probe = meson_codec_glue_input_dai_probe,              \
-       .remove = meson_codec_glue_input_dai_remove,            \
 }
 
 #define AIU_CODEC_CTRL_OUTPUT(xname) {                         \
index 59e00a74b5f847535e8a1505ee82ba057761f6f5..7d833500c799306e80b6d717a5b3653aeb23ebac 100644 (file)
@@ -140,6 +140,9 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
 }
 
 const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = {
+       .pcm_new        = aiu_fifo_pcm_new,
+       .probe          = aiu_fifo_i2s_dai_probe,
+       .remove         = aiu_fifo_dai_remove,
        .trigger        = aiu_fifo_i2s_trigger,
        .prepare        = aiu_fifo_i2s_prepare,
        .hw_params      = aiu_fifo_i2s_hw_params,
index ddbd2fc4018587fc0463c69d6bcf1f71cbcc0bd3..fa91f3c53fa4628a25a80194fe418cc50b7a2500 100644 (file)
@@ -155,6 +155,9 @@ static int fifo_spdif_hw_params(struct snd_pcm_substream *substream,
 }
 
 const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
+       .pcm_new        = aiu_fifo_pcm_new,
+       .probe          = aiu_fifo_spdif_dai_probe,
+       .remove         = aiu_fifo_dai_remove,
        .trigger        = fifo_spdif_trigger,
        .prepare        = fifo_spdif_prepare,
        .hw_params      = fifo_spdif_hw_params,
index da351a60df0c40d406cf093012ce3469a42d16a3..7109b81cc3d0a76e5df30b5f3f39627dbac4d36b 100644 (file)
@@ -121,9 +121,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
                        .formats        = AIU_FORMATS,
                },
                .ops            = &aiu_fifo_i2s_dai_ops,
-               .pcm_new        = aiu_fifo_pcm_new,
-               .probe          = aiu_fifo_i2s_dai_probe,
-               .remove         = aiu_fifo_dai_remove,
        },
        [CPU_SPDIF_FIFO] = {
                .name = "SPDIF FIFO",
@@ -137,9 +134,6 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
                        .formats        = AIU_FORMATS,
                },
                .ops            = &aiu_fifo_spdif_dai_ops,
-               .pcm_new        = aiu_fifo_pcm_new,
-               .probe          = aiu_fifo_spdif_dai_probe,
-               .remove         = aiu_fifo_dai_remove,
        },
        [CPU_I2S_ENCODER] = {
                .name = "I2S Encoder",
index 61f9d417fd608a5a93b25e6b6879aab8a70bc446..8c166a5f338ced6fdee51bb02d2051ead1700a8e 100644 (file)
@@ -100,6 +100,7 @@ static const struct snd_soc_dai_ops axg_frddr_ops = {
        .hw_params      = axg_frddr_dai_hw_params,
        .startup        = axg_frddr_dai_startup,
        .shutdown       = axg_frddr_dai_shutdown,
+       .pcm_new        = axg_frddr_pcm_new,
 };
 
 static struct snd_soc_dai_driver axg_frddr_dai_drv = {
@@ -112,7 +113,6 @@ static struct snd_soc_dai_driver axg_frddr_dai_drv = {
                .formats        = AXG_FIFO_FORMATS,
        },
        .ops            = &axg_frddr_ops,
-       .pcm_new        = axg_frddr_pcm_new,
 };
 
 static const char * const axg_frddr_sel_texts[] = {
@@ -175,6 +175,7 @@ static const struct snd_soc_dai_ops g12a_frddr_ops = {
        .hw_params      = axg_frddr_dai_hw_params,
        .startup        = axg_frddr_dai_startup,
        .shutdown       = axg_frddr_dai_shutdown,
+       .pcm_new        = axg_frddr_pcm_new,
 };
 
 static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
@@ -187,7 +188,6 @@ static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
                .formats        = AXG_FIFO_FORMATS,
        },
        .ops            = &g12a_frddr_ops,
-       .pcm_new        = axg_frddr_pcm_new,
 };
 
 static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
index ad43cb2a1e3fd64ba22f9b203f46f80be1e3b50b..d59050914d3cc911e92653b4b6653c954e11c0fe 100644 (file)
@@ -294,13 +294,6 @@ static void axg_pdm_shutdown(struct snd_pcm_substream *substream,
        clk_disable_unprepare(priv->dclk);
 }
 
-static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
-       .trigger        = axg_pdm_trigger,
-       .hw_params      = axg_pdm_hw_params,
-       .startup        = axg_pdm_startup,
-       .shutdown       = axg_pdm_shutdown,
-};
-
 static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv)
 {
        const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic;
@@ -440,6 +433,15 @@ static int axg_pdm_dai_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
+       .probe          = axg_pdm_dai_probe,
+       .remove         = axg_pdm_dai_remove,
+       .trigger        = axg_pdm_trigger,
+       .hw_params      = axg_pdm_hw_params,
+       .startup        = axg_pdm_startup,
+       .shutdown       = axg_pdm_shutdown,
+};
+
 static struct snd_soc_dai_driver axg_pdm_dai_drv = {
        .name = "PDM",
        .capture = {
@@ -453,8 +455,6 @@ static struct snd_soc_dai_driver axg_pdm_dai_drv = {
                                   SNDRV_PCM_FMTBIT_S32_LE),
        },
        .ops            = &axg_pdm_dai_ops,
-       .probe          = axg_pdm_dai_probe,
-       .remove         = axg_pdm_dai_remove,
 };
 
 static const struct snd_soc_component_driver axg_pdm_component_drv = {
index e2cc4c4be758612be58f9fd1f64f0d2fb5c01d4e..d8688016907525eb80e6dd014e12d2916237b118 100644 (file)
@@ -267,6 +267,8 @@ static int axg_spdifin_dai_remove(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops axg_spdifin_ops = {
+       .probe          = axg_spdifin_dai_probe,
+       .remove         = axg_spdifin_dai_remove,
        .prepare        = axg_spdifin_prepare,
        .startup        = axg_spdifin_startup,
        .shutdown       = axg_spdifin_shutdown,
@@ -429,8 +431,6 @@ axg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv)
 
        drv->name = "SPDIF Input";
        drv->ops = &axg_spdifin_ops;
-       drv->probe = axg_spdifin_dai_probe;
-       drv->remove = axg_spdifin_dai_remove;
        drv->capture.stream_name = "Capture";
        drv->capture.channels_min = 1;
        drv->capture.channels_max = 2;
index 9883dc777f630ce2adbf1614480b4e60bc3f4c58..63333a2b0a9c363d6882d3fe50ecff78da390316 100644 (file)
@@ -30,27 +30,32 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map,
                                        struct axg_tdm_stream *ts,
                                        unsigned int offset)
 {
-       unsigned int val, ch = ts->channels;
-       unsigned long mask;
-       int i, j;
+       unsigned int ch = ts->channels;
+       u32 val[AXG_TDM_NUM_LANES];
+       int i, j, k;
+
+       /*
+        * We need to mimick the slot distribution used by the HW to keep the
+        * channel placement consistent regardless of the number of channel
+        * in the stream. This is why the odd algorithm below is used.
+        */
+       memset(val, 0, sizeof(*val) * AXG_TDM_NUM_LANES);
 
        /*
         * Distribute the channels of the stream over the available slots
-        * of each TDM lane
+        * of each TDM lane. We need to go over the 32 slots ...
         */
-       for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
-               val = 0;
-               mask = ts->mask[i];
-
-               for (j = find_first_bit(&mask, 32);
-                    (j < 32) && ch;
-                    j = find_next_bit(&mask, 32, j + 1)) {
-                       val |= 1 << j;
-                       ch -= 1;
+       for (i = 0; (i < 32) && ch; i += 2) {
+               /* ... of all the lanes ... */
+               for (j = 0; j < AXG_TDM_NUM_LANES; j++) {
+                       /* ... then distribute the channels in pairs */
+                       for (k = 0; k < 2; k++) {
+                               if ((BIT(i + k) & ts->mask[j]) && ch) {
+                                       val[j] |= BIT(i + k);
+                                       ch -= 1;
+                               }
+                       }
                }
-
-               regmap_write(map, offset, val);
-               offset += regmap_get_reg_stride(map);
        }
 
        /*
@@ -63,6 +68,11 @@ int axg_tdm_formatter_set_channel_masks(struct regmap *map,
                return -EINVAL;
        }
 
+       for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
+               regmap_write(map, offset, val[i]);
+               offset += regmap_get_reg_stride(map);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
index 5e5e4c56d5051fffd07f1cfb4adab06454462533..1c3d433cefd23c400850429d1f9211f9d0da47a9 100644 (file)
@@ -395,6 +395,8 @@ static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
+       .probe          = axg_tdm_iface_probe_dai,
+       .remove         = axg_tdm_iface_remove_dai,
        .set_sysclk     = axg_tdm_iface_set_sysclk,
        .set_fmt        = axg_tdm_iface_set_fmt,
        .startup        = axg_tdm_iface_startup,
@@ -423,8 +425,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
                },
                .id = TDM_IFACE_PAD,
                .ops = &axg_tdm_iface_ops,
-               .probe = axg_tdm_iface_probe_dai,
-               .remove = axg_tdm_iface_remove_dai,
        },
        [TDM_IFACE_LOOPBACK] = {
                .name = "TDM Loopback",
@@ -437,8 +437,6 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
                },
                .id = TDM_IFACE_LOOPBACK,
                .ops = &axg_tdm_iface_ops,
-               .probe = axg_tdm_iface_probe_dai,
-               .remove = axg_tdm_iface_remove_dai,
        },
 };
 
index e9208e74e9659a4ae9b90e9a8e897d9e000d8704..1a0be177b8fe77b13730dfb8f3e5e9450502dacc 100644 (file)
@@ -122,6 +122,7 @@ static const struct snd_soc_dai_ops axg_toddr_ops = {
        .hw_params      = axg_toddr_dai_hw_params,
        .startup        = axg_toddr_dai_startup,
        .shutdown       = axg_toddr_dai_shutdown,
+       .pcm_new        = axg_toddr_pcm_new,
 };
 
 static struct snd_soc_dai_driver axg_toddr_dai_drv = {
@@ -134,7 +135,6 @@ static struct snd_soc_dai_driver axg_toddr_dai_drv = {
                .formats        = AXG_FIFO_FORMATS,
        },
        .ops            = &axg_toddr_ops,
-       .pcm_new        = axg_toddr_pcm_new,
 };
 
 static const char * const axg_toddr_sel_texts[] = {
@@ -217,6 +217,7 @@ static const struct snd_soc_dai_ops g12a_toddr_ops = {
        .hw_params      = axg_toddr_dai_hw_params,
        .startup        = g12a_toddr_dai_startup,
        .shutdown       = axg_toddr_dai_shutdown,
+       .pcm_new        = axg_toddr_pcm_new,
 };
 
 static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
@@ -229,7 +230,6 @@ static struct snd_soc_dai_driver g12a_toddr_dai_drv = {
                .formats        = AXG_FIFO_FORMATS,
        },
        .ops            = &g12a_toddr_ops,
-       .pcm_new        = axg_toddr_pcm_new,
 };
 
 static const struct snd_soc_component_driver g12a_toddr_component_drv = {
index ddc667956cf5eec96e81dc77ea467d1d8d79eb74..6c4503766fdcaefd2de32ff8ed4e52f8d7e1534a 100644 (file)
@@ -162,6 +162,8 @@ static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops g12a_toacodec_input_ops = {
+       .probe          = meson_codec_glue_input_dai_probe,
+       .remove         = meson_codec_glue_input_dai_remove,
        .hw_params      = g12a_toacodec_input_hw_params,
        .set_fmt        = meson_codec_glue_input_set_fmt,
 };
@@ -185,8 +187,6 @@ static const struct snd_soc_dai_ops g12a_toacodec_output_ops = {
        .id = (xid),                                                    \
        .playback = TOACODEC_STREAM(xname, "Playback", 8),              \
        .ops = &g12a_toacodec_input_ops,                                \
-       .probe = meson_codec_glue_input_dai_probe,                      \
-       .remove = meson_codec_glue_input_dai_remove,                    \
 }
 
 #define TOACODEC_OUTPUT(xname, xid) {                                  \
index 579a04ad4d1973b9583264c90e93e043a88a64d9..f7ef9aa1eed8db1879595133238ab79bc75f4f10 100644 (file)
@@ -140,6 +140,8 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = {
 };
 
 static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = {
+       .probe          = meson_codec_glue_input_dai_probe,
+       .remove         = meson_codec_glue_input_dai_remove,
        .hw_params      = meson_codec_glue_input_hw_params,
        .set_fmt        = meson_codec_glue_input_set_fmt,
 };
@@ -172,8 +174,6 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = {
        .id = (xid),                                                    \
        .playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax),   \
        .ops = &g12a_tohdmitx_input_ops,                                \
-       .probe = meson_codec_glue_input_dai_probe,                      \
-       .remove = meson_codec_glue_input_dai_remove,                    \
 }
 
 #define TOHDMITX_OUT(xname, xid, xfmt, xchmax) {                       \
index a1ed141b8795cbe3a84b2c8943c55cbbd452c48b..abfaf3cdf5bb6fc80180ca713a63de18b095108f 100644 (file)
@@ -340,6 +340,7 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai)
                SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+       .probe          = mmp_sspa_probe,
        .startup        = mmp_sspa_startup,
        .shutdown       = mmp_sspa_shutdown,
        .trigger        = mmp_sspa_trigger,
@@ -350,7 +351,6 @@ static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
 };
 
 static struct snd_soc_dai_driver mmp_sspa_dai = {
-       .probe = mmp_sspa_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 128,
index 430dd446321e503feefd49dcf771a9d2789b635f..b70034c07eeea517b2a4dc2bff6f3bf708497ac5 100644 (file)
@@ -591,7 +591,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 
                if (ret < 0) {
                        const struct pxa_ssp_clock_mode *m;
-                       int ssacd, acds;
+                       int ssacd;
 
                        for (m = pxa_ssp_clock_modes; m->rate; m++) {
                                if (m->rate == rate)
@@ -601,12 +601,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
                        if (!m->rate)
                                return -EINVAL;
 
-                       acds = m->acds;
-
-                       /* The values in the table are for 16 bits */
-                       if (width == 32)
-                               acds--;
-
                        ret = pxa_ssp_set_pll(priv, bclk);
                        if (ret < 0)
                                return ret;
@@ -819,6 +813,8 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
 #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+       .probe          = pxa_ssp_probe,
+       .remove         = pxa_ssp_remove,
        .startup        = pxa_ssp_startup,
        .shutdown       = pxa_ssp_shutdown,
        .trigger        = pxa_ssp_trigger,
@@ -830,8 +826,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
 };
 
 static struct snd_soc_dai_driver pxa_ssp_dai = {
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
                .playback = {
                        .channels_min = 1,
                        .channels_max = 8,
index 3e4c7040367226eb47c59a09fc9676aed381bcc1..10636506b622e123e03c4043aa85d684afc96f86 100644 (file)
@@ -370,18 +370,11 @@ static const struct snd_soc_component_driver pxa_i2s_component = {
 
 static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 {
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct resource *res;
 
-       if (!res) {
-               dev_err(&pdev->dev, "missing MMIO resource\n");
-               return -ENXIO;
-       }
-
-       i2s_reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(i2s_reg_base)) {
-               dev_err(&pdev->dev, "ioremap failed\n");
+       i2s_reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+       if (IS_ERR(i2s_reg_base))
                return PTR_ERR(i2s_reg_base);
-       }
 
        pxa2xx_i2s_pcm_stereo_out.addr = res->start + SADR;
        pxa2xx_i2s_pcm_stereo_in.addr = res->start + SADR;
index e54b8961112f3f9a9d636874af1f23a1f258a6ee..6de533d45e7d8938573cd9afd2543c9a650e00fd 100644 (file)
@@ -44,6 +44,17 @@ struct apq8016_sbc_data {
 #define DEFAULT_MCLK_RATE              9600000
 #define MI2S_BCLK_RATE                 1536000
 
+static struct snd_soc_jack_pin apq8016_sbc_jack_pins[] = {
+       {
+               .pin = "Mic Jack",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
 static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
 {
        struct snd_soc_dai *codec_dai;
@@ -90,13 +101,15 @@ static int apq8016_dai_init(struct snd_soc_pcm_runtime *rtd, int mi2s)
        if (!pdata->jack_setup) {
                struct snd_jack *jack;
 
-               rval = snd_soc_card_jack_new(card, "Headset Jack",
-                                            SND_JACK_HEADSET |
-                                            SND_JACK_HEADPHONE |
-                                            SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                            SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                                            SND_JACK_BTN_4,
-                                            &pdata->jack);
+               rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                                 SND_JACK_HEADSET |
+                                                 SND_JACK_HEADPHONE |
+                                                 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                                 SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                                 SND_JACK_BTN_4,
+                                                 &pdata->jack,
+                                                 apq8016_sbc_jack_pins,
+                                                 ARRAY_SIZE(apq8016_sbc_jack_pins));
 
                if (rval < 0) {
                        dev_err(card->dev, "Unable to add Headphone Jack\n");
@@ -255,8 +268,14 @@ static void msm8916_qdsp6_add_ops(struct snd_soc_card *card)
        }
 }
 
-static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+static const struct snd_kcontrol_new apq8016_sbc_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
+};
 
+static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
        SND_SOC_DAPM_MIC("Handset Mic", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_MIC("Secondary Mic", NULL),
@@ -285,6 +304,8 @@ static int apq8016_sbc_platform_probe(struct platform_device *pdev)
        card->owner = THIS_MODULE;
        card->dapm_widgets = apq8016_sbc_dapm_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(apq8016_sbc_dapm_widgets);
+       card->controls = apq8016_sbc_snd_controls;
+       card->num_controls = ARRAY_SIZE(apq8016_sbc_snd_controls);
 
        ret = qcom_snd_parse_of(card);
        if (ret)
index abaf694ee9a3a13be626e405370ff407ba4ae3c8..f919d46e18caa82c2b95eba4a9ebcf63bbe05101 100644 (file)
@@ -41,7 +41,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
                        .channels_min   = 1,
                        .channels_max   = 8,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        },
        [MI2S_SECONDARY] =  {
@@ -62,7 +61,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
                        .channels_min   = 1,
                        .channels_max   = 8,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        },
        [MI2S_TERTIARY] =  {
@@ -83,7 +81,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
                        .channels_min   = 1,
                        .channels_max   = 8,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        },
        [MI2S_QUATERNARY] =  {
@@ -119,7 +116,6 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
                        .channels_min   = 1,
                        .channels_max   = 8,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        },
 };
index dbdaaa85ce48113b740f541f21a1181d015e535a..39571fed40019a0df9fbc50cefedeb88ef369e2e 100644 (file)
@@ -404,18 +404,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
-const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
-       .set_sysclk     = lpass_cpu_daiops_set_sysclk,
-       .startup        = lpass_cpu_daiops_startup,
-       .shutdown       = lpass_cpu_daiops_shutdown,
-       .hw_params      = lpass_cpu_daiops_hw_params,
-       .trigger        = lpass_cpu_daiops_trigger,
-       .prepare        = lpass_cpu_daiops_prepare,
-};
-EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
-
-int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
-                               struct snd_soc_dai *dai)
+static int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
        int ret;
        struct snd_soc_dai_driver *drv = dai->driver;
@@ -431,9 +420,8 @@ int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(lpass_cpu_pcm_new);
 
-int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+static int lpass_cpu_daiops_probe(struct snd_soc_dai *dai)
 {
        struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
        int ret;
@@ -446,7 +434,29 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
+       .probe          = lpass_cpu_daiops_probe,
+       .set_sysclk     = lpass_cpu_daiops_set_sysclk,
+       .startup        = lpass_cpu_daiops_startup,
+       .shutdown       = lpass_cpu_daiops_shutdown,
+       .hw_params      = lpass_cpu_daiops_hw_params,
+       .trigger        = lpass_cpu_daiops_trigger,
+       .prepare        = lpass_cpu_daiops_prepare,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = {
+       .pcm_new        = lpass_cpu_daiops_pcm_new,
+       .probe          = lpass_cpu_daiops_probe,
+       .set_sysclk     = lpass_cpu_daiops_set_sysclk,
+       .startup        = lpass_cpu_daiops_startup,
+       .shutdown       = lpass_cpu_daiops_shutdown,
+       .hw_params      = lpass_cpu_daiops_hw_params,
+       .trigger        = lpass_cpu_daiops_trigger,
+       .prepare        = lpass_cpu_daiops_prepare,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2);
 
 static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
                                   const struct of_phandle_args *args,
index ef8a7984f232356c1f879abfb5b5efe04e725d44..2c97f295e39400dc048f19c87140aa6f25a9a06c 100644 (file)
@@ -51,7 +51,6 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
                .channels_min   = 1,
                .channels_max   = 8,
        },
-       .probe  = &asoc_qcom_lpass_cpu_dai_probe,
        .ops    = &asoc_qcom_lpass_cpu_dai_ops,
 };
 
index 56db852f4eab31998cfb1b5ac7ec04714013c64c..d16c0d83aaad923890fe9d6994c12663947d40a0 100644 (file)
@@ -43,7 +43,6 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
                        .channels_min   = 2,
                        .channels_max   = 2,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        }, {
                .id = MI2S_SECONDARY,
@@ -57,9 +56,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = {
                        .channels_min   = 2,
                        .channels_max   = 2,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
-               .ops    = &asoc_qcom_lpass_cpu_dai_ops,
-               .pcm_new = lpass_cpu_pcm_new,
+               .ops    = &asoc_qcom_lpass_cpu_dai_ops2,
        }, {
                .id = LPASS_DP_RX,
                .name = "Hdmi",
index bcf18fe8e14deea71cab5acb17a1e725c8f256e7..6b2eb25ed9390c012b7eca326dcc6ce70f4aa86a 100644 (file)
@@ -38,7 +38,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
                        .channels_min   = 2,
                        .channels_max   = 2,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        }, {
                .id = MI2S_SECONDARY,
@@ -52,7 +51,6 @@ static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
                        .channels_min   = 2,
                        .channels_max   = 2,
                },
-               .probe  = &asoc_qcom_lpass_cpu_dai_probe,
                .ops    = &asoc_qcom_lpass_cpu_dai_ops,
        }, {
                .id = LPASS_DP_RX,
index dd78600fc7b012ddc30e7d3990397847ce5d325d..bdfe66ec3314f9ee3abd27455c213b5a82628d83 100644 (file)
@@ -402,10 +402,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *);
 int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
 void asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
-int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
 extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
-int lpass_cpu_pcm_new(struct snd_soc_pcm_runtime *rtd,
-                               struct snd_soc_dai *dai);
+extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2;
 extern const struct snd_soc_dai_ops asoc_qcom_lpass_cdc_dma_dai_ops;
 
 #endif /* __LPASS_H__ */
index dbff55a971627df001d8dfd4a42875ed0ca6f4c2..3faa7e0eb0dd6a7441628d1ab7c4bd7773cda969 100644 (file)
@@ -619,44 +619,6 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
        {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"},
 };
 
-static const struct snd_soc_dai_ops q6hdmi_ops = {
-       .prepare        = q6afe_dai_prepare,
-       .hw_params      = q6hdmi_hw_params,
-       .shutdown       = q6afe_dai_shutdown,
-};
-
-static const struct snd_soc_dai_ops q6i2s_ops = {
-       .prepare        = q6afe_dai_prepare,
-       .hw_params      = q6i2s_hw_params,
-       .set_fmt        = q6i2s_set_fmt,
-       .shutdown       = q6afe_dai_shutdown,
-       .set_sysclk     = q6afe_mi2s_set_sysclk,
-};
-
-static const struct snd_soc_dai_ops q6slim_ops = {
-       .prepare        = q6afe_dai_prepare,
-       .hw_params      = q6slim_hw_params,
-       .shutdown       = q6afe_dai_shutdown,
-       .set_channel_map = q6slim_set_channel_map,
-};
-
-static const struct snd_soc_dai_ops q6tdm_ops = {
-       .prepare        = q6afe_dai_prepare,
-       .shutdown       = q6afe_dai_shutdown,
-       .set_sysclk     = q6afe_mi2s_set_sysclk,
-       .set_tdm_slot     = q6tdm_set_tdm_slot,
-       .set_channel_map  = q6tdm_set_channel_map,
-       .hw_params        = q6tdm_hw_params,
-};
-
-static const struct snd_soc_dai_ops q6dma_ops = {
-       .prepare        = q6afe_dai_prepare,
-       .shutdown       = q6afe_dai_shutdown,
-       .set_sysclk     = q6afe_mi2s_set_sysclk,
-       .set_channel_map  = q6dma_set_channel_map,
-       .hw_params        = q6dma_hw_params,
-};
-
 static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
 {
        struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -682,6 +644,54 @@ static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops q6hdmi_ops = {
+       .probe                  = msm_dai_q6_dai_probe,
+       .remove                 = msm_dai_q6_dai_remove,
+       .prepare                = q6afe_dai_prepare,
+       .hw_params              = q6hdmi_hw_params,
+       .shutdown               = q6afe_dai_shutdown,
+};
+
+static const struct snd_soc_dai_ops q6i2s_ops = {
+       .probe                  = msm_dai_q6_dai_probe,
+       .remove                 = msm_dai_q6_dai_remove,
+       .prepare                = q6afe_dai_prepare,
+       .hw_params              = q6i2s_hw_params,
+       .set_fmt                = q6i2s_set_fmt,
+       .shutdown               = q6afe_dai_shutdown,
+       .set_sysclk             = q6afe_mi2s_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops q6slim_ops = {
+       .probe                  = msm_dai_q6_dai_probe,
+       .remove                 = msm_dai_q6_dai_remove,
+       .prepare                = q6afe_dai_prepare,
+       .hw_params              = q6slim_hw_params,
+       .shutdown               = q6afe_dai_shutdown,
+       .set_channel_map        = q6slim_set_channel_map,
+};
+
+static const struct snd_soc_dai_ops q6tdm_ops = {
+       .probe                  = msm_dai_q6_dai_probe,
+       .remove                 = msm_dai_q6_dai_remove,
+       .prepare                = q6afe_dai_prepare,
+       .shutdown               = q6afe_dai_shutdown,
+       .set_sysclk             = q6afe_mi2s_set_sysclk,
+       .set_tdm_slot           = q6tdm_set_tdm_slot,
+       .set_channel_map        = q6tdm_set_channel_map,
+       .hw_params              = q6tdm_hw_params,
+};
+
+static const struct snd_soc_dai_ops q6dma_ops = {
+       .probe                  = msm_dai_q6_dai_probe,
+       .remove                 = msm_dai_q6_dai_remove,
+       .prepare                = q6afe_dai_prepare,
+       .shutdown               = q6afe_dai_shutdown,
+       .set_sysclk             = q6afe_mi2s_set_sysclk,
+       .set_channel_map        = q6dma_set_channel_map,
+       .hw_params              = q6dma_hw_params,
+};
+
 static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
        SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
@@ -1041,8 +1051,6 @@ static int q6afe_dai_dev_probe(struct platform_device *pdev)
        dev_set_drvdata(dev, dai_data);
        of_q6afe_parse_dai_data(dev, dai_data);
 
-       cfg.probe = msm_dai_q6_dai_probe;
-       cfg.remove = msm_dai_q6_dai_remove;
        cfg.q6hdmi_ops = &q6hdmi_ops;
        cfg.q6slim_ops = &q6slim_ops;
        cfg.q6i2s_ops = &q6i2s_ops;
index 5d44d07acd69c05655b8ec487879f0b3f87ef5e1..2a2a5bd98110bc70c2a164efb22df4147979d295 100644 (file)
@@ -27,7 +27,7 @@ struct apm_graph_mgmt_cmd {
 
 #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8)
 
-struct q6apm *g_apm;
+static struct q6apm *g_apm;
 
 int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
 {
index 8ee40732ce9e7187f9ce2983bda73836daa5376f..f486bd639b9f0d277b6b28937f65d3b8c5436f18 100644 (file)
@@ -126,7 +126,6 @@ int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
                                   struct audioreach_module_config *cfg);
 
 /* read/write related */
-int q6apm_send_eos_nowait(struct q6apm_graph *graph);
 int q6apm_read(struct q6apm_graph *graph);
 int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
                      uint32_t lsw_ts, uint32_t wflags);
@@ -144,7 +143,6 @@ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt,
 /* Callback for graph specific */
 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph,
                                                    uint32_t mid);
-void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv);
 int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph);
 
 bool q6apm_is_adsp_ready(void);
index 5fc8088e63c8107214a365df955a75825958b4e3..fe0666e9fd2386086b5ca0b2ff9b1df67056f6b0 100644 (file)
@@ -1230,6 +1230,10 @@ static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
        Q6ASM_FEDAI_DRIVER(8),
 };
 
+static const struct snd_soc_dai_ops q6asm_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static int of_q6asm_parse_dai_data(struct device *dev,
                                    struct q6asm_dai_data *pdata)
 {
@@ -1272,7 +1276,7 @@ static int of_q6asm_parse_dai_data(struct device *dev,
                        dai_drv->playback = empty_stream;
 
                if (of_property_read_bool(node, "is-compress-dai"))
-                       dai_drv->compress_new = snd_soc_new_compress;
+                       dai_drv->ops = &q6asm_dai_ops;
        }
 
        return 0;
index ac937a6bf909be5f1e73e471c3c7ca5e94ce7145..4919001de08b3eec87098c5280e3ee0702952b15 100644 (file)
@@ -603,9 +603,6 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
        int i;
 
        for (i = 0; i  < ARRAY_SIZE(q6dsp_audio_fe_dais); i++) {
-               q6dsp_audio_fe_dais[i].probe = cfg->probe;
-               q6dsp_audio_fe_dais[i].remove = cfg->remove;
-
                switch (q6dsp_audio_fe_dais[i].id) {
                case HDMI_RX:
                case DISPLAY_PORT_RX:
index f5f7c64b23a27ddeb1c6fa69c7d3ff61e54ba2f3..57c5f35dfcc51c4594804ad007a1ee60cf6b2aac 100644 (file)
@@ -42,6 +42,17 @@ static void sc7180_jack_free(struct snd_jack *jack)
        snd_soc_component_set_jack(component, NULL, NULL);
 }
 
+static struct snd_soc_jack_pin sc7180_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
@@ -51,13 +62,14 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_jack *jack;
        int rval;
 
-       rval = snd_soc_card_jack_new(
-                       card, "Headset Jack",
-                       SND_JACK_HEADSET |
-                       SND_JACK_HEADPHONE |
-                       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                       SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                       &pdata->hs_jack);
+       rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                         SND_JACK_HEADSET |
+                                         SND_JACK_HEADPHONE |
+                                         SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                         SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                         &pdata->hs_jack,
+                                         sc7180_jack_pins,
+                                         ARRAY_SIZE(sc7180_jack_pins));
 
        if (rval < 0) {
                dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -297,6 +309,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_widgets[] = {
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 };
 
+static const struct snd_kcontrol_new sc7180_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
 static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets[] = {
        SND_SOC_DAPM_MIC("DMIC", NULL),
 };
@@ -320,6 +337,11 @@ static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets[] = {
        SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, &sc7180_dmic_mux_control),
 };
 
+static const struct snd_kcontrol_new sc7180_snd_dual_mic_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
 static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route[] = {
        {"Dmic Mux", "Front Mic", "DMIC"},
        {"Dmic Mux", "Rear Mic", "DMIC"},
@@ -348,10 +370,14 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
        card->dev = dev;
        card->dapm_widgets = sc7180_snd_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_widgets);
+       card->controls = sc7180_snd_controls;
+       card->num_controls = ARRAY_SIZE(sc7180_snd_controls);
 
        if (of_property_read_bool(dev->of_node, "dmic-gpios")) {
                card->dapm_widgets = sc7180_snd_dual_mic_widgets,
                card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets),
+               card->controls = sc7180_snd_dual_mic_controls,
+               card->num_controls = ARRAY_SIZE(sc7180_snd_dual_mic_controls),
                card->dapm_routes = sc7180_snd_dual_mic_audio_route,
                card->num_dapm_routes = ARRAY_SIZE(sc7180_snd_dual_mic_audio_route),
                data->dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW);
index 787dd49e03f69ebbccc8ca5d5c290d6a2b8ffb22..43010e4e224202a8c1283b7d0eb322f757692d0a 100644 (file)
@@ -43,6 +43,17 @@ static void sc7280_jack_free(struct snd_jack *jack)
        snd_soc_component_set_jack(component, NULL, NULL);
 }
 
+static struct snd_soc_jack_pin sc7280_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
@@ -54,13 +65,15 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
        int rval, i;
 
        if (!pdata->jack_setup) {
-               rval = snd_soc_card_jack_new(card, "Headset Jack",
-                                            SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                                            SND_JACK_MECHANICAL |
-                                            SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                            SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                                            SND_JACK_BTN_4 | SND_JACK_BTN_5,
-                                            &pdata->hs_jack);
+               rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                                 SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                                 SND_JACK_MECHANICAL |
+                                                 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                                 SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                                 SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                                                 &pdata->hs_jack,
+                                                 sc7280_jack_pins,
+                                                 ARRAY_SIZE(sc7280_jack_pins));
 
                if (rval < 0) {
                        dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -361,6 +374,11 @@ static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = {
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 };
 
+static const struct snd_kcontrol_new sc7280_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
 static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
                                         struct snd_pcm_hw_params *params)
 {
@@ -396,6 +414,8 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev)
 
        card->dapm_widgets = sc7280_snd_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets);
+       card->controls = sc7280_snd_controls;
+       card->num_controls = ARRAY_SIZE(sc7280_snd_controls);
 
        ret = qcom_snd_parse_of(card);
        if (ret)
index 02612af714a8e8b215f20831a33abece6bdbaaea..29d23fe5dfa2d54aebaedeff1114c45b61581168 100644 (file)
@@ -42,6 +42,17 @@ struct sdm845_snd_data {
        struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
 };
 
+static struct snd_soc_jack_pin sdm845_jack_pins[] = {
+       {
+               .pin = "Headphone Jack",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
 
 static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
@@ -242,12 +253,14 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
 
 
        if (!pdata->jack_setup) {
-               rval = snd_soc_card_jack_new(card, "Headset Jack",
-                               SND_JACK_HEADSET |
-                               SND_JACK_HEADPHONE |
-                               SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                               SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                               &pdata->jack);
+               rval = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                                 SND_JACK_HEADSET |
+                                                 SND_JACK_HEADPHONE |
+                                                 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                                 SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                                 &pdata->jack,
+                                                 sdm845_jack_pins,
+                                                 ARRAY_SIZE(sdm845_jack_pins));
 
                if (rval < 0) {
                        dev_err(card->dev, "Unable to add Headphone Jack\n");
@@ -539,6 +552,11 @@ static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
        SND_SOC_DAPM_MIC("Int Mic", NULL),
 };
 
+static const struct snd_kcontrol_new sdm845_snd_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+};
+
 static void sdm845_add_ops(struct snd_soc_card *card)
 {
        struct snd_soc_dai_link *link;
@@ -572,6 +590,8 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
        card->driver_name = DRIVER_NAME;
        card->dapm_widgets = sdm845_snd_widgets;
        card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
+       card->controls = sdm845_snd_controls;
+       card->num_controls = ARRAY_SIZE(sdm845_snd_controls);
        card->dev = dev;
        card->owner = THIS_MODULE;
        dev_set_drvdata(dev, card);
index 5e52e9d60d4457d17f517de20ac4026ae0c8bc62..0f704d22d21b01867acd20811b4dde582a12e953 100644 (file)
@@ -41,13 +41,17 @@ static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {
                .pin = "Headset Mic",
                .mask = SND_JACK_MICROPHONE,
        },
-
+       {
+               .pin = "Line Out",
+               .mask = SND_JACK_LINEOUT,
+       },
 };
 
 static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
        SND_SOC_DAPM_MIC("Int Mic", NULL),
        SND_SOC_DAPM_LINE("HDMI", NULL),
 };
@@ -56,6 +60,7 @@ static const struct snd_kcontrol_new rockchip_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphones"),
        SOC_DAPM_PIN_SWITCH("Speakers"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
        SOC_DAPM_PIN_SWITCH("Int Mic"),
        SOC_DAPM_PIN_SWITCH("HDMI"),
 };
index 575a0b9b01e92928bb701c56543b36e3208b5e0f..834fbb5cf8103f7eff6c99216e4d3239c800b136 100644 (file)
@@ -539,6 +539,7 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
+       .probe = rockchip_i2s_dai_probe,
        .hw_params = rockchip_i2s_hw_params,
        .set_bclk_ratio = rockchip_i2s_set_bclk_ratio,
        .set_sysclk = rockchip_i2s_set_sysclk,
@@ -547,7 +548,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver rockchip_i2s_dai = {
-       .probe = rockchip_i2s_dai_probe,
        .ops = &rockchip_i2s_dai_ops,
        .symmetric_rate = 1,
 };
index 166257c6ae147570db244c68529ad5eaad99cd07..d3700f3c98e654a47c77d44330c8ba60cd9bccf9 100644 (file)
@@ -1114,6 +1114,7 @@ static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai,
 }
 
 static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
+       .probe = rockchip_i2s_tdm_dai_probe,
        .hw_params = rockchip_i2s_tdm_hw_params,
        .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio,
        .set_sysclk = rockchip_i2s_tdm_set_sysclk,
@@ -1324,7 +1325,6 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = {
 };
 
 static const struct snd_soc_dai_driver i2s_tdm_dai = {
-       .probe = rockchip_i2s_tdm_dai_probe,
        .ops = &rockchip_i2s_tdm_dai_ops,
 };
 
index 52f9aae60be8ad5fd9029d1347581b16f182f502..4756cfc23218cabf69f39e2cee75e9fc03cb878a 100644 (file)
@@ -379,6 +379,7 @@ static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
+       .probe = rockchip_pdm_dai_probe,
        .set_fmt = rockchip_pdm_set_fmt,
        .trigger = rockchip_pdm_trigger,
        .hw_params = rockchip_pdm_hw_params,
@@ -391,7 +392,6 @@ static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = {
                              SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_driver rockchip_pdm_dai = {
-       .probe = rockchip_pdm_dai_probe,
        .capture = {
                .stream_name = "Capture",
                .channels_min = 2,
@@ -584,7 +584,7 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
 
        match = of_match_device(rockchip_pdm_match, &pdev->dev);
        if (match)
-               pdm->version = (enum rk_pdm_version)match->data;
+               pdm->version = (uintptr_t)match->data;
 
        if (pdm->version == RK_PDM_RK3308) {
                pdm->reset = devm_reset_control_get(&pdev->dev, "pdm-m");
index e73a342b7953c67f571a6104db08c46abd39042c..ef9fdf0386cbdbce70dbf1ea210a8544adb7d023 100644 (file)
 #define DRV_NAME "rockchip-snd-rt5645"
 
 static struct snd_soc_jack headset_jack;
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
 
 static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
@@ -103,11 +113,13 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
        int ret;
 
        /* Enable Headset and 4 Buttons Jack detection */
-       ret = snd_soc_card_jack_new(card, "Headset Jack",
-                                   SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3,
-                                   &headset_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
+                                        SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3,
+                                        &headset_jack,
+                                        headset_jack_pins,
+                                        ARRAY_SIZE(headset_jack_pins));
        if (ret) {
                dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
                return ret;
index 0b73fe94e4bbdc5a15111d304ebf87a685dc2a98..1a24b78e9e02a20d7b969a604f0386da8b071928 100644 (file)
@@ -202,12 +202,12 @@ static int rk_spdif_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops rk_spdif_dai_ops = {
+       .probe = rk_spdif_dai_probe,
        .hw_params = rk_spdif_hw_params,
        .trigger = rk_spdif_trigger,
 };
 
 static struct snd_soc_dai_driver rk_spdif_dai = {
-       .probe = rk_spdif_dai_probe,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
index 7492bb41456c700744c00630351f9995540dfeae..dd3cd2c9644a0a467f45bcd59c1032ce13c37ba5 100644 (file)
@@ -620,10 +620,14 @@ static int aries_audio_probe(struct platform_device *pdev)
        /* Update card-name if provided through DT, else use default name */
        snd_soc_of_parse_card_name(card, "model");
 
-       ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+       ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
        if (ret < 0) {
-               dev_err(dev, "Audio routing invalid/unspecified\n");
-               return ret;
+               /* Backwards compatible way */
+               ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+               if (ret < 0) {
+                       dev_err(dev, "Audio routing invalid/unspecified\n");
+                       return ret;
+               }
        }
 
        aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt;
index f3d98abd5f0d3c088341019f3e26544bacf12967..3af48c9b5ab7b9bf201bbb07b246105e70501c1c 100644 (file)
@@ -1120,6 +1120,8 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+       .probe = samsung_i2s_dai_probe,
+       .remove = samsung_i2s_dai_remove,
        .trigger = i2s_trigger,
        .hw_params = i2s_hw_params,
        .set_fmt = i2s_set_fmt,
@@ -1188,9 +1190,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
        for (i = 0; i < num_dais; i++) {
                dai_drv = &priv->dai_drv[i];
 
-               dai_drv->probe = samsung_i2s_dai_probe;
-               dai_drv->remove = samsung_i2s_dai_remove;
-
                dai_drv->symmetric_rate = 1;
                dai_drv->ops = &samsung_i2s_dai_ops;
 
index 5d8118e69359395a48d3b306fece8e6d46a67329..fafadcef234e4d76b02e1aa6a610f972d6b8730b 100644 (file)
@@ -225,12 +225,15 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w,
 }
 
 static const struct snd_kcontrol_new controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("WM1250 Input"),
        SOC_DAPM_PIN_SWITCH("WM1250 Output"),
 };
 
 static const struct snd_soc_dapm_widget widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_HP("Headset Mic", NULL),
 
        SND_SOC_DAPM_MIC("AMIC", NULL),
        SND_SOC_DAPM_MIC("DMIC", NULL),
@@ -255,6 +258,16 @@ static const struct snd_soc_dapm_route audio_paths[] = {
 };
 
 static struct snd_soc_jack littlemill_headset;
+static struct snd_soc_jack_pin littlemill_headset_pins[] = {
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
 
 static int littlemill_late_probe(struct snd_soc_card *card)
 {
@@ -281,12 +294,14 @@ static int littlemill_late_probe(struct snd_soc_card *card)
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_card_jack_new(card, "Headset",
-                                   SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                                   SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                   SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                                   SND_JACK_BTN_4 | SND_JACK_BTN_5,
-                                   &littlemill_headset);
+       ret = snd_soc_card_jack_new_pins(card, "Headset",
+                                        SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                        SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                        SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                                        &littlemill_headset,
+                                        littlemill_headset_pins,
+                                        ARRAY_SIZE(littlemill_headset_pins));
        if (ret)
                return ret;
 
index 106770be6fc5afae3ba5a4aa0b69c99b7011b3b9..a79df871ea135899d3dd442401991d18c03ac700 100644 (file)
@@ -22,12 +22,16 @@ static struct snd_soc_jack lowland_headset;
 static struct snd_soc_jack_pin lowland_headset_pins[] = {
        {
                .pin = "Headphone",
-               .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
+               .mask = SND_JACK_HEADPHONE,
        },
        {
                .pin = "Headset Mic",
                .mask = SND_JACK_MICROPHONE,
        },
+       {
+               .pin = "Line Out",
+               .mask = SND_JACK_LINEOUT,
+       },
 };
 
 static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
@@ -140,11 +144,13 @@ static const struct snd_kcontrol_new controls[] = {
        SOC_DAPM_PIN_SWITCH("WM1250 Input"),
        SOC_DAPM_PIN_SWITCH("WM1250 Output"),
        SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Line Out"),
 };
 
 static const struct snd_soc_dapm_widget widgets[] = {
        SND_SOC_DAPM_HP("Headphone", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
 
        SND_SOC_DAPM_SPK("Main Speaker", NULL),
 
index 6931b9a45b3e5e5f0fc4f29dab4f010f5b42baef..2ec7e16ddfa216ce97c578629a1171e569133ada 100644 (file)
@@ -38,6 +38,17 @@ struct midas_priv {
        struct snd_soc_jack headset_jack;
 };
 
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
 static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
 {
        struct snd_soc_card *card = rtd->card;
@@ -261,6 +272,7 @@ static const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
        SND_SOC_DAPM_LINE("HDMI", NULL),
        SND_SOC_DAPM_LINE("FM In", midas_fm_set),
 
+       SND_SOC_DAPM_HP("Headphone", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
        SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
@@ -305,11 +317,13 @@ static int midas_late_probe(struct snd_soc_card *card)
                return ret;
        }
 
-       ret = snd_soc_card_jack_new(card, "Headset",
-                       SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                       SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
-                       SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
-                       &priv->headset_jack);
+       ret = snd_soc_card_jack_new_pins(card, "Headset",
+                                        SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                                        SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                                        SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                                        &priv->headset_jack,
+                                        headset_jack_pins,
+                                        ARRAY_SIZE(headset_jack_pins));
        if (ret)
                return ret;
 
@@ -462,10 +476,14 @@ static int midas_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+       ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
        if (ret < 0) {
-               dev_err(dev, "Audio routing invalid/unspecified\n");
-               return ret;
+               /* Backwards compatible way */
+               ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+               if (ret < 0) {
+                       dev_err(dev, "Audio routing invalid/unspecified\n");
+                       return ret;
+               }
        }
 
        cpu = of_get_child_by_name(dev->of_node, "cpu");
index a5442592bde4da26398fa6e7a69bb0e5f791f169..c93cb5a864269fc9ad4862997cf5a9664c86f88e 100644 (file)
@@ -223,19 +223,20 @@ static int odroid_audio_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) {
+       if (of_property_present(dev->of_node, "samsung,audio-widgets")) {
                ret = snd_soc_of_parse_audio_simple_widgets(card,
                                                "samsung,audio-widgets");
                if (ret < 0)
                        return ret;
        }
 
-       if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) {
-               ret = snd_soc_of_parse_audio_routing(card,
-                                               "samsung,audio-routing");
-               if (ret < 0)
-                       return ret;
-       }
+       ret = 0;
+       if (of_property_present(dev->of_node, "audio-routing"))
+               ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+       else if (of_property_present(dev->of_node, "samsung,audio-routing"))
+               ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+       if (ret < 0)
+               return ret;
 
        card->dai_link = odroid_card_dais;
        card->num_links = ARRAY_SIZE(odroid_card_dais);
index 335fe5cb9cfc67c88b0f13cc196cb7107f1f4f63..d2cdc5c8e05bdf2c26fcc415d72e3c23ddddd549 100644 (file)
@@ -432,14 +432,6 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
-       .set_sysclk     = s3c_pcm_set_sysclk,
-       .set_clkdiv     = s3c_pcm_set_clkdiv,
-       .trigger        = s3c_pcm_trigger,
-       .hw_params      = s3c_pcm_hw_params,
-       .set_fmt        = s3c_pcm_set_fmt,
-};
-
 static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
 {
        struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai);
@@ -449,11 +441,19 @@ static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+       .probe          = s3c_pcm_dai_probe,
+       .set_sysclk     = s3c_pcm_set_sysclk,
+       .set_clkdiv     = s3c_pcm_set_clkdiv,
+       .trigger        = s3c_pcm_trigger,
+       .hw_params      = s3c_pcm_hw_params,
+       .set_fmt        = s3c_pcm_set_fmt,
+};
+
 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
 
 #define S3C_PCM_DAI_DECLARE                    \
        .symmetric_rate = 1,                                    \
-       .probe = s3c_pcm_dai_probe,                             \
        .ops = &s3c_pcm_dai_ops,                                \
        .playback = {                                           \
                .channels_min   = 2,                            \
index d611ec9e5325e6a1eebe032eba1d16fe9403d5f8..5ebf17f3de1e15c30fb5075c562638049cc6cca8 100644 (file)
@@ -523,10 +523,14 @@ static int tm2_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+       ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
        if (ret < 0) {
-               dev_err(dev, "Audio routing is not specified or invalid\n");
-               return ret;
+               /* Backwards compatible way */
+               ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
+               if (ret < 0) {
+                       dev_err(dev, "Audio routing is not specified or invalid\n");
+                       return ret;
+               }
        }
 
        card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node,
index 6a522e6dd85ab27c2e90faa091fd8bf6a1ada274..e29c2fee9521943bd961b5725b30a9024a00e72b 100644 (file)
@@ -1085,17 +1085,6 @@ static u64 rsnd_soc_dai_formats[] = {
        SND_SOC_POSSIBLE_DAIFMT_DSP_B,
 };
 
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
-       .startup        = rsnd_soc_dai_startup,
-       .shutdown       = rsnd_soc_dai_shutdown,
-       .trigger        = rsnd_soc_dai_trigger,
-       .set_fmt        = rsnd_soc_dai_set_fmt,
-       .set_tdm_slot   = rsnd_soc_set_dai_tdm_slot,
-       .prepare        = rsnd_soc_dai_prepare,
-       .auto_selectable_formats        = rsnd_soc_dai_formats,
-       .num_auto_selectable_formats    = ARRAY_SIZE(rsnd_soc_dai_formats),
-};
-
 static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
                                      struct rsnd_dai_stream *io,
                                      struct device_node *dai_np)
@@ -1260,13 +1249,13 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name
        return i;
 }
 
-static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
-                                           int *is_graph)
+static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct device_node *np = dev->of_node;
-       struct device_node *dai_node;
-       struct device_node *ret;
+       struct device_node *ports, *node;
+       int nr = 0;
+       int i = 0;
 
        *is_graph = 0;
 
@@ -1274,26 +1263,53 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
         * parse both previous dai (= rcar_sound,dai), and
         * graph dai (= ports/port)
         */
-       dai_node = of_get_child_by_name(np, RSND_NODE_DAI);
-       if (dai_node) {
-               ret = dai_node;
-               goto of_node_compatible;
-       }
 
-       ret = np;
+       /*
+        * Simple-Card
+        */
+       node = of_get_child_by_name(np, RSND_NODE_DAI);
+       if (!node)
+               goto audio_graph;
 
-       dai_node = of_graph_get_next_endpoint(np, NULL);
-       if (dai_node)
-               goto of_node_graph;
+       of_node_put(node);
 
-       return NULL;
+       for_each_child_of_node(np, node) {
+               if (!of_node_name_eq(node, RSND_NODE_DAI))
+                       continue;
+
+               priv->component_dais[i] = of_get_child_count(node);
+               nr += priv->component_dais[i];
+               i++;
+               if (i >= RSND_MAX_COMPONENT) {
+                       dev_info(dev, "reach to max component\n");
+                       of_node_put(node);
+                       break;
+               }
+       }
+
+       return nr;
+
+audio_graph:
+       /*
+        * Audio-Graph-Card
+        */
+       for_each_child_of_node(np, ports) {
+               if (!of_node_name_eq(ports, "ports") &&
+                   !of_node_name_eq(ports, "port"))
+                       continue;
+               priv->component_dais[i] = of_graph_get_endpoint_count(ports);
+               nr += priv->component_dais[i];
+               i++;
+               if (i >= RSND_MAX_COMPONENT) {
+                       dev_info(dev, "reach to max component\n");
+                       of_node_put(node);
+                       break;
+               }
+       }
 
-of_node_graph:
        *is_graph = 1;
-of_node_compatible:
-       of_node_put(dai_node);
 
-       return ret;
+       return nr;
 }
 
 
@@ -1328,8 +1344,7 @@ static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
-static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd,
-                       struct snd_soc_dai *dai)
+static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
 {
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        int ret;
@@ -1355,8 +1370,22 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd,
        return 0;
 }
 
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+       .pcm_new                        = rsnd_soc_dai_pcm_new,
+       .startup                        = rsnd_soc_dai_startup,
+       .shutdown                       = rsnd_soc_dai_shutdown,
+       .trigger                        = rsnd_soc_dai_trigger,
+       .set_fmt                        = rsnd_soc_dai_set_fmt,
+       .set_tdm_slot                   = rsnd_soc_set_dai_tdm_slot,
+       .prepare                        = rsnd_soc_dai_prepare,
+       .auto_selectable_formats        = rsnd_soc_dai_formats,
+       .num_auto_selectable_formats    = ARRAY_SIZE(rsnd_soc_dai_formats),
+};
+
 static void __rsnd_dai_probe(struct rsnd_priv *priv,
                             struct device_node *dai_np,
+                            struct device_node *node_np,
+                            uint32_t node_arg,
                             int dai_i)
 {
        struct rsnd_dai_stream *io_playback;
@@ -1374,10 +1403,16 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
 
        snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
 
+       /* for multi Component */
+       rdai->dai_args.np               = node_np;
+       rdai->dai_args.args_count       = 1;
+       rdai->dai_args.args[0]          = node_arg;
+
        rdai->priv      = priv;
        drv->name       = rdai->name;
        drv->ops        = &rsnd_soc_dai_ops;
-       drv->pcm_new    = rsnd_pcm_new;
+       drv->id         = dai_i;
+       drv->dai_args   = &rdai->dai_args;
 
        io_playback->rdai               = rdai;
        io_capture->rdai                = rdai;
@@ -1441,21 +1476,15 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
 
 static int rsnd_dai_probe(struct rsnd_priv *priv)
 {
-       struct device_node *dai_node;
-       struct device_node *dai_np;
        struct snd_soc_dai_driver *rdrv;
        struct device *dev = rsnd_priv_to_dev(priv);
+       struct device_node *np = dev->of_node;
        struct rsnd_dai *rdai;
-       int nr;
+       int nr = 0;
        int is_graph;
        int dai_i;
 
-       dai_node = rsnd_dai_of_node(priv, &is_graph);
-       if (is_graph)
-               nr = of_graph_get_endpoint_count(dai_node);
-       else
-               nr = of_get_child_count(dai_node);
-
+       nr = rsnd_dai_of_node(priv, &is_graph);
        if (!nr)
                return -EINVAL;
 
@@ -1473,26 +1502,42 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
         */
        dai_i = 0;
        if (is_graph) {
-               for_each_endpoint_of_node(dai_node, dai_np) {
-                       __rsnd_dai_probe(priv, dai_np, dai_i);
-                       if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
-                               rdai = rsnd_rdai_get(priv, dai_i);
-
-                               rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
-                               rsnd_parse_connect_graph(priv, &rdai->capture,  dai_np);
+               struct device_node *ports;
+               struct device_node *dai_np;
+
+               for_each_child_of_node(np, ports) {
+                       if (!of_node_name_eq(ports, "ports") &&
+                           !of_node_name_eq(ports, "port"))
+                               continue;
+                       for_each_endpoint_of_node(ports, dai_np) {
+                               __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i);
+                               if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
+                                       rdai = rsnd_rdai_get(priv, dai_i);
+
+                                       rsnd_parse_connect_graph(priv, &rdai->playback, dai_np);
+                                       rsnd_parse_connect_graph(priv, &rdai->capture,  dai_np);
+                               }
+                               dai_i++;
                        }
-                       dai_i++;
                }
        } else {
-               for_each_child_of_node(dai_node, dai_np) {
-                       __rsnd_dai_probe(priv, dai_np, dai_i);
-                       if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
-                               rdai = rsnd_rdai_get(priv, dai_i);
+               struct device_node *node;
+               struct device_node *dai_np;
+
+               for_each_child_of_node(np, node) {
+                       if (!of_node_name_eq(node, RSND_NODE_DAI))
+                               continue;
 
-                               rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
-                               rsnd_parse_connect_simple(priv, &rdai->capture,  dai_np);
+                       for_each_child_of_node(node, dai_np) {
+                               __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i);
+                               if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) {
+                                       rdai = rsnd_rdai_get(priv, dai_i);
+
+                                       rsnd_parse_connect_simple(priv, &rdai->playback, dai_np);
+                                       rsnd_parse_connect_simple(priv, &rdai->capture,  dai_np);
+                               }
+                               dai_i++;
                        }
-                       dai_i++;
                }
        }
 
@@ -1922,6 +1967,7 @@ static int rsnd_probe(struct platform_device *pdev)
                rsnd_dai_probe,
        };
        int ret, i;
+       int ci;
 
        /*
         *      init priv data
@@ -1958,11 +2004,18 @@ static int rsnd_probe(struct platform_device *pdev)
        /*
         *      asoc register
         */
-       ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
-                                        priv->daidrv, rsnd_rdai_nr(priv));
-       if (ret < 0) {
-               dev_err(dev, "cannot snd dai register\n");
-               goto exit_snd_probe;
+       ci = 0;
+       for (i = 0; priv->component_dais[i] > 0; i++) {
+               int nr = priv->component_dais[i];
+
+               ret = devm_snd_soc_register_component(dev, &rsnd_soc_component,
+                                                     priv->daidrv + ci, nr);
+               if (ret < 0) {
+                       dev_err(dev, "cannot snd component register\n");
+                       goto exit_snd_probe;
+               }
+
+               ci += nr;
        }
 
        pm_runtime_enable(dev);
index 239705d5251744312a689897c8758acea8d153a7..43c0d675cc34335a69dce795a538868d749bc7d5 100644 (file)
@@ -545,6 +545,7 @@ struct rsnd_dai {
        struct rsnd_dai_stream capture;
        struct rsnd_priv *priv;
        struct snd_pcm_hw_constraint_list constraint;
+       struct of_phandle_args dai_args;
 
        int max_channels;       /* 2ch - 16ch */
        int ssi_lane;           /* 1lane - 4lane */
@@ -702,6 +703,9 @@ struct rsnd_priv {
        struct snd_soc_dai_driver *daidrv;
        struct rsnd_dai *rdai;
        int rdai_nr;
+
+#define RSND_MAX_COMPONENT 3
+       int component_dais[RSND_MAX_COMPONENT];
 };
 
 #define rsnd_priv_to_pdev(priv)        ((priv)->pdev)
index 142476f1396ff42646728906423a429f38439160..6d693b2ad5a35bee0a41b9709e40edb40a0392f5 100644 (file)
@@ -125,5 +125,78 @@ struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
 }
 EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
 
+#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
+                                 SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
+
+/* Check if all Slaves defined on the link can be found */
+bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev,
+                                       const struct snd_soc_acpi_link_adr *link,
+                                       struct sdw_extended_slave_id *ids,
+                                       int num_slaves)
+{
+       unsigned int part_id, link_id, unique_id, mfg_id, version;
+       int i, j, k;
+
+       for (i = 0; i < link->num_adr; i++) {
+               u64 adr = link->adr_d[i].adr;
+               int reported_part_count = 0;
+
+               mfg_id = SDW_MFG_ID(adr);
+               part_id = SDW_PART_ID(adr);
+               link_id = SDW_DISCO_LINK_ID(adr);
+               version = SDW_VERSION(adr);
+
+               for (j = 0; j < num_slaves; j++) {
+                       /* find out how many identical parts were reported on that link */
+                       if (ids[j].link_id == link_id &&
+                           ids[j].id.part_id == part_id &&
+                           ids[j].id.mfg_id == mfg_id &&
+                           ids[j].id.sdw_version == version)
+                               reported_part_count++;
+               }
+
+               for (j = 0; j < num_slaves; j++) {
+                       int expected_part_count = 0;
+
+                       if (ids[j].link_id != link_id ||
+                           ids[j].id.part_id != part_id ||
+                           ids[j].id.mfg_id != mfg_id ||
+                           ids[j].id.sdw_version != version)
+                               continue;
+
+                       /* find out how many identical parts are expected */
+                       for (k = 0; k < link->num_adr; k++) {
+                               u64 adr2 = link->adr_d[k].adr;
+
+                               if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
+                                       expected_part_count++;
+                       }
+
+                       if (reported_part_count == expected_part_count) {
+                               /*
+                                * we have to check unique id
+                                * if there is more than one
+                                * Slave on the link
+                                */
+                               unique_id = SDW_UNIQUE_ID(adr);
+                               if (reported_part_count == 1 ||
+                                   ids[j].id.unique_id == unique_id) {
+                                       dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id);
+                                       break;
+                               }
+                       } else {
+                               dev_dbg(dev, "part_id %#x reported %d expected %d on link %d, skipping\n",
+                                       part_id, reported_part_count, expected_part_count, link_id);
+                       }
+               }
+               if (j == num_slaves) {
+                       dev_dbg(dev, "Slave part_id %#x not found\n", part_id);
+                       return false;
+               }
+       }
+       return true;
+}
+EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("ALSA SoC ACPI module");
index 1a0bde23f5e6ff6283ba2d43bab6708fa8288d96..a5b96c17633ab9188a89e15a3fa525373e623be1 100644 (file)
@@ -238,6 +238,81 @@ static inline void snd_soc_debugfs_exit(void) { }
 
 #endif
 
+static int snd_soc_is_match_dai_args(struct of_phandle_args *args1,
+                                    struct of_phandle_args *args2)
+{
+       if (!args1 || !args2)
+               return 0;
+
+       if (args1->np != args2->np)
+               return 0;
+
+       for (int i = 0; i < args1->args_count; i++)
+               if (args1->args[i] != args2->args[i])
+                       return 0;
+
+       return 1;
+}
+
+static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+       return !(dlc->dai_args || dlc->name || dlc->of_node);
+}
+
+static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc)
+{
+       return (dlc->name && dlc->of_node);
+}
+
+static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc)
+{
+       return !(dlc->dai_args || dlc->dai_name);
+}
+
+static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc,
+                                  struct snd_soc_dai *dai)
+{
+       if (!dlc)
+               return 0;
+
+       if (dlc->dai_args)
+               return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args);
+
+       if (!dlc->dai_name)
+               return 1;
+
+       /* see snd_soc_dai_name_get() */
+
+       if (strcmp(dlc->dai_name, dai->name) == 0)
+               return 1;
+
+       if (dai->driver->name &&
+           strcmp(dai->driver->name, dlc->dai_name) == 0)
+               return 1;
+
+       if (dai->component->name &&
+           strcmp(dlc->dai_name, dai->component->name) == 0)
+               return 1;
+
+       return 0;
+}
+
+const char *snd_soc_dai_name_get(struct snd_soc_dai *dai)
+{
+       /* see snd_soc_is_matching_dai() */
+       if (dai->name)
+               return dai->name;
+
+       if (dai->driver->name)
+               return dai->driver->name;
+
+       if (dai->component->name)
+               return dai->component->name;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_name_get);
+
 static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd,
                                     struct snd_soc_component *component)
 {
@@ -734,6 +809,19 @@ static struct device_node
        return of_node;
 }
 
+struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, struct of_phandle_args *args)
+{
+       struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL);
+
+       if (!ret)
+               return NULL;
+
+       *ret = *args;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_copy_dai_args);
+
 static int snd_soc_is_matching_component(
        const struct snd_soc_dai_link_component *dlc,
        struct snd_soc_component *component)
@@ -743,6 +831,15 @@ static int snd_soc_is_matching_component(
        if (!dlc)
                return 0;
 
+       if (dlc->dai_args) {
+               struct snd_soc_dai *dai;
+
+               for_each_component_dais(component, dai)
+                       if (snd_soc_is_matching_dai(dlc, dai))
+                               return 1;
+               return 0;
+       }
+
        component_of_node = soc_component_to_node(component);
 
        if (dlc->of_node && component_of_node != dlc->of_node)
@@ -795,18 +892,11 @@ struct snd_soc_dai *snd_soc_find_dai(
        lockdep_assert_held(&client_mutex);
 
        /* Find CPU DAI from registered DAIs */
-       for_each_component(component) {
-               if (!snd_soc_is_matching_component(dlc, component))
-                       continue;
-               for_each_component_dais(component, dai) {
-                       if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)
-                           && (!dai->driver->name
-                               || strcmp(dai->driver->name, dlc->dai_name)))
-                               continue;
-
-                       return dai;
-               }
-       }
+       for_each_component(component)
+               if (snd_soc_is_matching_component(dlc, component))
+                       for_each_component_dais(component, dai)
+                               if (snd_soc_is_matching_dai(dlc, dai))
+                                       return dai;
 
        return NULL;
 }
@@ -829,102 +919,100 @@ static int soc_dai_link_sanity_check(struct snd_soc_card *card,
                                     struct snd_soc_dai_link *link)
 {
        int i;
-       struct snd_soc_dai_link_component *cpu, *codec, *platform;
+       struct snd_soc_dai_link_component *dlc;
 
-       for_each_link_codecs(link, i, codec) {
+       /* Codec check */
+       for_each_link_codecs(link, i, dlc) {
                /*
                 * Codec must be specified by 1 of name or OF node,
                 * not both or neither.
                 */
-               if (!!codec->name == !!codec->of_node) {
-                       dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
-                               link->name);
-                       return -EINVAL;
-               }
+               if (snd_soc_dlc_component_is_invalid(dlc))
+                       goto component_invalid;
+
+               if (snd_soc_dlc_component_is_empty(dlc))
+                       goto component_empty;
 
                /* Codec DAI name must be specified */
-               if (!codec->dai_name) {
-                       dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
-                               link->name);
-                       return -EINVAL;
-               }
+               if (snd_soc_dlc_dai_is_empty(dlc))
+                       goto dai_empty;
 
                /*
                 * Defer card registration if codec component is not added to
                 * component list.
                 */
-               if (!soc_find_component(codec)) {
-                       dev_dbg(card->dev,
-                               "ASoC: codec component %s not found for link %s\n",
-                               codec->name, link->name);
-                       return -EPROBE_DEFER;
-               }
+               if (!soc_find_component(dlc))
+                       goto component_not_find;
        }
 
-       for_each_link_platforms(link, i, platform) {
+       /* Platform check */
+       for_each_link_platforms(link, i, dlc) {
                /*
                 * Platform may be specified by either name or OF node, but it
                 * can be left unspecified, then no components will be inserted
                 * in the rtdcom list
                 */
-               if (!!platform->name == !!platform->of_node) {
-                       dev_err(card->dev,
-                               "ASoC: Neither/both platform name/of_node are set for %s\n",
-                               link->name);
-                       return -EINVAL;
-               }
+               if (snd_soc_dlc_component_is_invalid(dlc))
+                       goto component_invalid;
+
+               if (snd_soc_dlc_component_is_empty(dlc))
+                       goto component_empty;
 
                /*
                 * Defer card registration if platform component is not added to
                 * component list.
                 */
-               if (!soc_find_component(platform)) {
-                       dev_dbg(card->dev,
-                               "ASoC: platform component %s not found for link %s\n",
-                               platform->name, link->name);
-                       return -EPROBE_DEFER;
-               }
+               if (!soc_find_component(dlc))
+                       goto component_not_find;
        }
 
-       for_each_link_cpus(link, i, cpu) {
+       /* CPU check */
+       for_each_link_cpus(link, i, dlc) {
                /*
                 * CPU device may be specified by either name or OF node, but
                 * can be left unspecified, and will be matched based on DAI
                 * name alone..
                 */
-               if (cpu->name && cpu->of_node) {
-                       dev_err(card->dev,
-                               "ASoC: Neither/both cpu name/of_node are set for %s\n",
-                               link->name);
-                       return -EINVAL;
-               }
+               if (snd_soc_dlc_component_is_invalid(dlc))
+                       goto component_invalid;
 
-               /*
-                * Defer card registration if cpu dai component is not added to
-                * component list.
-                */
-               if ((cpu->of_node || cpu->name) &&
-                   !soc_find_component(cpu)) {
-                       dev_dbg(card->dev,
-                               "ASoC: cpu component %s not found for link %s\n",
-                               cpu->name, link->name);
-                       return -EPROBE_DEFER;
-               }
 
-               /*
-                * At least one of CPU DAI name or CPU device name/node must be
-                * specified
-                */
-               if (!cpu->dai_name &&
-                   !(cpu->name || cpu->of_node)) {
-                       dev_err(card->dev,
-                               "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
-                               link->name);
-                       return -EINVAL;
+               if (snd_soc_dlc_component_is_empty(dlc)) {
+                       /*
+                        * At least one of CPU DAI name or CPU device name/node must be specified
+                        */
+                       if (snd_soc_dlc_dai_is_empty(dlc))
+                               goto component_dai_empty;
+               } else {
+                       /*
+                        * Defer card registration if Component is not added
+                        */
+                       if (!soc_find_component(dlc))
+                               goto component_not_find;
                }
        }
 
        return 0;
+
+component_invalid:
+       dev_err(card->dev, "ASoC: Both Component name/of_node are set for %s\n", link->name);
+       return -EINVAL;
+
+component_empty:
+       dev_err(card->dev, "ASoC: Neither Component name/of_node are set for %s\n", link->name);
+       return -EINVAL;
+
+component_not_find:
+       dev_err(card->dev, "ASoC: Component %s not found for link %s\n", dlc->name, link->name);
+       return -EPROBE_DEFER;
+
+dai_empty:
+       dev_err(card->dev, "ASoC: DAI name is not set for %s\n", link->name);
+       return -EINVAL;
+
+component_dai_empty:
+       dev_err(card->dev, "ASoC: Neither DAI/Component name/of_node are set for %s\n", link->name);
+       return -EINVAL;
 }
 
 /**
@@ -2930,6 +3018,14 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot);
 
+void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms,
+                                    struct snd_soc_dai_link_component *cpus)
+{
+       platforms->of_node      = cpus->of_node;
+       platforms->dai_args     = cpus->dai_args;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform);
+
 void snd_soc_of_parse_node_prefix(struct device_node *np,
                                  struct snd_soc_codec_conf *codec_conf,
                                  struct device_node *of_node,
@@ -3235,11 +3331,12 @@ EXPORT_SYMBOL_GPL(snd_soc_get_stream_cpu);
 int snd_soc_get_dai_id(struct device_node *ep)
 {
        struct snd_soc_component *component;
-       struct snd_soc_dai_link_component dlc;
+       struct snd_soc_dai_link_component dlc = {
+               .of_node = of_graph_get_port_parent(ep),
+       };
        int ret;
 
-       dlc.of_node     = of_graph_get_port_parent(ep);
-       dlc.name        = NULL;
+
        /*
         * For example HDMI case, HDMI has video/sound port,
         * but ALSA SoC needs sound port number only.
@@ -3264,8 +3361,6 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
        struct snd_soc_component *pos;
        int ret = -EPROBE_DEFER;
 
-       dlc->of_node = args->np;
-
        mutex_lock(&client_mutex);
        for_each_component(pos) {
                struct device_node *component_of_node = soc_component_to_node(pos);
@@ -3304,9 +3399,7 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
                                id--;
                        }
 
-                       dlc->dai_name   = dai->driver->name;
-                       if (!dlc->dai_name)
-                               dlc->dai_name = pos->name;
+                       dlc->dai_name   = snd_soc_dai_name_get(dai);
                } else if (ret) {
                        /*
                         * if another error than ENOTSUPP is returned go on and
@@ -3319,6 +3412,10 @@ int snd_soc_get_dlc(const struct of_phandle_args *args, struct snd_soc_dai_link_
 
                break;
        }
+
+       if (ret == 0)
+               dlc->of_node = args->np;
+
        mutex_unlock(&client_mutex);
        return ret;
 }
@@ -3370,6 +3467,24 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
 
+struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args)
+{
+       struct snd_soc_dai *dai;
+       struct snd_soc_component *component;
+
+       mutex_lock(&client_mutex);
+       for_each_component(component) {
+               for_each_component_dais(component, dai)
+                       if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args))
+                               goto found;
+       }
+       dai = NULL;
+found:
+       mutex_unlock(&client_mutex);
+       return dai;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args);
+
 static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component)
 {
        if (component->of_node) {
index 02dd64dea17925b45c69654f99ef7399674604b8..3f33f0630ad8aaae032268ce68c405f6c85e120b 100644 (file)
@@ -424,6 +424,9 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
 {
        int ret = 0;
 
+       if (!snd_soc_dai_stream_valid(dai, substream->stream))
+               return 0;
+
        if (dai->driver->ops &&
            dai->driver->ops->startup)
                ret = dai->driver->ops->startup(substream, dai);
@@ -439,6 +442,9 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
                          struct snd_pcm_substream *substream,
                          int rollback)
 {
+       if (!snd_soc_dai_stream_valid(dai, substream->stream))
+               return;
+
        if (rollback && !soc_dai_mark_match(dai, substream, startup))
                return;
 
@@ -454,8 +460,9 @@ int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
                             struct snd_soc_pcm_runtime *rtd, int num)
 {
        int ret = -ENOTSUPP;
-       if (dai->driver->compress_new)
-               ret = dai->driver->compress_new(rtd, num);
+       if (dai->driver->ops &&
+           dai->driver->ops->compress_new)
+               ret = dai->driver->ops->compress_new(rtd, num);
        return soc_dai_ret(dai, ret);
 }
 
@@ -539,19 +546,20 @@ int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
        int i;
 
        for_each_rtd_dais(rtd, i, dai) {
-               if (dai->driver->probe_order != order)
-                       continue;
-
                if (dai->probed)
                        continue;
 
-               if (dai->driver->probe) {
-                       int ret = dai->driver->probe(dai);
+               if (dai->driver->ops) {
+                       if (dai->driver->ops->probe_order != order)
+                               continue;
 
-                       if (ret < 0)
-                               return soc_dai_ret(dai, ret);
-               }
+                       if (dai->driver->ops->probe) {
+                               int ret = dai->driver->ops->probe(dai);
 
+                               if (ret < 0)
+                                       return soc_dai_ret(dai, ret);
+                       }
+               }
                dai->probed = 1;
        }
 
@@ -564,16 +572,19 @@ int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
        int i, r, ret = 0;
 
        for_each_rtd_dais(rtd, i, dai) {
-               if (dai->driver->remove_order != order)
+               if (!dai->probed)
                        continue;
 
-               if (dai->probed &&
-                   dai->driver->remove) {
-                       r = dai->driver->remove(dai);
-                       if (r < 0)
-                               ret = r; /* use last error */
-               }
+               if (dai->driver->ops) {
+                       if (dai->driver->ops->remove_order != order)
+                               continue;
 
+                       if (dai->driver->ops->remove) {
+                               r = dai->driver->ops->remove(dai);
+                               if (r < 0)
+                                       ret = r; /* use last error */
+                       }
+               }
                dai->probed = 0;
        }
 
@@ -586,8 +597,9 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
        int i;
 
        for_each_rtd_dais(rtd, i, dai) {
-               if (dai->driver->pcm_new) {
-                       int ret = dai->driver->pcm_new(rtd, dai);
+               if (dai->driver->ops &&
+                   dai->driver->ops->pcm_new) {
+                       int ret = dai->driver->ops->pcm_new(rtd, dai);
                        if (ret < 0)
                                return soc_dai_ret(dai, ret);
                }
@@ -603,6 +615,8 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
        int i, ret;
 
        for_each_rtd_dais(rtd, i, dai) {
+               if (!snd_soc_dai_stream_valid(dai, substream->stream))
+                       continue;
                if (dai->driver->ops &&
                    dai->driver->ops->prepare) {
                        ret = dai->driver->ops->prepare(substream, dai);
@@ -619,6 +633,9 @@ static int soc_dai_trigger(struct snd_soc_dai *dai,
 {
        int ret = 0;
 
+       if (!snd_soc_dai_stream_valid(dai, substream->stream))
+               return 0;
+
        if (dai->driver->ops &&
            dai->driver->ops->trigger)
                ret = dai->driver->ops->trigger(substream, cmd, dai);
index 3091e8160bad77c22255e2655273051601994fee..f07e836783737ba4d54c948a88f103483853de9e 100644 (file)
@@ -916,6 +916,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
                                return -EINVAL;
                        }
                }
+               if (w->no_wname_in_kcontrol_name)
+                       wname_in_long_name = false;
 
                if (wname_in_long_name && kcname_in_long_name) {
                        /*
index f951acb2ce362a82ccaf4b247909cadce3194183..b2cc13b9c77b78b08b5a1f63a4cb25441b4a5edf 100644 (file)
@@ -37,7 +37,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        struct snd_soc_jack_pin *pin;
        unsigned int sync = 0;
 
-       if (!jack)
+       if (!jack || !jack->jack)
                return;
        trace_snd_soc_jack_report(jack, mask, status);
 
index 8896227e4fb76000dec354b6ddf7af6431684900..3aa6b988cb4b492faf801434302cc28f844adf6c 100644 (file)
@@ -38,6 +38,7 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd,
        switch (ret) {
        case -EPROBE_DEFER:
        case -ENOTSUPP:
+       case -EINVAL:
                break;
        default:
                dev_err(rtd->dev,
@@ -2466,8 +2467,11 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
 
        /* there is no point preparing this FE if there are no BEs */
        if (list_empty(&fe->dpcm[stream].be_clients)) {
-               dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
-                               fe->dai_link->name);
+               /* dev_err_once() for visibility, dev_dbg() for debugging UCM profiles */
+               dev_err_once(fe->dev, "ASoC: no backend DAIs enabled for %s, possibly missing ALSA mixer-based routing or UCM profile\n",
+                            fe->dai_link->name);
+               dev_dbg(fe->dev, "ASoC: no backend DAIs enabled for %s\n",
+                       fe->dai_link->name);
                ret = -EINVAL;
                goto out;
        }
index ad08d4f75a7b4913fa91a4c671814b7fafbbe0d5..e783055b6c3afa7d589e762cce76e870ce4f7144 100644 (file)
@@ -1560,6 +1560,10 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
                        1 : 0;
 }
 
+static const struct snd_soc_dai_ops tplg_dai_ops = {
+       .compress_new   = snd_soc_new_compress,
+};
+
 static int soc_tplg_dai_create(struct soc_tplg *tplg,
        struct snd_soc_tplg_pcm *pcm)
 {
@@ -1601,7 +1605,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        }
 
        if (pcm->compress)
-               dai_drv->compress_new = snd_soc_new_compress;
+               dai_drv->ops = &tplg_dai_ops;
 
        /* pass control to component driver for optional further init */
        ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
index 1cb92d6030e339f923e07c2355d597e2c1c29e46..f2faa08f0c0e05708f872db1082d718800ad0cbf 100644 (file)
@@ -2,7 +2,7 @@
 # This file is provided under a dual BSD/GPLv2 license. When using or
 # redistributing this file, you may do so under either license.
 #
-# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
 
 config SND_SOC_SOF_AMD_TOPLEVEL
        tristate "SOF support for AMD audio DSPs"
@@ -21,6 +21,7 @@ config SND_SOC_SOF_AMD_COMMON
        select SND_SOC_SOF_PCI_DEV
        select SND_AMD_ACP_CONFIG
        select SND_SOC_SOF_XTENSA
+       select SND_SOC_SOF_ACP_PROBES
        select SND_SOC_ACPI if ACPI
        help
          This option is not user-selectable but automatically handled by
@@ -33,6 +34,16 @@ config SND_SOC_SOF_AMD_RENOIR
        help
          Select this option for SOF support on AMD Renoir platform
 
+config SND_SOC_SOF_AMD_VANGOGH
+       tristate "SOF support for VANGOGH"
+       depends on SND_SOC_SOF_PCI
+       select SND_SOC_SOF_AMD_COMMON
+       help
+         Select this option for SOF support
+         on AMD Vangogh platform.
+         Say Y if you want to enable SOF on Vangogh.
+         If unsure select "N".
+
 config SND_SOC_SOF_AMD_REMBRANDT
        tristate "SOF support for REMBRANDT"
        depends on SND_SOC_SOF_PCI
@@ -42,4 +53,11 @@ config SND_SOC_SOF_AMD_REMBRANDT
          Say Y if you want to enable SOF on Rembrandt.
          If unsure select "N".
 
+config SND_SOC_SOF_ACP_PROBES
+       tristate
+       select SND_SOC_SOF_DEBUG_PROBES
+       help
+         This option is not user-selectable but automatically handled by
+         'select' statements at a higher level
+
 endif
index 5626d13b3e69c4136c457211123d62b2d089bf6a..f3b375e67a6fbf7dc916ba6282bb45e6c1f0c460 100644 (file)
@@ -2,12 +2,15 @@
 # This file is provided under a dual BSD/GPLv2 license. When using or
 # redistributing this file, you may do so under either license.
 #
-# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+# Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
 
 snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o
+snd-sof-amd-acp-$(CONFIG_SND_SOC_SOF_ACP_PROBES) = acp-probes.o
 snd-sof-amd-renoir-objs := pci-rn.o renoir.o
 snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o
+snd-sof-amd-vangogh-objs := pci-vangogh.o vangogh.o
 
 obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
 obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o
 obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) +=snd-sof-amd-vangogh.o
index df36b411a12e66eb0e0bb8a4ab84a13775470491..3a0c7688dcfe6593faead43b70f0598dc54be176 100644 (file)
@@ -196,6 +196,10 @@ struct snd_sof_dsp_ops sof_acp_common_ops = {
        .dbg_dump               = amd_sof_dump,
        .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
        .dsp_arch_ops = &sof_xtensa_arch_ops,
+
+       /* probe client device registation */
+       .register_ipc_clients = acp_probes_register,
+       .unregister_ipc_clients = acp_probes_unregister,
 };
 EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON);
 
index 920155dee819b508c21116034ec3b45e8d56240e..a913f1cc4c80970400f6bfa2da24524b1e4bc6bd 100644 (file)
@@ -3,7 +3,7 @@
  * This file is provided under a dual BSD/GPLv2 license. When using or
  * redistributing this file, you may do so under either license.
  *
- * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
  *
  * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
  */
 #define ACP_CONTROL                            0x1004
 
 #define ACP3X_I2S_PIN_CONFIG                   0x1400
+#define ACP5X_I2S_PIN_CONFIG                   0x1400
 #define ACP6X_I2S_PIN_CONFIG                   0x1440
 
 /* Registers offsets from ACP_PGFSM block */
 #define ACP3X_PGFSM_BASE                       0x141C
+#define ACP5X_PGFSM_BASE                       0x1424
 #define ACP6X_PGFSM_BASE                        0x1024
 #define PGFSM_CONTROL_OFFSET                   0x0
 #define PGFSM_STATUS_OFFSET                    0x4
 #define ACP3X_CLKMUX_SEL                       0x1424
+#define ACP5X_CLKMUX_SEL                       0x142C
 #define ACP6X_CLKMUX_SEL                       0x102C
 
 /* Registers from ACP_INTR block */
 #define ACP3X_EXT_INTR_STAT                    0x1808
+#define ACP5X_EXT_INTR_STAT                    0x1808
 #define ACP6X_EXT_INTR_STAT                     0x1A0C
 
 #define ACP3X_DSP_SW_INTR_BASE                 0x1814
+#define ACP5X_DSP_SW_INTR_BASE                 0x1814
 #define ACP6X_DSP_SW_INTR_BASE                  0x1808
 #define DSP_SW_INTR_CNTL_OFFSET                        0x0
 #define DSP_SW_INTR_STAT_OFFSET                        0x4
 #define DSP_SW_INTR_TRIG_OFFSET                        0x8
 #define ACP_ERROR_STATUS                       0x18C4
 #define ACP3X_AXI2DAGB_SEM_0                   0x1880
+#define ACP5X_AXI2DAGB_SEM_0                   0x1884
 #define ACP6X_AXI2DAGB_SEM_0                   0x1874
 
 /* Registers from ACP_SHA block */
@@ -81,6 +87,7 @@
 #define ACP_SHA_DMA_CMD_STS                    0x1CC0
 #define ACP_SHA_DMA_ERR_STATUS                 0x1CC4
 #define ACP_SHA_TRANSFER_BYTE_CNT              0x1CC8
+#define ACP_SHA_DMA_INCLUDE_HDR         0x1CCC
 #define ACP_SHA_PSP_ACK                         0x1C74
 
 #define ACP_SCRATCH_REG_0                      0x10000
index 8a0fc635a997c4105de05777299ea2679a7cd0c8..81a2c096a1858beefba3d2d60cd95b3385160b6b 100644 (file)
@@ -155,6 +155,8 @@ out:
 irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
 {
        struct snd_sof_dev *sdev = context;
+       const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+       struct acp_dev_data *adata = sdev->pdata->hw_pdata;
        unsigned int dsp_msg_write = sdev->debug_box.offset +
                                     offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
        unsigned int dsp_ack_write = sdev->debug_box.offset +
@@ -200,6 +202,30 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
                return IRQ_HANDLED;
        }
 
+       if (desc->probe_reg_offset) {
+               u32 val;
+               u32 posn;
+
+               /* Probe register consists of two parts
+                * (0-30) bit has cumulative position value
+                * 31 bit is a synchronization flag between DSP and CPU
+                * for the position update
+                */
+               val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->probe_reg_offset);
+               if (val & PROBE_STATUS_BIT) {
+                       posn = val & ~PROBE_STATUS_BIT;
+                       if (adata->probe_stream) {
+                               /* Probe related posn value is of 31 bits limited to 2GB
+                                * once wrapped DSP won't send posn interrupt.
+                                */
+                               adata->probe_stream->cstream_posn = posn;
+                               snd_compr_fragment_elapsed(adata->probe_stream->cstream);
+                               snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->probe_reg_offset, posn);
+                               ipc_irq = true;
+                       }
+               }
+       }
+
        if (!ipc_irq)
                dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
 
index a4bce5a3ae482b82fc947b07b24b4ac74450a2d9..a63c00b53a5eec4bf585d567534b54ce43ba8e3f 100644 (file)
@@ -3,7 +3,7 @@
 // This file is provided under a dual BSD/GPLv2 license. When using or
 // redistributing this file, you may do so under either license.
 //
-// Copyright(c) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
 //
 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
 
@@ -158,7 +158,11 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
        int ret;
 
        adata = sdev->pdata->hw_pdata;
-       size_fw = adata->fw_bin_size;
+
+       if (adata->signed_fw_image)
+               size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
+       else
+               size_fw = adata->fw_bin_size;
 
        page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
        adata->fw_bin_page_count = page_count;
@@ -219,3 +223,34 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev)
        return 0;
 }
 EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON);
+
+int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
+{
+       struct snd_sof_pdata *plat_data = sdev->pdata;
+       struct acp_dev_data *adata = plat_data->hw_pdata;
+       int ret;
+
+       ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev);
+       if (ret < 0) {
+               dev_err(sdev->dev, "sof signed firmware code bin is missing\n");
+               return ret;
+       } else {
+               dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin);
+       }
+       ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
+                                     (void *)sdev->basefw.fw->data, sdev->basefw.fw->size);
+
+       ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev);
+       if (ret < 0) {
+               dev_err(sdev->dev, "sof signed firmware data bin is missing\n");
+               return ret;
+
+       } else {
+               dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin);
+       }
+
+       ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
+                                     (void *)adata->fw_dbin->data, adata->fw_dbin->size);
+       return ret;
+}
+EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON);
diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c
new file mode 100644 (file)
index 0000000..778cf1a
--- /dev/null
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: V Sujith Kumar Reddy <Vsujithkumar.Reddy@amd.com>
+
+/*
+ * Probe interface for generic AMD audio ACP DSP block
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include "../sof-priv.h"
+#include "../sof-client-probes.h"
+#include "../sof-client.h"
+#include "../ops.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+static int acp_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 acp_dsp_stream *stream;
+       struct acp_dev_data *adata;
+
+       adata = sdev->pdata->hw_pdata;
+       stream = acp_dsp_stream_get(sdev, 0);
+       if (!stream)
+               return -ENODEV;
+
+       stream->cstream = cstream;
+       cstream->runtime->private_data = stream;
+
+       adata->probe_stream = stream;
+       *stream_id = stream->stream_tag;
+
+       return 0;
+}
+
+static int acp_probes_compr_shutdown(struct sof_client_dev *cdev,
+                                    struct snd_compr_stream *cstream,
+                                    struct snd_soc_dai *dai)
+{
+       struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+       struct acp_dsp_stream *stream = cstream->runtime->private_data;
+       struct acp_dev_data *adata;
+       int ret;
+
+       ret = acp_dsp_stream_put(sdev, stream);
+       if (ret < 0) {
+               dev_err(sdev->dev, "Failed to release probe compress stream\n");
+               return ret;
+       }
+
+       adata = sdev->pdata->hw_pdata;
+       stream->cstream = NULL;
+       cstream->runtime->private_data = NULL;
+       adata->probe_stream = NULL;
+
+       return 0;
+}
+
+static int acp_probes_compr_set_params(struct sof_client_dev *cdev,
+                                      struct snd_compr_stream *cstream,
+                                      struct snd_compr_params *params,
+                                      struct snd_soc_dai *dai)
+{
+       struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
+       struct acp_dsp_stream *stream = cstream->runtime->private_data;
+       unsigned int buf_offset, index;
+       u32 size;
+       int ret;
+
+       stream->dmab = cstream->runtime->dma_buffer_p;
+       stream->num_pages = PFN_UP(cstream->runtime->dma_bytes);
+       size = cstream->runtime->buffer_size;
+
+       ret = acp_dsp_stream_config(sdev, stream);
+       if (ret < 0) {
+               acp_dsp_stream_put(sdev, stream);
+               return ret;
+       }
+
+       /* write buffer size of stream in scratch memory */
+
+       buf_offset = sdev->debug_box.offset +
+                    offsetof(struct scratch_reg_conf, buf_size);
+       index = stream->stream_tag - 1;
+       buf_offset = buf_offset + index * 4;
+
+       snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + buf_offset, size);
+
+       return 0;
+}
+
+static int acp_probes_compr_trigger(struct sof_client_dev *cdev,
+                                   struct snd_compr_stream *cstream,
+                                   int cmd, struct snd_soc_dai *dai)
+{
+       /* Nothing to do here, as it is a mandatory callback just defined */
+       return 0;
+}
+
+static int acp_probes_compr_pointer(struct sof_client_dev *cdev,
+                                   struct snd_compr_stream *cstream,
+                                   struct snd_compr_tstamp *tstamp,
+                                   struct snd_soc_dai *dai)
+{
+       struct acp_dsp_stream *stream = cstream->runtime->private_data;
+       struct snd_soc_pcm_stream *pstream;
+
+       pstream = &dai->driver->capture;
+       tstamp->copied_total = stream->cstream_posn;
+       tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
+
+       return 0;
+}
+
+/* SOF client implementation */
+static const struct sof_probes_host_ops acp_probes_ops = {
+       .startup = acp_probes_compr_startup,
+       .shutdown = acp_probes_compr_shutdown,
+       .set_params = acp_probes_compr_set_params,
+       .trigger = acp_probes_compr_trigger,
+       .pointer = acp_probes_compr_pointer,
+};
+
+int acp_probes_register(struct snd_sof_dev *sdev)
+{
+       return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops,
+                                      sizeof(acp_probes_ops));
+}
+EXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON);
+
+void acp_probes_unregister(struct snd_sof_dev *sdev)
+{
+       sof_client_dev_unregister(sdev, "acp-probes", 0);
+}
+EXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON);
+
+MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
+
index afb505461ea1795bb1e8e807519e27eddc2058b1..b2e00a10a03e70e8574adb87f09959749ee81e38 100644 (file)
@@ -3,7 +3,7 @@
 // This file is provided under a dual BSD/GPLv2 license. When using or
 // redistributing this file, you may do so under either license.
 //
-// Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
 //
 // Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
 //         Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
 #include "acp.h"
 #include "acp-dsp-offset.h"
 
+#define SECURED_FIRMWARE 1
+
+const struct dmi_system_id acp_sof_quirk_table[] = {
+       {
+               /* Valve Jupiter device */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
+                       DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"),
+               },
+               .driver_data = (void *)SECURED_FIRMWARE,
+       },
+       {}
+};
+EXPORT_SYMBOL_GPL(acp_sof_quirk_table);
+
 static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
 {
        pci_write_config_dword(dev, 0x60, smn_addr);
@@ -28,12 +44,14 @@ static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
        return 0;
 }
 
-static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data)
+static int smn_read(struct pci_dev *dev, u32 smn_addr)
 {
+       u32 data = 0;
+
        pci_write_config_dword(dev, 0x60, smn_addr);
-       pci_read_config_dword(dev, 0x64, data);
+       pci_read_config_dword(dev, 0x64, &data);
 
-       return 0;
+       return data;
 }
 
 static void init_dma_descriptor(struct acp_dev_data *adata)
@@ -150,15 +168,13 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
 static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
 {
        struct snd_sof_dev *sdev = adata->dev;
-       int timeout;
+       int ret;
        u32 data;
 
-       for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
-               msleep(20);
-               smn_read(adata->smn_dev, MP0_C2PMSG_114_REG, &data);
-               if (data & MBOX_READY_MASK)
-                       return 0;
-       }
+       ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US,
+                               ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG);
+       if (!ret)
+               return 0;
 
        dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK);
 
@@ -177,23 +193,19 @@ static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
 static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
 {
        struct snd_sof_dev *sdev = adata->dev;
-       int ret, timeout;
+       int ret;
        u32 data;
 
        if (!cmd)
                return -EINVAL;
 
        /* Get a non-zero Doorbell value from PSP */
-       for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
-               msleep(MBOX_DELAY);
-               smn_read(adata->smn_dev, MP0_C2PMSG_73_REG, &data);
-               if (data)
-                       break;
-       }
+       ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false,
+                               adata->smn_dev, MP0_C2PMSG_73_REG);
 
-       if (!timeout) {
+       if (ret) {
                dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG);
-               return -EINVAL;
+               return ret;
        }
 
        /* Check if PSP is ready for new command */
@@ -239,6 +251,9 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
                }
        }
 
+       if (adata->signed_fw_image)
+               snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER);
+
        snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
        snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_DESTINATION_ADDR, dest_addr);
        snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_MSG_LENGTH, image_length);
@@ -469,8 +484,10 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
 int amd_sof_acp_probe(struct snd_sof_dev *sdev)
 {
        struct pci_dev *pci = to_pci_dev(sdev->dev);
+       struct snd_sof_pdata *plat_data = sdev->pdata;
        struct acp_dev_data *adata;
        const struct sof_amd_acp_desc *chip;
+       const struct dmi_system_id *dmi_id;
        unsigned int addr;
        int ret;
 
@@ -531,6 +548,20 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
        sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
        sdev->debug_box.size = BOX_SIZE_1024;
 
+       adata->signed_fw_image = false;
+       dmi_id = dmi_first_match(acp_sof_quirk_table);
+       if (dmi_id && dmi_id->driver_data) {
+               adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin",
+                                              plat_data->fw_filename_prefix,
+                                              chip->name);
+               adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin",
+                                              plat_data->fw_filename_prefix,
+                                              chip->name);
+               adata->signed_fw_image = dmi_id->driver_data;
+
+               dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin,
+                       adata->fw_data_bin);
+       }
        acp_memory_init(sdev);
 
        acp_dsp_stream_init(sdev);
index dc624f727aa37593da3311126a8e799735a5fe5c..19cad4fcf99a38d8722794ffdf699d068f15474b 100644 (file)
@@ -3,7 +3,7 @@
  * This file is provided under a dual BSD/GPLv2 license. When using or
  * redistributing this file, you may do so under either license.
  *
- * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright(c) 2021, 2023 Advanced Micro Devices, Inc. All rights reserved.
  *
  * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
  */
@@ -11,6 +11,8 @@
 #ifndef __SOF_AMD_ACP_H
 #define __SOF_AMD_ACP_H
 
+#include <linux/dmi.h>
+
 #include "../sof-priv.h"
 #include "../sof-audio.h"
 
@@ -32,6 +34,7 @@
 
 #define ACP_DSP_INTR_EN_MASK                   0x00000001
 #define ACP3X_SRAM_PTE_OFFSET                  0x02050000
+#define ACP5X_SRAM_PTE_OFFSET                  0x02050000
 #define ACP6X_SRAM_PTE_OFFSET                  0x03800000
 #define PAGE_SIZE_4K_ENABLE                    0x2
 #define ACP_PAGE_SIZE                          0x1000
@@ -40,6 +43,7 @@
 #define DSP_FW_RUN_ENABLE                      0x01
 #define ACP_SHA_RUN                            0x01
 #define ACP_SHA_RESET                          0x02
+#define ACP_SHA_HEADER                         0x01
 #define ACP_DMA_CH_RST                         0x01
 #define ACP_DMA_CH_GRACEFUL_RST_EN             0x10
 #define ACP_ATU_CACHE_INVALID                  0x01
 #define ACP_DSP_TO_HOST_IRQ                    0x04
 
 #define ACP_RN_PCI_ID                          0x01
+#define ACP_VANGOGH_PCI_ID                     0x50
 #define ACP_RMB_PCI_ID                         0x6F
 
 #define HOST_BRIDGE_CZN                                0x1630
+#define HOST_BRIDGE_VGH                                0x1645
 #define HOST_BRIDGE_RMB                                0x14B5
 #define ACP_SHA_STAT                           0x8000
-#define ACP_PSP_TIMEOUT_COUNTER                        5
+#define ACP_PSP_TIMEOUT_US                     1000000
 #define ACP_EXT_INTR_ERROR_STAT                        0x20000000
 #define MP0_C2PMSG_114_REG                     0x3810AC8
 #define MP0_C2PMSG_73_REG                      0x3810A24
 #define MBOX_ACP_SHA_DMA_COMMAND               0x70000
-#define MBOX_DELAY                             1000
+#define MBOX_DELAY_US                          1000
 #define MBOX_READY_MASK                                0x80000000
 #define MBOX_STATUS_MASK                       0xFFFF
 
@@ -77,6 +83,9 @@
 #define AMD_STACK_DUMP_SIZE                    32
 
 #define SRAM1_SIZE                             0x13A000
+#define PROBE_STATUS_BIT                       BIT(31)
+
+#define ACP_FIRMWARE_SIGNATURE                 0x100
 
 enum clock_source {
        ACP_CLOCK_96M = 0,
@@ -156,10 +165,13 @@ struct acp_dsp_stream {
        int active;
        unsigned int reg_offset;
        size_t posn_offset;
+       struct snd_compr_stream *cstream;
+       u64 cstream_posn;
 };
 
 struct sof_amd_acp_desc {
        unsigned int rev;
+       const char *name;
        unsigned int host_bridge_id;
        u32 pgfsm_base;
        u32 ext_intr_stat;
@@ -168,24 +180,30 @@ struct sof_amd_acp_desc {
        u32 hw_semaphore_offset;
        u32 acp_clkmux_sel;
        u32 fusion_dsp_offset;
+       u32 probe_reg_offset;
 };
 
 /* Common device data struct for ACP devices */
 struct acp_dev_data {
        struct snd_sof_dev  *dev;
+       const struct firmware *fw_dbin;
        /* DMIC device */
        struct platform_device *dmic_dev;
        unsigned int fw_bin_size;
        unsigned int fw_data_bin_size;
+       const char *fw_code_bin;
+       const char *fw_data_bin;
        u32 fw_bin_page_count;
        dma_addr_t sha_dma_addr;
        u8 *bin_buf;
        dma_addr_t dma_addr;
        u8 *data_buf;
+       bool signed_fw_image;
        struct dma_descriptor dscr_info[ACP_MAX_DESC];
        struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
        struct acp_dsp_stream *dtrace_stream;
        struct pci_dev *smn_dev;
+       struct acp_dsp_stream *probe_stream;
 };
 
 void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -205,6 +223,7 @@ int amd_sof_acp_remove(struct snd_sof_dev *sdev);
 /* DSP Loader callbacks */
 int acp_sof_dsp_run(struct snd_sof_dev *sdev);
 int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev);
+int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev);
 int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type);
 
 /* Block IO callbacks */
@@ -248,6 +267,8 @@ extern struct snd_sof_dsp_ops sof_acp_common_ops;
 
 extern struct snd_sof_dsp_ops sof_renoir_ops;
 int sof_renoir_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_vangogh_ops;
+int sof_vangogh_ops_init(struct snd_sof_dev *sdev);
 extern struct snd_sof_dsp_ops sof_rembrandt_ops;
 int sof_rembrandt_ops_init(struct snd_sof_dev *sdev);
 
@@ -273,4 +294,10 @@ static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata
 
        return desc->chip_info;
 }
+
+int acp_probes_register(struct snd_sof_dev *sdev);
+void acp_probes_unregister(struct snd_sof_dev *sdev);
+
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[];
+extern const struct dmi_system_id acp_sof_quirk_table[];
 #endif
index 58b3092425f1af1aa96f71219b2bcbbf0b3b139f..9935e457b467b02b1609e31c40ab3a0e480719af 100644 (file)
@@ -25,6 +25,7 @@
 
 #define ACP6x_REG_START                0x1240000
 #define ACP6x_REG_END          0x125C000
+#define ACP6X_FUTURE_REG_ACLK_0        0x1854
 
 static const struct sof_amd_acp_desc rembrandt_chip_info = {
        .rev            = 6,
@@ -36,6 +37,7 @@ static const struct sof_amd_acp_desc rembrandt_chip_info = {
        .hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
        .acp_clkmux_sel = ACP6X_CLKMUX_SEL,
        .fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
+       .probe_reg_offset = ACP6X_FUTURE_REG_ACLK_0,
 };
 
 static const struct sof_dev_desc rembrandt_desc = {
index 7409e21ce5aa78ebbcec6b61f81025898593efbf..c72d5d8aff8e6aeb80f96e06a947618bff80cb38 100644 (file)
@@ -25,6 +25,7 @@
 
 #define ACP3x_REG_START                0x1240000
 #define ACP3x_REG_END          0x125C000
+#define ACP3X_FUTURE_REG_ACLK_0        0x1860
 
 static const struct sof_amd_acp_desc renoir_chip_info = {
        .rev            = 3,
@@ -35,6 +36,7 @@ static const struct sof_amd_acp_desc renoir_chip_info = {
        .sram_pte_offset = ACP3X_SRAM_PTE_OFFSET,
        .hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0,
        .acp_clkmux_sel = ACP3X_CLKMUX_SEL,
+       .probe_reg_offset = ACP3X_FUTURE_REG_ACLK_0,
 };
 
 static const struct sof_dev_desc renoir_desc = {
diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c
new file mode 100644 (file)
index 0000000..d8be42f
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com>
+
+/*.
+ * PCI interface for Vangogh ACP device
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <sound/sof.h>
+#include <sound/soc-acpi.h>
+
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+#include "../../amd/mach-config.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define ACP5X_FUTURE_REG_ACLK_0 0x1864
+
+static const struct sof_amd_acp_desc vangogh_chip_info = {
+       .rev            = 5,
+       .name           = "vangogh",
+       .host_bridge_id = HOST_BRIDGE_VGH,
+       .pgfsm_base     = ACP5X_PGFSM_BASE,
+       .ext_intr_stat  = ACP5X_EXT_INTR_STAT,
+       .dsp_intr_base  = ACP5X_DSP_SW_INTR_BASE,
+       .sram_pte_offset = ACP5X_SRAM_PTE_OFFSET,
+       .hw_semaphore_offset = ACP5X_AXI2DAGB_SEM_0,
+       .acp_clkmux_sel = ACP5X_CLKMUX_SEL,
+       .probe_reg_offset = ACP5X_FUTURE_REG_ACLK_0,
+};
+
+static const struct sof_dev_desc vangogh_desc = {
+       .machines               = snd_soc_acpi_amd_vangogh_sof_machines,
+       .resindex_lpe_base      = 0,
+       .resindex_pcicfg_base   = -1,
+       .resindex_imr_base      = -1,
+       .irqindex_host_ipc      = -1,
+       .chip_info              = &vangogh_chip_info,
+       .ipc_supported_mask     = BIT(SOF_IPC),
+       .ipc_default            = SOF_IPC,
+       .default_fw_path        = {
+               [SOF_IPC] = "amd/sof",
+       },
+       .default_tplg_path      = {
+               [SOF_IPC] = "amd/sof-tplg",
+       },
+       .default_fw_filename    = {
+               [SOF_IPC] = "sof-vangogh.ri",
+       },
+       .nocodec_tplg_filename  = "sof-acp.tplg",
+       .ops                    = &sof_vangogh_ops,
+       .ops_init               = sof_vangogh_ops_init,
+};
+
+static int acp_pci_vgh_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+       unsigned int flag;
+
+       if (pci->revision != ACP_VANGOGH_PCI_ID)
+               return -ENODEV;
+
+       flag = snd_amd_acp_find_config(pci);
+       if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+               return -ENODEV;
+
+       return sof_pci_probe(pci, pci_id);
+};
+
+static void acp_pci_vgh_remove(struct pci_dev *pci)
+{
+       sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id vgh_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+       .driver_data = (unsigned long)&vangogh_desc},
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, vgh_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_vgh_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = vgh_pci_ids,
+       .probe = acp_pci_vgh_probe,
+       .remove = acp_pci_vgh_remove,
+       .driver = {
+               .pm = &sof_pci_pm,
+       },
+};
+module_pci_driver(snd_sof_pci_amd_vgh_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c
new file mode 100644 (file)
index 0000000..de15d21
--- /dev/null
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2023 Advanced Micro Devices, Inc.
+//
+// Authors: Venkata Prasad Potturu <venkataprasad.potturu@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on Vangogh platform
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include "../ops.h"
+#include "../sof-audio.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define I2S_HS_INSTANCE                0
+#define I2S_BT_INSTANCE                1
+#define I2S_SP_INSTANCE                2
+#define PDM_DMIC_INSTANCE      3
+#define I2S_HS_VIRTUAL_INSTANCE        4
+
+static struct snd_soc_dai_driver vangogh_sof_dai[] = {
+       [I2S_HS_INSTANCE] = {
+               .id = I2S_HS_INSTANCE,
+               .name = "acp-sof-hs",
+               .playback = {
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 96000,
+               },
+               .capture = {
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       /* Supporting only stereo for I2S HS controller capture */
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rate_min = 8000,
+                       .rate_max = 48000,
+               },
+       },
+
+       [I2S_BT_INSTANCE] = {
+               .id = I2S_BT_INSTANCE,
+               .name = "acp-sof-bt",
+               .playback = {
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 96000,
+               },
+               .capture = {
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       /* Supporting only stereo for I2S BT controller capture */
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rate_min = 8000,
+                       .rate_max = 48000,
+               },
+       },
+
+       [I2S_SP_INSTANCE] = {
+               .id = I2S_SP_INSTANCE,
+               .name = "acp-sof-sp",
+               .playback = {
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 96000,
+               },
+               .capture = {
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       /* Supporting only stereo for I2S SP controller capture */
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rate_min = 8000,
+                       .rate_max = 48000,
+               },
+       },
+
+       [PDM_DMIC_INSTANCE] = {
+               .id = PDM_DMIC_INSTANCE,
+               .name = "acp-sof-dmic",
+               .capture = {
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                       .channels_min = 2,
+                       .channels_max = 4,
+                       .rate_min = 8000,
+                       .rate_max = 48000,
+               },
+       },
+
+       [I2S_HS_VIRTUAL_INSTANCE] = {
+               .id = I2S_HS_VIRTUAL_INSTANCE,
+               .name = "acp-sof-hs-virtual",
+               .playback = {
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       .channels_min = 2,
+                       .channels_max = 8,
+                       .rate_min = 8000,
+                       .rate_max = 96000,
+               },
+               .capture = {
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                                  SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+                       /* Supporting only stereo for I2S HS-Virtual controller capture */
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rate_min = 8000,
+                       .rate_max = 48000,
+               },
+       },
+};
+
+/* Vangogh ops */
+struct snd_sof_dsp_ops sof_vangogh_ops;
+EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON);
+
+int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
+{
+       const struct dmi_system_id *dmi_id;
+
+       /* common defaults */
+       memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+       sof_vangogh_ops.drv = vangogh_sof_dai;
+       sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai);
+
+       dmi_id = dmi_first_match(acp_sof_quirk_table);
+       if (dmi_id && dmi_id->driver_data)
+               sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware;
+
+       return 0;
+}
+
+MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
+MODULE_DESCRIPTION("VANGOGH SOF Driver");
+MODULE_LICENSE("Dual BSD/GPL");
index 69c1a370d3b610e1810aae46c36b5011b40e09fb..9d0107932117fc5cb7d40bb4be0b8b6cb0ef1e5a 100644 (file)
@@ -262,6 +262,22 @@ config SND_SOC_SOF_METEORLAKE
          Say Y if you have such a device.
          If unsure select "N".
 
+config SND_SOC_SOF_INTEL_LNL
+       tristate
+       select SND_SOC_SOF_HDA_COMMON
+       select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+       select SND_SOC_SOF_INTEL_IPC4
+
+config SND_SOC_SOF_LUNARLAKE
+       tristate "SOF support for Lunarlake"
+       default SND_SOC_SOF_PCI
+       select SND_SOC_SOF_INTEL_LNL
+       help
+         This adds support for Sound Open Firmware for Intel(R) platforms
+         using the Lunarlake processors.
+         Say Y if you have such a device.
+         If unsure select "N".
+
 config SND_SOC_SOF_HDA_COMMON
        tristate
        select SND_SOC_SOF_INTEL_COMMON
index fdb463c12e91daedbc9e47a8d8286b275d86db50..030574dbc9980aea01a6a1a1292d56c5935af15a 100644 (file)
@@ -7,7 +7,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
                                 hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
                                 hda-dai.o hda-dai-ops.o hda-bus.o \
                                 skl.o hda-loader-skl.o \
-                                apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
+                                apl.o cnl.o tgl.o icl.o mtl.o lnl.o hda-common-ops.o
 
 snd-sof-intel-hda-mlink-objs := hda-mlink.o
 
@@ -31,6 +31,7 @@ snd-sof-pci-intel-cnl-objs := pci-cnl.o
 snd-sof-pci-intel-icl-objs := pci-icl.o
 snd-sof-pci-intel-tgl-objs := pci-tgl.o
 snd-sof-pci-intel-mtl-objs := pci-mtl.o
+snd-sof-pci-intel-lnl-objs := pci-lnl.o
 
 obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o
@@ -39,3 +40,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
 obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o
index a95222e53ecf30a3a344a7a76771835d0b42485e..c6fbf42852620d836671d7c9eed002bdb4b51321 100644 (file)
@@ -466,6 +466,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
@@ -501,6 +502,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
index f3513796c189c6972ea5d614ef70fdb38901a3d9..494ced2b746e116109a6ca8cebff3e74451d6766 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <sound/pcm_params.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
 #include <sound/sof/ipc4/header.h>
 #include <uapi/sound/sof/header.h>
 #include "../ipc4-priv.h"
@@ -144,9 +145,17 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
                                                      struct snd_soc_dai *cpu_dai,
                                                      struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *dai;
        struct hdac_ext_stream *hext_stream;
 
-       hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+       /* only allocate a stream_tag for the first DAI in the dailink */
+       dai = asoc_rtd_to_cpu(rtd, 0);
+       if (dai == cpu_dai)
+               hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+       else
+               hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+
        if (!hext_stream)
                return NULL;
 
@@ -159,9 +168,14 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
                                    struct snd_pcm_substream *substream)
 {
        struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       struct snd_soc_dai *dai;
 
+       /* only release a stream_tag for the first DAI in the dailink */
+       dai = asoc_rtd_to_cpu(rtd, 0);
+       if (dai == cpu_dai)
+               snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
        snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
-       snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
 }
 
 static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
@@ -219,6 +233,77 @@ static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
        return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
 }
 
+static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
+                                              struct snd_pcm_substream *substream,
+                                              struct snd_pcm_hw_params *params)
+{
+       unsigned int format_val;
+
+       format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
+                                                params_format(params),
+                                                params_physical_width(params),
+                                                0);
+
+       dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+               params_rate(params), params_channels(params), params_format(params));
+
+       return format_val;
+}
+
+static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
+                                           struct snd_pcm_substream *substream,
+                                           struct snd_pcm_hw_params *params)
+{
+       unsigned int format_val;
+       snd_pcm_format_t format;
+       unsigned int channels;
+       unsigned int width;
+
+       channels = params_channels(params);
+       format = params_format(params);
+       width = params_physical_width(params);
+
+       if (format == SNDRV_PCM_FORMAT_S16_LE) {
+               format = SNDRV_PCM_FORMAT_S32_LE;
+               channels /= 2;
+               width = 32;
+       }
+
+       format_val = snd_hdac_calc_stream_format(params_rate(params), channels,
+                                                format,
+                                                width,
+                                                0);
+
+       dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
+               params_rate(params), channels, format);
+
+       return format_val;
+}
+
+static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
+                                          struct snd_pcm_substream *substream)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       return hdac_bus_eml_ssp_get_hlink(bus);
+}
+
+static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
+                                           struct snd_pcm_substream *substream)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       return hdac_bus_eml_dmic_get_hlink(bus);
+}
+
+static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
+                                          struct snd_pcm_substream *substream)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       return hdac_bus_eml_sdw_get_hlink(bus);
+}
+
 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                struct snd_pcm_substream *substream, int cmd)
 {
@@ -234,6 +319,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
        pipe_widget = swidget->spipe->pipe_widget;
        pipeline = pipe_widget->private;
 
+       if (pipe_widget->instance_id < 0)
+               return 0;
+
        mutex_lock(&ipc4_data->pipeline_state_mutex);
 
        switch (cmd) {
@@ -297,6 +385,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
        pipe_widget = swidget->spipe->pipe_widget;
        pipeline = pipe_widget->private;
 
+       if (pipe_widget->instance_id < 0)
+               return 0;
+
        mutex_lock(&ipc4_data->pipeline_state_mutex);
 
        switch (cmd) {
@@ -343,6 +434,28 @@ out:
        return ret;
 }
 
+static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
+                                                           struct snd_soc_dai *cpu_dai,
+                                                           struct snd_pcm_substream *substream)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+       struct snd_sof_widget *swidget = w->dobj.private;
+       struct snd_sof_dai *dai = swidget->private;
+       struct sof_ipc4_copier *ipc4_copier = dai->private;
+       struct sof_ipc4_alh_configuration_blob *blob;
+
+       blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
+
+       /*
+        * Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using
+        * the multi-gateway firmware configuration. The DMA hardware can take care of
+        * multiple links without needing any firmware assistance
+        */
+       blob->alh_cfg.device_count = 1;
+
+       return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream);
+}
+
 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
        .get_hext_stream = hda_ipc4_get_hext_stream,
        .assign_hext_stream = hda_assign_hext_stream,
@@ -357,6 +470,45 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
        .get_hlink = hda_get_hlink,
 };
 
+static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
+       .get_hext_stream = hda_ipc4_get_hext_stream,
+       .assign_hext_stream = hda_assign_hext_stream,
+       .release_hext_stream = hda_release_hext_stream,
+       .setup_hext_stream = hda_setup_hext_stream,
+       .reset_hext_stream = hda_reset_hext_stream,
+       .pre_trigger = hda_ipc4_pre_trigger,
+       .trigger = hda_trigger,
+       .post_trigger = hda_ipc4_post_trigger,
+       .calc_stream_format = generic_calc_stream_format,
+       .get_hlink = ssp_get_hlink,
+};
+
+static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
+       .get_hext_stream = hda_ipc4_get_hext_stream,
+       .assign_hext_stream = hda_assign_hext_stream,
+       .release_hext_stream = hda_release_hext_stream,
+       .setup_hext_stream = hda_setup_hext_stream,
+       .reset_hext_stream = hda_reset_hext_stream,
+       .pre_trigger = hda_ipc4_pre_trigger,
+       .trigger = hda_trigger,
+       .post_trigger = hda_ipc4_post_trigger,
+       .calc_stream_format = dmic_calc_stream_format,
+       .get_hlink = dmic_get_hlink,
+};
+
+static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
+       .get_hext_stream = sdw_hda_ipc4_get_hext_stream,
+       .assign_hext_stream = hda_assign_hext_stream,
+       .release_hext_stream = hda_release_hext_stream,
+       .setup_hext_stream = hda_setup_hext_stream,
+       .reset_hext_stream = hda_reset_hext_stream,
+       .pre_trigger = hda_ipc4_pre_trigger,
+       .trigger = hda_trigger,
+       .post_trigger = hda_ipc4_post_trigger,
+       .calc_stream_format = generic_calc_stream_format,
+       .get_hlink = sdw_get_hlink,
+};
+
 static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
        .get_hext_stream = hda_get_hext_stream,
        .assign_hext_stream = hda_assign_hext_stream,
@@ -372,6 +524,7 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
 static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                 struct snd_pcm_substream *substream, int cmd)
 {
+       struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
        struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
 
        switch (cmd) {
@@ -379,9 +532,17 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
        case SNDRV_PCM_TRIGGER_STOP:
        {
                struct snd_sof_dai_config_data data = { 0 };
+               int ret;
 
                data.dai_data = DMA_CHAN_INVALID;
-               return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+               ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+               if (ret < 0)
+                       return ret;
+
+               if (cmd == SNDRV_PCM_TRIGGER_STOP)
+                       return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
+
+               break;
        }
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
@@ -459,8 +620,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
        case SOF_INTEL_IPC4:
        {
                struct sof_ipc4_copier *ipc4_copier = sdai->private;
+               const struct sof_intel_dsp_desc *chip;
 
-               if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
+               chip = get_chip_info(sdev->pdata);
+
+               switch (ipc4_copier->dai_type) {
+               case SOF_DAI_INTEL_HDA:
+               {
                        struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
                        struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
 
@@ -469,6 +635,22 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
 
                        return &hda_ipc4_dma_ops;
                }
+               case SOF_DAI_INTEL_SSP:
+                       if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+                               return NULL;
+                       return &ssp_ipc4_dma_ops;
+               case SOF_DAI_INTEL_DMIC:
+                       if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+                               return NULL;
+                       return &dmic_ipc4_dma_ops;
+               case SOF_DAI_INTEL_ALH:
+                       if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+                               return NULL;
+                       return &sdw_ipc4_dma_ops;
+
+               default:
+                       break;
+               }
                break;
        }
        default:
index 3297dea493aa60594578a411ebb823facc37a092..f3cefd86608120ce8ba1044091078e2e80022ed1 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <sound/pcm_params.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
+#include <sound/hda_register.h>
 #include <sound/intel-nhlt.h>
 #include <sound/sof/ipc4/header.h>
 #include <uapi/sound/sof/header.h>
@@ -107,9 +109,8 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
        return sdai->platform_private;
 }
 
-static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
-                               struct hdac_ext_stream *hext_stream,
-                               struct snd_soc_dai *cpu_dai)
+int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
+                        struct snd_soc_dai *cpu_dai)
 {
        const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
        struct sof_intel_hda_stream *hda_stream;
@@ -330,6 +331,175 @@ static const struct snd_soc_dai_ops hda_dai_ops = {
 
 #endif
 
+static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
+{
+       struct snd_sof_widget *swidget = w->dobj.private;
+       struct snd_sof_dai *sdai = swidget->private;
+       struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
+
+       return ipc4_copier;
+}
+
+static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+       struct sof_ipc4_dma_config_tlv *dma_config_tlv;
+       const struct hda_dai_widget_dma_ops *ops;
+       struct sof_ipc4_dma_config *dma_config;
+       struct sof_ipc4_copier *ipc4_copier;
+       struct hdac_ext_stream *hext_stream;
+       struct hdac_stream *hstream;
+       struct snd_sof_dev *sdev;
+       int stream_id;
+       int ret;
+
+       ops = hda_dai_get_ops(substream, cpu_dai);
+       if (!ops) {
+               dev_err(cpu_dai->dev, "DAI widget ops not set\n");
+               return -EINVAL;
+       }
+
+       /* use HDaudio stream handling */
+       ret = hda_dai_hw_params(substream, params, cpu_dai);
+       if (ret < 0) {
+               dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret);
+               return ret;
+       }
+
+       /* get stream_id */
+       sdev = widget_to_sdev(w);
+       hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+       if (!hext_stream) {
+               dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
+               return -ENODEV;
+       }
+
+       hstream = &hext_stream->hstream;
+       stream_id = hstream->stream_tag;
+
+       if (!stream_id) {
+               dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
+               return -ENODEV;
+       }
+
+       /* configure TLV */
+       ipc4_copier = widget_to_copier(w);
+
+       dma_config_tlv = &ipc4_copier->dma_config_tlv;
+       dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
+       /* dma_config_priv_size is zero */
+       dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
+
+       dma_config = &dma_config_tlv->dma_config;
+
+       dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
+       dma_config->pre_allocated_by_host = 1;
+       dma_config->dma_channel_id = stream_id - 1;
+       dma_config->stream_id = stream_id;
+       dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
+       dma_config->dma_priv_config_size = 0;
+
+       return 0;
+}
+
+static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+       int stream = substream->stream;
+
+       return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
+}
+
+static const struct snd_soc_dai_ops ssp_dai_ops = {
+       .hw_params = non_hda_dai_hw_params,
+       .hw_free = hda_dai_hw_free,
+       .trigger = hda_dai_trigger,
+       .prepare = non_hda_dai_prepare,
+};
+
+static const struct snd_soc_dai_ops dmic_dai_ops = {
+       .hw_params = non_hda_dai_hw_params,
+       .hw_free = hda_dai_hw_free,
+       .trigger = hda_dai_trigger,
+       .prepare = non_hda_dai_prepare,
+};
+
+int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
+                         struct snd_pcm_hw_params *params,
+                         struct snd_soc_dai *cpu_dai,
+                         int link_id)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+       const struct hda_dai_widget_dma_ops *ops;
+       struct hdac_ext_stream *hext_stream;
+       struct snd_sof_dev *sdev;
+       int ret;
+
+       ret = non_hda_dai_hw_params(substream, params, cpu_dai);
+       if (ret < 0) {
+               dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       ops = hda_dai_get_ops(substream, cpu_dai);
+       sdev = widget_to_sdev(w);
+       hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+       if (!hext_stream)
+               return -ENODEV;
+
+       /* in the case of SoundWire we need to program the PCMSyCM registers */
+       ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+                                            GENMASK(params_channels(params) - 1, 0),
+                                            hdac_stream(hext_stream)->stream_tag,
+                                            substream->stream);
+       if (ret < 0) {
+               dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *cpu_dai,
+                       int link_id)
+{
+       struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+       struct snd_sof_dev *sdev;
+       int ret;
+
+       ret = hda_dai_hw_free(substream, cpu_dai);
+       if (ret < 0) {
+               dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
+               return ret;
+       }
+
+       sdev = widget_to_sdev(w);
+
+       /* in the case of SoundWire we need to reset the PCMSyCM registers */
+       ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+                                            0, 0, substream->stream);
+       if (ret < 0) {
+               dev_err(cpu_dai->dev, "%s:  hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                       struct snd_soc_dai *cpu_dai)
+{
+       return hda_dai_trigger(substream, cmd, cpu_dai);
+}
+
 static int hda_dai_suspend(struct hdac_bus *bus)
 {
        struct snd_soc_pcm_runtime *rtd;
@@ -384,7 +554,42 @@ static int hda_dai_suspend(struct hdac_bus *bus)
        return 0;
 }
 
-#endif
+static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+       const struct sof_intel_dsp_desc *chip;
+       int i;
+
+       chip = get_chip_info(sdev->pdata);
+
+       if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+               for (i = 0; i < ops->num_drv; i++) {
+                       if (strstr(ops->drv[i].name, "SSP"))
+                               ops->drv[i].ops = &ssp_dai_ops;
+               }
+       }
+}
+
+static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
+{
+       const struct sof_intel_dsp_desc *chip;
+       int i;
+
+       chip = get_chip_info(sdev->pdata);
+
+       if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+               for (i = 0; i < ops->num_drv; i++) {
+                       if (strstr(ops->drv[i].name, "DMIC"))
+                               ops->drv[i].ops = &dmic_dai_ops;
+               }
+       }
+}
+
+#else
+
+static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
+
+#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
 
 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 {
@@ -399,6 +604,9 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 #endif
        }
 
+       ssp_set_dai_drv_ops(sdev, ops);
+       dmic_set_dai_drv_ops(sdev, ops);
+
        if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
                struct sof_ipc4_fw_data *ipc4_data = sdev->private;
 
index b7cbf66badf5b12e039b62f28ce34937124ef3d5..b592e687a87a1a54ff23a568377d5efdd759db82 100644 (file)
@@ -331,14 +331,19 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask)
        return !!(val & cmdsync_mask);
 }
 
-static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num)
+static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid)
 {
-       u32 val;
+       return readw(lsdiid);
+}
+
+static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num)
+{
+       u16 val;
 
-       val = readl(lsdiid);
+       val = readw(lsdiid);
        val |= BIT(dev_num);
 
-       writel(val, lsdiid);
+       writew(val, lsdiid);
 }
 
 static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan,
@@ -752,6 +757,22 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink)
 }
 EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
 
+int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid)
+{
+       struct hdac_ext2_link *h2link;
+       struct hdac_ext_link *hlink;
+
+       h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
+       if (!h2link)
+               return -ENODEV;
+
+       hlink = &h2link->hext_link;
+
+       *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink));
+
+       return 0;
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK);
+
 int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
 {
        struct hdac_ext2_link *h2link;
@@ -781,6 +802,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
 {
        struct hdac_ext2_link *h2link;
        u16 __iomem *pcmsycm;
+       int hchan;
+       int lchan;
        u16 val;
 
        h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
@@ -791,17 +814,25 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
                h2link->instance_offset * sublink +
                AZX_REG_SDW_SHIM_PCMSyCM(y);
 
+       if (channel_mask) {
+               hchan = __fls(channel_mask);
+               lchan = __ffs(channel_mask);
+       } else {
+               hchan = 0;
+               lchan = 0;
+       }
+
        mutex_lock(&h2link->eml_lock);
 
-       hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask),
+       hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan,
                                 stream_id, dir);
 
        mutex_unlock(&h2link->eml_lock);
 
        val = readw(pcmsycm);
 
-       dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
-               channel_mask, stream_id, dir, val);
+       dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
+               sublink, channel_mask, stream_id, dir, val);
 
        return 0;
 } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);
index b13acb9596537b586cb5bb2557cefaafe78df97e..0b0087abcc50ed87e69fcde321f693a228e93a64 100644 (file)
@@ -869,8 +869,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
                return -ENOMEM;
        }
 
-       /* create capture streams */
-       for (i = 0; i < num_capture; i++) {
+       /* create capture and playback streams */
+       for (i = 0; i < num_total; i++) {
                struct sof_intel_hda_stream *hda_stream;
 
                hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
@@ -909,69 +909,17 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
                hstream->index = i;
                sd_offset = SOF_STREAM_SD_OFFSET(hstream);
                hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
-               hstream->stream_tag = i + 1;
                hstream->opened = false;
                hstream->running = false;
-               hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
 
-               /* memory alloc for stream BDL */
-               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
-                                         HDA_DSP_BDL_SIZE, &hstream->bdl);
-               if (ret < 0) {
-                       dev_err(sdev->dev, "error: stream bdl dma alloc failed\n");
-                       return -ENOMEM;
-               }
-               hstream->posbuf = (__le32 *)(bus->posbuf.area +
-                       (hstream->index) * 8);
-
-               list_add_tail(&hstream->list, &bus->stream_list);
-       }
-
-       /* create playback streams */
-       for (i = num_capture; i < num_total; i++) {
-               struct sof_intel_hda_stream *hda_stream;
-
-               hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream),
-                                         GFP_KERNEL);
-               if (!hda_stream)
-                       return -ENOMEM;
-
-               hda_stream->sdev = sdev;
-
-               hext_stream = &hda_stream->hext_stream;
-
-               if (sdev->bar[HDA_DSP_PP_BAR]) {
-                       hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
-                               SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
-
-                       hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
-                               SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
-                               SOF_HDA_PPLC_INTERVAL * i;
-               }
-
-               hstream = &hext_stream->hstream;
-
-               /* do we support SPIB */
-               if (sdev->bar[HDA_DSP_SPIB_BAR]) {
-                       hstream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
-                               SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
-                               SOF_HDA_SPIB_SPIB;
-
-                       hstream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] +
-                               SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i +
-                               SOF_HDA_SPIB_MAXFIFO;
+               if (i < num_capture) {
+                       hstream->stream_tag = i + 1;
+                       hstream->direction = SNDRV_PCM_STREAM_CAPTURE;
+               } else {
+                       hstream->stream_tag = i - num_capture + 1;
+                       hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
                }
 
-               hstream->bus = bus;
-               hstream->sd_int_sta_mask = 1 << i;
-               hstream->index = i;
-               sd_offset = SOF_STREAM_SD_OFFSET(hstream);
-               hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset;
-               hstream->stream_tag = i - num_capture + 1;
-               hstream->opened = false;
-               hstream->running = false;
-               hstream->direction = SNDRV_PCM_STREAM_PLAYBACK;
-
                /* mem alloc for stream BDL */
                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev,
                                          HDA_DSP_BDL_SIZE, &hstream->bdl);
index 64bebe1a72bbcb868ec913cd667ae2b2447e8240..15e6779efaa3bcc9e0dc16e6a92271930eba7a0f 100644 (file)
@@ -71,6 +71,11 @@ static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
                                    BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
                interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
                break;
+       case SOF_INTEL_ACE_2_0:
+               interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
+                                   BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
+               interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */
+               break;
        default:
                break;
        }
@@ -107,6 +112,34 @@ struct sdw_intel_ops sdw_callback = {
        .params_stream = sdw_params_stream,
 };
 
+static int sdw_ace2x_params_stream(struct device *dev,
+                                  struct sdw_intel_stream_params_data *params_data)
+{
+       return sdw_hda_dai_hw_params(params_data->substream,
+                                    params_data->hw_params,
+                                    params_data->dai,
+                                    params_data->link_id);
+}
+
+static int sdw_ace2x_free_stream(struct device *dev,
+                                struct sdw_intel_stream_free_data *free_data)
+{
+       return sdw_hda_dai_hw_free(free_data->substream,
+                                  free_data->dai,
+                                  free_data->link_id);
+}
+
+static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
+{
+       return sdw_hda_dai_trigger(substream, cmd, dai);
+}
+
+static struct sdw_intel_ops sdw_ace2x_callback = {
+       .params_stream = sdw_ace2x_params_stream,
+       .free_stream = sdw_ace2x_free_stream,
+       .trigger = sdw_ace2x_trigger,
+};
+
 void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
 {
        struct sof_intel_hda_dev *hdev;
@@ -174,6 +207,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
                res.shim_base = hdev->desc->sdw_shim_base;
                res.alh_base = hdev->desc->sdw_alh_base;
                res.ext = false;
+               res.ops = &sdw_callback;
        } else {
                /*
                 * retrieve eml_lock needed to protect shared registers
@@ -191,11 +225,13 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
                 */
                res.hw_ops = &sdw_intel_lnl_hw_ops;
                res.ext = true;
+               res.ops = &sdw_ace2x_callback;
+
        }
        res.irq = sdev->ipc_irq;
        res.handle = hdev->info.handle;
        res.parent = sdev->dev;
-       res.ops = &sdw_callback;
+
        res.dev = sdev->dev;
        res.clock_stop_quirks = sdw_clock_stop_quirks;
        res.hbus = sof_to_bus(sdev);
@@ -363,14 +399,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
        return sdw_intel_thread(irq, context);
 }
 
-static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
 {
-       u32 interface_mask = hda_get_interface_mask(sdev);
        struct sof_intel_hda_dev *hdev;
 
-       if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
-               return false;
-
        hdev = sdev->pdata->hw_pdata;
        if (hdev->sdw &&
            snd_sof_dsp_read(sdev, HDA_DSP_BAR,
@@ -380,6 +412,21 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
        return false;
 }
 
+static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+{
+       u32 interface_mask = hda_get_interface_mask(sdev);
+       const struct sof_intel_dsp_desc *chip;
+
+       if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
+               return false;
+
+       chip = get_chip_info(sdev->pdata);
+       if (chip && chip->check_sdw_wakeen_irq)
+               return chip->check_sdw_wakeen_irq(sdev);
+
+       return false;
+}
+
 void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
 {
        u32 interface_mask = hda_get_interface_mask(sdev);
@@ -1429,83 +1476,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 
-#define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
-                                 SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
-
-/* Check if all Slaves defined on the link can be found */
-static bool link_slaves_found(struct snd_sof_dev *sdev,
-                             const struct snd_soc_acpi_link_adr *link,
-                             struct sdw_intel_ctx *sdw)
-{
-       struct hdac_bus *bus = sof_to_bus(sdev);
-       struct sdw_intel_slave_id *ids = sdw->ids;
-       int num_slaves = sdw->num_slaves;
-       unsigned int part_id, link_id, unique_id, mfg_id, version;
-       int i, j, k;
-
-       for (i = 0; i < link->num_adr; i++) {
-               u64 adr = link->adr_d[i].adr;
-               int reported_part_count = 0;
-
-               mfg_id = SDW_MFG_ID(adr);
-               part_id = SDW_PART_ID(adr);
-               link_id = SDW_DISCO_LINK_ID(adr);
-               version = SDW_VERSION(adr);
-
-               for (j = 0; j < num_slaves; j++) {
-                       /* find out how many identical parts were reported on that link */
-                       if (ids[j].link_id == link_id &&
-                           ids[j].id.part_id == part_id &&
-                           ids[j].id.mfg_id == mfg_id &&
-                           ids[j].id.sdw_version == version)
-                               reported_part_count++;
-               }
-
-               for (j = 0; j < num_slaves; j++) {
-                       int expected_part_count = 0;
-
-                       if (ids[j].link_id != link_id ||
-                           ids[j].id.part_id != part_id ||
-                           ids[j].id.mfg_id != mfg_id ||
-                           ids[j].id.sdw_version != version)
-                               continue;
-
-                       /* find out how many identical parts are expected */
-                       for (k = 0; k < link->num_adr; k++) {
-                               u64 adr2 = link->adr_d[k].adr;
-
-                               if (SDW_CODEC_ADR_MASK(adr2) == SDW_CODEC_ADR_MASK(adr))
-                                       expected_part_count++;
-                       }
-
-                       if (reported_part_count == expected_part_count) {
-                               /*
-                                * we have to check unique id
-                                * if there is more than one
-                                * Slave on the link
-                                */
-                               unique_id = SDW_UNIQUE_ID(adr);
-                               if (reported_part_count == 1 ||
-                                   ids[j].id.unique_id == unique_id) {
-                                       dev_dbg(bus->dev, "found %x at link %d\n",
-                                               part_id, link_id);
-                                       break;
-                               }
-                       } else {
-                               dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n",
-                                       part_id, reported_part_count, expected_part_count, link_id);
-                       }
-               }
-               if (j == num_slaves) {
-                       dev_dbg(bus->dev,
-                               "Slave %x not found\n",
-                               part_id);
-                       return false;
-               }
-       }
-       return true;
-}
-
 static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
 {
        struct snd_sof_pdata *pdata = sdev->pdata;
@@ -1549,7 +1519,9 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
                                 * Try next machine if any expected Slaves
                                 * are not found on this link.
                                 */
-                               if (!link_slaves_found(sdev, link, hdev->sdw))
+                               if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
+                                                                       hdev->sdw->ids,
+                                                                       hdev->sdw->num_slaves))
                                        break;
                        }
                        /* Found if all Slaves are checked */
index 3f7c6fb05e5d7535df0ba5eb6d698229338201ef..5c517ec57d4a2033cc5c8a116bbc86f928080ef7 100644 (file)
@@ -785,6 +785,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev);
 int hda_sdw_startup(struct snd_sof_dev *sdev);
 void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
 void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
+bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev);
 void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
 bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
 
@@ -813,6 +814,11 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
 {
 }
 
+static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
+{
+       return false;
+}
+
 static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
 {
 }
@@ -824,6 +830,18 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
 
 #endif
 
+int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
+                         struct snd_pcm_hw_params *params,
+                         struct snd_soc_dai *cpu_dai,
+                         int link_id);
+
+int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *cpu_dai,
+                       int link_id);
+
+int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                       struct snd_soc_dai *cpu_dai);
+
 /* common dai driver */
 extern struct snd_soc_dai_driver skl_dai[];
 int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
@@ -845,6 +863,8 @@ extern struct snd_sof_dsp_ops sof_icl_ops;
 int sof_icl_ops_init(struct snd_sof_dev *sdev);
 extern struct snd_sof_dsp_ops sof_mtl_ops;
 int sof_mtl_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_lnl_ops;
+int sof_lnl_ops_init(struct snd_sof_dev *sdev);
 
 extern const struct sof_intel_dsp_desc skl_chip_info;
 extern const struct sof_intel_dsp_desc apl_chip_info;
@@ -856,6 +876,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info;
 extern const struct sof_intel_dsp_desc jsl_chip_info;
 extern const struct sof_intel_dsp_desc adls_chip_info;
 extern const struct sof_intel_dsp_desc mtl_chip_info;
+extern const struct sof_intel_dsp_desc lnl_chip_info;
 
 /* Probes support */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
@@ -963,5 +984,7 @@ const struct hda_dai_widget_dma_ops *
 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
 int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
                   struct snd_sof_dai_config_data *data);
+int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
+                        struct snd_soc_dai *cpu_dai);
 
 #endif
index 0f249efc6a5a28de4d2ed2dcce980ed907becab3..7ac10167a90d77c2f7863c9a02f3fa51772fd36f 100644 (file)
@@ -188,6 +188,7 @@ const struct sof_intel_dsp_desc icl_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
new file mode 100644 (file)
index 0000000..db94b45
--- /dev/null
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2023 Intel Corporation. All rights reserved.
+
+/*
+ * Hardware interface for audio DSP on LunarLake.
+ */
+
+#include <linux/firmware.h>
+#include <sound/hda_register.h>
+#include <sound/sof/ipc4/header.h>
+#include <trace/events/sof_intel.h>
+#include "../ipc4-priv.h"
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+#include "mtl.h"
+#include <sound/hda-mlink.h>
+
+/* LunarLake ops */
+struct snd_sof_dsp_ops sof_lnl_ops;
+EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {
+       {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
+       {"pp", HDA_DSP_PP_BAR,  0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
+       {"dsp", HDA_DSP_BAR,  0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
+};
+
+/* this helps allows the DSP to setup DMIC/SSP */
+static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus)
+{
+       int ret;
+
+       ret = hdac_bus_eml_enable_offload(bus, true,  AZX_REG_ML_LEPTR_ID_INTEL_SSP, true);
+       if (ret < 0)
+               return ret;
+
+       ret = hdac_bus_eml_enable_offload(bus, true,  AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev)
+{
+       int ret;
+
+       ret = hda_dsp_probe(sdev);
+       if (ret < 0)
+               return ret;
+
+       return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+}
+
+static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)
+{
+       int ret;
+
+       ret = hda_dsp_resume(sdev);
+       if (ret < 0)
+               return ret;
+
+       return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+}
+
+static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
+{
+       int ret;
+
+       ret = hda_dsp_runtime_resume(sdev);
+       if (ret < 0)
+               return ret;
+
+       return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+}
+
+int sof_lnl_ops_init(struct snd_sof_dev *sdev)
+{
+       struct sof_ipc4_fw_data *ipc4_data;
+
+       /* common defaults */
+       memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+       /* probe */
+       sof_lnl_ops.probe = lnl_hda_dsp_probe;
+
+       /* shutdown */
+       sof_lnl_ops.shutdown = hda_dsp_shutdown;
+
+       /* doorbell */
+       sof_lnl_ops.irq_thread = mtl_ipc_irq_thread;
+
+       /* ipc */
+       sof_lnl_ops.send_msg = mtl_ipc_send_msg;
+       sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
+       sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
+
+       /* debug */
+       sof_lnl_ops.debug_map = lnl_dsp_debugfs;
+       sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs);
+       sof_lnl_ops.dbg_dump = mtl_dsp_dump;
+       sof_lnl_ops.ipc_dump = mtl_ipc_dump;
+
+       /* pre/post fw run */
+       sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
+       sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run;
+
+       /* parse platform specific extended manifest */
+       sof_lnl_ops.parse_platform_ext_manifest = NULL;
+
+       /* dsp core get/put */
+       /* TODO: add core_get and core_put */
+
+       /* PM */
+       sof_lnl_ops.resume                      = lnl_hda_dsp_resume;
+       sof_lnl_ops.runtime_resume              = lnl_hda_dsp_runtime_resume;
+
+       sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
+
+       sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
+       if (!sdev->private)
+               return -ENOMEM;
+
+       ipc4_data = sdev->private;
+       ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
+
+       ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+
+       /* External library loading support */
+       ipc4_data->load_library = hda_dsp_ipc4_load_library;
+
+       /* set DAI ops */
+       hda_set_dai_drv_ops(sdev, &sof_lnl_ops);
+
+       sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
+
+       return 0;
+};
+EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+
+/* Check if an SDW IRQ occurred */
+static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       return hdac_bus_eml_check_interrupt(bus, true,  AZX_REG_ML_LEPTR_ID_SDW);
+}
+
+static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+
+       hdac_bus_eml_enable_interrupt(bus, true,  AZX_REG_ML_LEPTR_ID_SDW, enable);
+}
+
+static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
+{
+       lnl_enable_sdw_irq(sdev, false);
+       mtl_disable_ipc_interrupts(sdev);
+       return mtl_enable_interrupts(sdev, false);
+}
+
+const struct sof_intel_dsp_desc lnl_chip_info = {
+       .cores_num = 5,
+       .init_core_mask = BIT(0),
+       .host_managed_cores_mask = BIT(0),
+       .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+       .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+       .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+       .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+       .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+       .rom_status_reg = MTL_DSP_ROM_STS,
+       .rom_init_timeout = 300,
+       .ssp_count = MTL_SSP_COUNT,
+       .d0i3_offset = MTL_HDA_VS_D0I3C,
+       .read_sdw_lcount =  hda_sdw_check_lcount_ext,
+       .enable_sdw_irq = lnl_enable_sdw_irq,
+       .check_sdw_irq = lnl_dsp_check_sdw_irq,
+       .check_ipc_irq = mtl_dsp_check_ipc_irq,
+       .cl_init = mtl_dsp_cl_init,
+       .power_down_dsp = mtl_power_down_dsp,
+       .disable_interrupts = lnl_dsp_disable_interrupts,
+       .hw_ip_version = SOF_INTEL_ACE_2_0,
+};
+EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
index 30fe77fd87bf8dddbaa8cc5c7012f6045f8748ad..b84ca58da9d5da72d4158dabd51564f046630fe7 100644 (file)
@@ -91,7 +91,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
        return false;
 }
 
-static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
 {
        struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
        struct sof_ipc4_msg *msg_data = msg->msg_data;
@@ -230,7 +230,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
 }
 
 /* pre fw run operations */
-static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
+int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
 {
        struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
        u32 dsphfpwrsts;
@@ -279,7 +279,7 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
        return ret;
 }
 
-static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
 {
        int ret;
 
@@ -301,7 +301,7 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
        return 0;
 }
 
-static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
 {
        char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
        u32 romdbgsts;
@@ -495,7 +495,7 @@ err:
        return ret;
 }
 
-static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
+irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
 {
        struct sof_ipc4_msg notification_data = {{ 0 }};
        struct snd_sof_dev *sdev = context;
@@ -578,17 +578,17 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
        return IRQ_HANDLED;
 }
 
-static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
+int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
 {
        return MTL_DSP_MBOX_UPLINK_OFFSET;
 }
 
-static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
 {
        return MTL_SRAM_WINDOW_OFFSET(id);
 }
 
-static void mtl_ipc_dump(struct snd_sof_dev *sdev)
+void mtl_ipc_dump(struct snd_sof_dev *sdev)
 {
        u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;
 
@@ -612,9 +612,9 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
        return mtl_enable_interrupts(sdev, false);
 }
 
-static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
-                                               struct snd_soc_component *component,
-                                               struct snd_pcm_substream *substream)
+u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
+                                        struct snd_soc_component *component,
+                                        struct snd_pcm_substream *substream)
 {
        struct hdac_stream *hstream = substream->runtime->private_data;
        u32 llp_l, llp_u;
@@ -735,6 +735,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = mtl_enable_sdw_irq,
        .check_sdw_irq = mtl_dsp_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq = mtl_dsp_check_ipc_irq,
        .cl_init = mtl_dsp_cl_init,
        .power_down_dsp = mtl_power_down_dsp,
index 2794fe6e81396dd84f6e0db069b8218a65401741..02181490f12a6f1b550e0463dcae039161a0993b 100644 (file)
 #define MTL_DSP_REG_HfIMRIS1           0x162088
 #define MTL_DSP_REG_HfIMRIS1_IU_MASK   BIT(0)
 
+bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
+int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
+
 void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
 void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
-bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
 
 int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
-int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
+
+int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev);
+int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev);
+void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
+
 int mtl_power_down_dsp(struct snd_sof_dev *sdev);
+int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
+
+irqreturn_t mtl_ipc_irq_thread(int irq, void *context);
+
+int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
+int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
+
+void mtl_ipc_dump(struct snd_sof_dev *sdev);
+
+u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
+                                        struct snd_soc_component *component,
+                                        struct snd_pcm_substream *substream);
index 69cad5a6bc724e9ae16859b53a3837424136d89a..460f87f25dac224d1648d7272423d1aff6e652b8 100644 (file)
@@ -85,12 +85,8 @@ static const struct sof_dev_desc glk_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       { PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */
-               .driver_data = (unsigned long)&bxt_desc},
-       { PCI_DEVICE(0x8086, 0x1a98),/* BXT-T */
-               .driver_data = (unsigned long)&bxt_desc},
-       { PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */
-               .driver_data = (unsigned long)&glk_desc},
+       { PCI_DEVICE_DATA(INTEL, HDA_APL, &bxt_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_GML, &glk_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index 8895508a0be6d7dbc6285b85a5f78972c58e0565..e2c50e7b0aa78e85f4b5f9321cf57b260cc2401a 100644 (file)
@@ -120,16 +120,11 @@ static const struct sof_dev_desc cml_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       { PCI_DEVICE(0x8086, 0x9dc8), /* CNL-LP */
-               .driver_data = (unsigned long)&cnl_desc},
-       { PCI_DEVICE(0x8086, 0xa348), /* CNL-H */
-               .driver_data = (unsigned long)&cfl_desc},
-       { PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */
-               .driver_data = (unsigned long)&cml_desc},
-       { PCI_DEVICE(0x8086, 0x06c8), /* CML-H */
-               .driver_data = (unsigned long)&cml_desc},
-       { PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */
-               .driver_data = (unsigned long)&cml_desc},
+       { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cfl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cml_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cml_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &cml_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index 5fb5a820693e4ada842993f7bfb3a6df4e54c75a..0a65df3ed9e2b3ede4555032f484a04710eb9b08 100644 (file)
@@ -86,14 +86,10 @@ static const struct sof_dev_desc jsl_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       { PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */
-               .driver_data = (unsigned long)&icl_desc},
-       { PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */
-               .driver_data = (unsigned long)&icl_desc},
-       { PCI_DEVICE(0x8086, 0x38c8), /* ICL-N */
-               .driver_data = (unsigned long)&jsl_desc},
-       { PCI_DEVICE(0x8086, 0x4dc8), /* JSL-N */
-               .driver_data = (unsigned long)&jsl_desc},
+       { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &jsl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c
new file mode 100644 (file)
index 0000000..1b12c28
--- /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) 2023 Intel Corporation. All rights reserved.
+//
+// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.h"
+#include "mtl.h"
+
+static const struct sof_dev_desc lnl_desc = {
+       .use_acpi_target_states = true,
+       .machines               = snd_soc_acpi_intel_lnl_machines,
+       .alt_machines           = snd_soc_acpi_intel_lnl_sdw_machines,
+       .resindex_lpe_base      = 0,
+       .resindex_pcicfg_base   = -1,
+       .resindex_imr_base      = -1,
+       .irqindex_host_ipc      = -1,
+       .chip_info              = &lnl_chip_info,
+       .ipc_supported_mask     = BIT(SOF_INTEL_IPC4),
+       .ipc_default            = SOF_INTEL_IPC4,
+       .dspless_mode_supported = true,
+       .default_fw_path = {
+               [SOF_INTEL_IPC4] = "intel/sof-ipc4/lnl",
+       },
+       .default_tplg_path = {
+               [SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
+       },
+       .default_fw_filename = {
+               [SOF_INTEL_IPC4] = "sof-lnl.ri",
+       },
+       .nocodec_tplg_filename = "sof-lnl-nocodec.tplg",
+       .ops = &sof_lnl_ops,
+       .ops_init = sof_lnl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+       { PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_lnl_driver = {
+       .name = "sof-audio-pci-intel-lnl",
+       .id_table = sof_pci_ids,
+       .probe = hda_pci_intel_probe,
+       .remove = sof_pci_remove,
+       .shutdown = sof_pci_shutdown,
+       .driver = {
+               .pm = &sof_pci_pm,
+       },
+};
+module_pci_driver(snd_sof_pci_intel_lnl_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
+MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
index e276e1e37fed8ee616fe400fee5ea3fb1ab0bb36..7868b0827e844ed5305580fbefc157e6440753f0 100644 (file)
@@ -52,8 +52,7 @@ static const struct sof_dev_desc mtl_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       { PCI_DEVICE(0x8086, 0x7E28), /* MTL */
-               .driver_data = (unsigned long)&mtl_desc},
+       { PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index 5e69af6eed344b9ed84f7aceec086d08edc70433..a6588b138a8c074de03f28aa1294e3515a917a8a 100644 (file)
@@ -69,10 +69,8 @@ static struct sof_dev_desc kbl_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       /* Sunrise Point-LP */
-       { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&skl_desc},
-       /* KBL */
-       { PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc},
+       { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &kbl_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index ca37ff1bbd2ae56713199d1bba221b8a1e6e82d1..d688f9373fb2f5ede2aa0a5dfc612419b9b9fa94 100644 (file)
@@ -284,36 +284,21 @@ static const struct sof_dev_desc rpl_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */
-               .driver_data = (unsigned long)&tgl_desc},
-       { PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */
-               .driver_data = (unsigned long)&tglh_desc},
-       { PCI_DEVICE(0x8086, 0x4b55), /* EHL */
-               .driver_data = (unsigned long)&ehl_desc},
-       { PCI_DEVICE(0x8086, 0x4b58), /* EHL */
-               .driver_data = (unsigned long)&ehl_desc},
-       { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */
-               .driver_data = (unsigned long)&adls_desc},
-       { PCI_DEVICE(0x8086, 0x7a50), /* RPL-S */
-               .driver_data = (unsigned long)&rpls_desc},
-       { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */
-               .driver_data = (unsigned long)&adl_desc},
-       { PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */
-               .driver_data = (unsigned long)&adl_desc},
-       { PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */
-               .driver_data = (unsigned long)&rpl_desc},
-       { PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */
-               .driver_data = (unsigned long)&rpl_desc},
-       { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
-               .driver_data = (unsigned long)&adl_desc},
-       { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
-               .driver_data = (unsigned long)&adl_desc},
-       { PCI_DEVICE(0x8086, 0x51ce), /* RPL-M */
-               .driver_data = (unsigned long)&rpl_desc},
-       { PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */
-               .driver_data = (unsigned long)&rpl_desc},
-       { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
-               .driver_data = (unsigned long)&adl_n_desc},
+       { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tglh_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adls_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &rpls_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &rpl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &rpl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) },
+       { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index 8c22a00266c06a6ffd94be4e2e921450d721ce14..4ae4fe17cc0bc55d4c2dae6f0280f1bb83f8f462 100644 (file)
@@ -225,8 +225,7 @@ static const struct sof_dev_desc tng_desc = {
 
 /* PCI IDs */
 static const struct pci_device_id sof_pci_ids[] = {
-       { PCI_DEVICE(0x8086, 0x119a),
-               .driver_data = (unsigned long)&tng_desc},
+       { PCI_DEVICE_DATA(INTEL, SST_TNG, &tng_desc) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index 207df48e27cf92dc088dfc9bc953dff9b3f4d648..9515d753c816e1fd09eb93d9a9f9c6bd72a9ec65 100644 (file)
@@ -189,6 +189,7 @@ struct sof_intel_dsp_desc {
        int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
        void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
        bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
+       bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev);
        bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
        int (*power_down_dsp)(struct snd_sof_dev *sdev);
        int (*disable_interrupts)(struct snd_sof_dev *sdev);
index 8e2b07e1612b7693422ac9a87bc6fbc796ce2f85..bb9f20253c996da3a746da7ddcb7e7c8006a0283 100644 (file)
@@ -147,6 +147,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
@@ -175,6 +176,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
@@ -203,6 +205,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
@@ -231,6 +234,7 @@ const struct sof_intel_dsp_desc adls_chip_info = {
        .read_sdw_lcount =  hda_sdw_check_lcount_common,
        .enable_sdw_irq = hda_common_enable_sdw_irq,
        .check_sdw_irq  = hda_common_check_sdw_irq,
+       .check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
        .check_ipc_irq  = hda_dsp_check_ipc_irq,
        .cl_init = cl_dsp_init,
        .power_down_dsp = hda_power_down_dsp,
index 35da85a45a9aeded73a21bfcfeda4233999d144c..bd07f0472efd719b99df5cd9afd9bced1318bedc 100644 (file)
@@ -196,15 +196,9 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user
                return -EINVAL;
        }
 
-       string = kmalloc(count + 1, GFP_KERNEL);
-       if (!string)
-               return -ENOMEM;
-
-       if (copy_from_user(string, from, count)) {
-               ret = -EFAULT;
-               goto error;
-       }
-       string[count] = '\0';
+       string = memdup_user_nul(from, count);
+       if (IS_ERR(string))
+               return PTR_ERR(string);
 
        ret = trace_filter_parse(sdev, string, &num_elems, &elems);
        if (ret < 0)
index 304faf6425abc16da9c7c7d28479a69d21113d60..cb58ee8c158a5593fc104c4dbc3b223e94f4421b 100644 (file)
@@ -309,6 +309,23 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
                channels->min = private->dai_config->afe.channels;
                channels->max = private->dai_config->afe.channels;
 
+               snd_mask_none(fmt);
+
+               switch (private->dai_config->afe.format) {
+               case SOF_IPC_FRAME_S16_LE:
+                       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+                       break;
+               case SOF_IPC_FRAME_S24_4LE:
+                       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+                       break;
+               case SOF_IPC_FRAME_S32_LE:
+                       snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+                       break;
+               default:
+                       dev_err(component->dev, "Not available format!\n");
+                       return -EINVAL;
+               }
+
                dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max);
                dev_dbg(component->dev, "channels_min: %d channels_max: %d\n",
                        channels->min, channels->max);
index 2c5aac31e8b0712ec05ef46724d14e7414fede02..fb40378ad0840255a9b35cb74f99c9b80d5271b9 100644 (file)
@@ -312,7 +312,7 @@ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
                } else {
                        if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
                                ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
-                       if (msg->reply_size)
+                       if (reply_data && msg->reply_size)
                                /* copy the data returned from DSP */
                                memcpy(reply_data, msg->reply_data,
                                       msg->reply_size);
@@ -567,13 +567,10 @@ int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
        /* create read-only cc_version debugfs to store compiler version info */
        /* use local copy of the cc_version to prevent data corruption */
        if (sdev->first_boot) {
-               sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
-                                               GFP_KERNEL);
-
+               sdev->cc_version = devm_kmemdup(sdev->dev, cc, cc->ext_hdr.hdr.size, GFP_KERNEL);
                if (!sdev->cc_version)
                        return -ENOMEM;
 
-               memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
                ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
                                               cc->ext_hdr.hdr.size,
                                               "cc_version", 0444);
@@ -1001,7 +998,7 @@ void sof_ipc3_do_rx_work(struct snd_sof_dev *sdev, struct sof_ipc_cmd_hdr *hdr,
 
        ipc3_log_header(sdev->dev, "ipc rx", hdr->cmd);
 
-       if (hdr->size < sizeof(hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
+       if (hdr->size < sizeof(*hdr) || hdr->size > SOF_IPC_MSG_MAX_SIZE) {
                dev_err(sdev->dev, "The received message size is invalid: %u\n",
                        hdr->size);
                return;
index 0c905bd0fab4d17eb4dd2e1aea731e8595dee26d..db19cd03ecad8a91f327c7c0c7d63879a52aa315 100644 (file)
@@ -23,7 +23,8 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
 
        /* trigger a single pipeline */
        if (trigger_list->count == 1)
-               return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state);
+               return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
+                                                  state);
 
        primary = state;
        primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
@@ -42,15 +43,15 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
        return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size);
 }
 
-int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state)
 {
        struct sof_ipc4_msg msg = {{ 0 }};
        u32 primary;
 
-       dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
+       dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state);
 
        primary = state;
-       primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
+       primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id);
        primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
        primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
        primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@ -79,19 +80,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
                 * for the first time
                 */
                if (spipe->started_count == spipe->paused_count)
-                       trigger_list->pipeline_ids[trigger_list->count++] =
+                       trigger_list->pipeline_instance_ids[trigger_list->count++] =
                                pipe_widget->instance_id;
                break;
        case SOF_IPC4_PIPE_RESET:
                /* RESET if the pipeline is neither running nor paused */
                if (!spipe->started_count && !spipe->paused_count)
-                       trigger_list->pipeline_ids[trigger_list->count++] =
+                       trigger_list->pipeline_instance_ids[trigger_list->count++] =
                                pipe_widget->instance_id;
                break;
        case SOF_IPC4_PIPE_PAUSED:
                /* Pause the pipeline only when its started_count is 1 more than paused_count */
                if (spipe->paused_count == (spipe->started_count - 1))
-                       trigger_list->pipeline_ids[trigger_list->count++] =
+                       trigger_list->pipeline_instance_ids[trigger_list->count++] =
                                pipe_widget->instance_id;
                break;
        default:
@@ -113,7 +114,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
 
        /* set state for pipeline if it was just triggered */
        for (i = 0; i < trigger_list->count; i++) {
-               if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) {
+               if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) {
                        pipeline->state = state;
                        break;
                }
@@ -314,8 +315,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
                return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
 
        /* allocate memory for the pipeline data */
-       trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
-                              GFP_KERNEL);
+       trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
+                                          pipeline_list->count), GFP_KERNEL);
        if (!trigger_list)
                return -ENOMEM;
 
@@ -708,6 +709,9 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
        struct snd_sof_pcm *spcm;
 
        spcm = snd_sof_find_spcm_dai(component, rtd);
+       if (!spcm)
+               return -EINVAL;
+
        time_info = spcm->stream[substream->stream].private;
        /* delay calculation is not supported by current fw_reg ABI */
        if (!time_info)
index a4e1a70b607d9bb6d6b9661a5da53aa015fbcb11..633f6040d7128c6f2b9a422e66b712af32ccdc76 100644 (file)
@@ -1731,6 +1731,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
 
        *ipc_config_size = ipc_size;
 
+       /* update pipeline memory usage */
+       sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
+
        /* copy IPC data */
        memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
        if (gtw_cfg_config_length)
@@ -1743,8 +1746,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
                       gtw_cfg_config_length,
                       &ipc4_copier->dma_config_tlv, dma_config_tlv_size);
 
-       /* update pipeline memory usage */
-       sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
+       /*
+        * Restore gateway config length now that IPC payload is prepared. This avoids
+        * counting the DMA CONFIG TLV multiple times
+        */
+       copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
 
        return 0;
 }
@@ -2319,6 +2325,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
                pipeline->mem_usage = 0;
                pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
                ida_free(&pipeline_ida, swidget->instance_id);
+               swidget->instance_id = -EINVAL;
        } else {
                struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
                struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
index 6dcf14886e856b324c1971d2f1cb763a8990f328..d75f17f4749c60600611e8dad9839d889f4b1ca6 100644 (file)
@@ -144,11 +144,11 @@ struct sof_ipc4_pipeline {
 /**
  * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data
  * @count: Number of pipelines to be triggered
- * @pipeline_ids: Flexible array of IDs of the pipelines to be triggered
+ * @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered
  */
 struct ipc4_pipeline_set_state_data {
        u32 count;
-       DECLARE_FLEX_ARRAY(u32, pipeline_ids);
+       DECLARE_FLEX_ARRAY(u32, pipeline_instance_ids);
 } __packed;
 
 /**
index 3e0ea0e109e2f6d6fc572d3b791c3264a432f96f..f587edf9e0a70fdeb786a71b8ebfcd5d529c4360 100644 (file)
@@ -111,6 +111,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
 
        dev_dbg(dev, "DMA %pR\n", &res);
 
+       adsp->pa_shared_dram = (phys_addr_t)res.start;
+       adsp->shared_size = resource_size(&res);
+       if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
+               dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
+                       (u32)adsp->pa_shared_dram);
+               return -EINVAL;
+       }
+
        ret = of_reserved_mem_device_init(dev);
        if (ret) {
                dev_err(dev, "of_reserved_mem_device_init failed\n");
@@ -244,23 +252,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
 {
        struct device *dev = &pdev->dev;
        struct mtk_adsp_chip_info *adsp = data;
-       u32 shared_size;
 
        /* remap shared-dram base to be non-cachable */
-       shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL;
-       adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size;
-       if (adsp->va_dram) {
-               adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size;
-       } else {
-               adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
-                                                shared_size);
-               if (!adsp->shared_dram) {
-                       dev_err(dev, "ioremap failed for shared DRAM\n");
-                       return -ENOMEM;
-               }
+       adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
+                                        adsp->shared_size);
+       if (!adsp->shared_dram) {
+               dev_err(dev, "failed to ioremap base %pa size %#x\n",
+                       adsp->shared_dram, adsp->shared_size);
+               return -ENOMEM;
        }
-       dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
-               adsp->shared_dram, &adsp->pa_shared_dram, shared_size);
+
+       dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa,  size=%#x\n",
+               adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
 
        return 0;
 }
@@ -307,9 +310,12 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
                return -ENOMEM;
        }
 
-       sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev,
-                                                         priv->adsp->pa_dram,
-                                                         priv->adsp->dramsize);
+       priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM];
+
+       sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev,
+                                                      priv->adsp->pa_dram,
+                                                      priv->adsp->dramsize);
+
        if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
                dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
                        &priv->adsp->pa_dram, priv->adsp->dramsize);
index ea21ef176c42b7e23425d701507ba1495ba303d5..c56a85854d92c8f72c07a1b5ffa482f36e161623 100644 (file)
@@ -146,6 +146,9 @@ static int ipc4_probes_deinit(struct sof_client_dev *cdev)
        struct sof_man4_module *mentry = sof_ipc4_probe_get_module_info(cdev);
        struct sof_ipc4_msg msg;
 
+       if (!mentry)
+               return -ENODEV;
+
        msg.primary = mentry->id;
        msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_DELETE_INSTANCE);
        msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
@@ -197,6 +200,9 @@ static int ipc4_probes_points_add(struct sof_client_dev *cdev,
        struct sof_ipc4_msg msg;
        int i, ret;
 
+       if (!mentry)
+               return -ENODEV;
+
        /* The sof_probe_point_desc and sof_ipc4_probe_point structs
         * are of same size and even the integers are the same in the
         * same order, and similar meaning, but since there is no
@@ -247,6 +253,9 @@ static int ipc4_probes_points_remove(struct sof_client_dev *cdev,
        u32 *probe_point_ids;
        int i, ret;
 
+       if (!mentry)
+               return -ENODEV;
+
        probe_point_ids = kcalloc(num_buffer_id, sizeof(*probe_point_ids),
                                  GFP_KERNEL);
        if (!probe_point_ids)
index 8d9e9d5f40e45b9626bf4797a4316c39e975042f..740b637822db38e4d2d1ad43708ad0be1324389c 100644 (file)
@@ -354,10 +354,14 @@ static const struct file_operations sof_probes_points_remove_fops = {
        .owner = THIS_MODULE,
 };
 
+static const struct snd_soc_dai_ops sof_probes_dai_ops = {
+       .compress_new = snd_soc_new_compress,
+};
+
 static struct snd_soc_dai_driver sof_probes_dai_drv[] = {
 {
        .name = "Probe Extraction CPU DAI",
-       .compress_new = snd_soc_new_compress,
+       .ops  = &sof_probes_dai_ops,
        .cops = &sof_probes_compr_ops,
        .capture = {
                .stream_name = "Probe Extraction",
@@ -523,6 +527,7 @@ static void sof_probes_client_remove(struct auxiliary_device *auxdev)
 
 static const struct auxiliary_device_id sof_probes_client_id_table[] = {
        { .name = "snd_sof.hda-probes", },
+       { .name = "snd_sof.acp-probes", },
        {},
 };
 MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table);
index 698129dccc7df26183c543ceaf7dfcd4dc4c38b8..a3a3af252259d9f447da23381bc9cb37d2e22311 100644 (file)
@@ -1117,10 +1117,11 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
 {
        struct snd_soc_card *card = scomp->card;
        struct snd_soc_pcm_runtime *rtd;
+       const char *sname = w->sname;
        struct snd_soc_dai *cpu_dai;
        int i, stream;
 
-       if (!w->sname)
+       if (!sname)
                return;
 
        if (w->id == snd_soc_dapm_dai_out)
@@ -1133,7 +1134,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
        list_for_each_entry(rtd, &card->rtd_list, list) {
                /* does stream match DAI link ? */
                if (!rtd->dai_link->stream_name ||
-                   strcmp(w->sname, rtd->dai_link->stream_name))
+                   strcmp(sname, rtd->dai_link->stream_name))
                        continue;
 
                for_each_rtd_cpu_dais(rtd, i, cpu_dai)
@@ -1366,6 +1367,20 @@ err:
        return ret;
 }
 
+static int get_w_no_wname_in_long_name(void *elem, void *object, u32 offset)
+{
+       struct snd_soc_tplg_vendor_value_elem *velem = elem;
+       struct snd_soc_dapm_widget *w = object;
+
+       w->no_wname_in_kcontrol_name = !!le32_to_cpu(velem->value);
+       return 0;
+}
+
+static const struct sof_topology_token dapm_widget_tokens[] = {
+       {SOF_TKN_COMP_NO_WNAME_IN_KCONTROL_NAME, SND_SOC_TPLG_TUPLE_TYPE_BOOL,
+        get_w_no_wname_in_long_name, 0}
+};
+
 /* external widget init - used for any driver specific init */
 static int sof_widget_ready(struct snd_soc_component *scomp, int index,
                            struct snd_soc_dapm_widget *w,
@@ -1396,6 +1411,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
        ida_init(&swidget->output_queue_ida);
        ida_init(&swidget->input_queue_ida);
 
+       ret = sof_parse_tokens(scomp, w, dapm_widget_tokens, ARRAY_SIZE(dapm_widget_tokens),
+                              priv->array, le32_to_cpu(priv->size));
+       if (ret < 0) {
+               dev_err(scomp->dev, "failed to parse dapm widget tokens for %s\n",
+                       w->name);
+               goto widget_free;
+       }
+
        ret = sof_parse_tokens(scomp, swidget, comp_pin_tokens,
                               ARRAY_SIZE(comp_pin_tokens), priv->array,
                               le32_to_cpu(priv->size));
@@ -2157,6 +2180,8 @@ static int sof_complete(struct snd_soc_component *scomp)
                struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
                struct snd_sof_widget *swidget;
 
+               pipe_widget->instance_id = -EINVAL;
+
                /* Update the scheduler widget's IPC structure */
                if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) {
                        ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget);
index 5f5a6ca7dbda68789ce2327c33fbc451cc42e254..8c117794b02897fe920c90f80ef892d746d49079 100644 (file)
@@ -463,13 +463,6 @@ static int jh7110_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = {
-       .startup        = jh7110_tdm_startup,
-       .hw_params      = jh7110_tdm_hw_params,
-       .trigger        = jh7110_tdm_trigger,
-       .set_fmt        = jh7110_tdm_set_dai_fmt,
-};
-
 static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai)
 {
        struct jh7110_tdm_dev *tdm = snd_soc_dai_get_drvdata(dai);
@@ -479,6 +472,14 @@ static int jh7110_tdm_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops jh7110_tdm_dai_ops = {
+       .probe          = jh7110_tdm_dai_probe,
+       .startup        = jh7110_tdm_startup,
+       .hw_params      = jh7110_tdm_hw_params,
+       .trigger        = jh7110_tdm_trigger,
+       .set_fmt        = jh7110_tdm_set_dai_fmt,
+};
+
 #define JH7110_TDM_RATES       SNDRV_PCM_RATE_8000_48000
 
 #define JH7110_TDM_FORMATS     (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -502,7 +503,6 @@ static struct snd_soc_dai_driver jh7110_tdm_dai = {
                .formats        = JH7110_TDM_FORMATS,
        },
        .ops = &jh7110_tdm_dai_ops,
-       .probe = jh7110_tdm_dai_probe,
        .symmetric_rate = 1,
 };
 
@@ -634,10 +634,9 @@ err_pm_disable:
        return ret;
 }
 
-static int jh7110_tdm_dev_remove(struct platform_device *pdev)
+static void jh7110_tdm_dev_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
-       return 0;
 }
 
 static const struct of_device_id jh7110_tdm_of_match[] = {
@@ -661,7 +660,7 @@ static struct platform_driver jh7110_tdm_driver = {
                .pm = pm_ptr(&jh7110_tdm_pm_ops),
        },
        .probe = jh7110_tdm_probe,
-       .remove = jh7110_tdm_dev_remove,
+       .remove_new = jh7110_tdm_dev_remove,
 };
 module_platform_driver(jh7110_tdm_driver);
 
index a4d74d1e3c2403321c9fb18fea4dd8550319629f..2c21a86421e66e5f6b565c671f79f176f8a672c9 100644 (file)
@@ -369,10 +369,14 @@ static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai)
        return sti_uniperiph_dai_create_ctrl(dai);
 }
 
-static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
+static const struct snd_soc_dai_ops sti_uniperiph_dai_ops = {
        .probe = sti_uniperiph_dai_probe,
 };
 
+static const struct snd_soc_dai_driver sti_uniperiph_dai_template = {
+       .ops = &sti_uniperiph_dai_ops,
+};
+
 static const struct snd_soc_component_driver sti_uniperiph_dai_component = {
        .name = "sti_cpu_dai",
        .suspend = sti_uniperiph_suspend,
index 3871307019604d04ca1d0b69963778a5f1adb126..06a42130f5e48d7252801d159b459c34bacfdf84 100644 (file)
@@ -953,6 +953,7 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = {
 };
 
 static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = {
+       .probe          = stm32_i2s_dai_probe,
        .set_sysclk     = stm32_i2s_set_sysclk,
        .set_fmt        = stm32_i2s_set_dai_fmt,
        .startup        = stm32_i2s_startup,
@@ -1002,7 +1003,6 @@ static int stm32_i2s_dais_init(struct platform_device *pdev,
        if (!dai_ptr)
                return -ENOMEM;
 
-       dai_ptr->probe = stm32_i2s_dai_probe;
        dai_ptr->ops = &stm32_i2s_pcm_dai_ops;
        dai_ptr->id = 1;
        stm32_i2s_dai_init(&dai_ptr->playback, "playback");
index 271ec5b3378d2423dbbab366a8244a5ba321040e..42d67b7a68e87a4961ef45aec551b7ff47560d84 100644 (file)
@@ -1222,6 +1222,19 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 }
 
 static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
+       .probe          = stm32_sai_dai_probe,
+       .set_sysclk     = stm32_sai_set_sysclk,
+       .set_fmt        = stm32_sai_set_dai_fmt,
+       .set_tdm_slot   = stm32_sai_set_dai_tdm_slot,
+       .startup        = stm32_sai_startup,
+       .hw_params      = stm32_sai_hw_params,
+       .trigger        = stm32_sai_trigger,
+       .shutdown       = stm32_sai_shutdown,
+       .pcm_new        = stm32_sai_pcm_new,
+};
+
+static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops2 = {
+       .probe          = stm32_sai_dai_probe,
        .set_sysclk     = stm32_sai_set_sysclk,
        .set_fmt        = stm32_sai_set_dai_fmt,
        .set_tdm_slot   = stm32_sai_set_dai_tdm_slot,
@@ -1287,8 +1300,6 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
 };
 
 static struct snd_soc_dai_driver stm32_sai_playback_dai = {
-               .probe = stm32_sai_dai_probe,
-               .pcm_new = stm32_sai_pcm_new,
                .id = 1, /* avoid call to fmt_single_name() */
                .playback = {
                        .channels_min = 1,
@@ -1306,7 +1317,6 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = {
 };
 
 static struct snd_soc_dai_driver stm32_sai_capture_dai = {
-               .probe = stm32_sai_dai_probe,
                .id = 1, /* avoid call to fmt_single_name() */
                .capture = {
                        .channels_min = 1,
@@ -1320,7 +1330,7 @@ static struct snd_soc_dai_driver stm32_sai_capture_dai = {
                                SNDRV_PCM_FMTBIT_S16_LE |
                                SNDRV_PCM_FMTBIT_S32_LE,
                },
-               .ops = &stm32_sai_pcm_dai_ops,
+               .ops = &stm32_sai_pcm_dai_ops2,
 };
 
 static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
index a4066f271f2dbf8969595004120c7e7779f1a219..a359b528b26b73c9cea380ec24d03c69ee8559ad 100644 (file)
@@ -856,6 +856,7 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = {
+       .probe          = stm32_spdifrx_dai_probe,
        .startup        = stm32_spdifrx_startup,
        .hw_params      = stm32_spdifrx_hw_params,
        .trigger        = stm32_spdifrx_trigger,
@@ -864,7 +865,6 @@ static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = {
 
 static struct snd_soc_dai_driver stm32_spdifrx_dai[] = {
        {
-               .probe = stm32_spdifrx_dai_probe,
                .capture = {
                        .stream_name = "CPU-Capture",
                        .channels_min = 1,
index 55328850aef546a459c7f5927f0925f282a2438c..f0a5fd90110182db675ecbead9a4f68a603738fa 100644 (file)
@@ -1252,9 +1252,12 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops dummy_dai_ops = {
+       .probe  = sun4i_codec_dai_probe,
+};
+
 static struct snd_soc_dai_driver dummy_cpu_dai = {
        .name   = "sun4i-codec-cpu-dai",
-       .probe  = sun4i_codec_dai_probe,
        .playback = {
                .stream_name    = "Playback",
                .channels_min   = 1,
@@ -1271,6 +1274,7 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
                .formats        = SUN4I_CODEC_FORMATS,
                .sig_bits       = 24,
         },
+       .ops = &dummy_dai_ops,
 };
 
 static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
index 669d712bbe9f771538850dc3ede004c1bcdd885c..5124b6c9ceb4b9585072c5a3d534c074937b6ba7 100644 (file)
@@ -1081,14 +1081,6 @@ static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
        return 0;
 }
 
-static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
-       .hw_params      = sun4i_i2s_hw_params,
-       .set_fmt        = sun4i_i2s_set_fmt,
-       .set_sysclk     = sun4i_i2s_set_sysclk,
-       .set_tdm_slot   = sun4i_i2s_set_tdm_slot,
-       .trigger        = sun4i_i2s_trigger,
-};
-
 static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -1100,12 +1092,20 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
+       .probe          = sun4i_i2s_dai_probe,
+       .hw_params      = sun4i_i2s_hw_params,
+       .set_fmt        = sun4i_i2s_set_fmt,
+       .set_sysclk     = sun4i_i2s_set_sysclk,
+       .set_tdm_slot   = sun4i_i2s_set_tdm_slot,
+       .trigger        = sun4i_i2s_trigger,
+};
+
 #define SUN4I_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | \
                         SNDRV_PCM_FMTBIT_S20_LE | \
                         SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_driver sun4i_i2s_dai = {
-       .probe = sun4i_i2s_dai_probe,
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
index ff18d4113aac0823e1a0c9c488912e724199f16d..b849bb7cf58e24b571fb37d3d4f757da7ef691c4 100644 (file)
@@ -508,6 +508,7 @@ static int sun4i_spdif_soc_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops sun4i_spdif_dai_ops = {
+       .probe          = sun4i_spdif_soc_dai_probe,
        .startup        = sun4i_spdif_startup,
        .trigger        = sun4i_spdif_trigger,
        .hw_params      = sun4i_spdif_hw_params,
@@ -533,7 +534,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
                .rates = SUN4I_RATES,
                .formats = SUN4I_FORMATS,
        },
-       .probe = sun4i_spdif_soc_dai_probe,
        .ops = &sun4i_spdif_dai_ops,
        .name = "spdif",
 };
@@ -718,7 +718,7 @@ static const struct dev_pm_ops sun4i_spdif_pm = {
 static struct platform_driver sun4i_spdif_driver = {
        .driver         = {
                .name   = "sun4i-spdif",
-               .of_match_table = of_match_ptr(sun4i_spdif_of_match),
+               .of_match_table = sun4i_spdif_of_match,
                .pm     = &sun4i_spdif_pm,
        },
        .probe          = sun4i_spdif_probe,
index c10439b9e0a26c6b1f2302c391cfdd54afb60136..2599683a582dcd51863a97cfff7f63ec64cb1fb5 100644 (file)
@@ -236,6 +236,7 @@ static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = {
+       .probe          = sun50i_dmic_soc_dai_probe,
        .startup        = sun50i_dmic_startup,
        .trigger        = sun50i_dmic_trigger,
        .hw_params      = sun50i_dmic_hw_params,
@@ -260,7 +261,6 @@ static struct snd_soc_dai_driver sun50i_dmic_dai = {
                .formats = SUN50I_DMIC_FORMATS,
                .sig_bits = 21,
        },
-       .probe = sun50i_dmic_soc_dai_probe,
        .ops = &sun50i_dmic_dai_ops,
        .name = "dmic",
 };
index a4073a746ae32e88262128e1bedc8c9b88f7b1e3..e713feca25fa426fccfaf73637a781843112c0b7 100644 (file)
@@ -203,10 +203,6 @@ static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
-       .trigger        = tegra20_ac97_trigger,
-};
-
 static int tegra20_ac97_probe(struct snd_soc_dai *dai)
 {
        struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
@@ -217,9 +213,13 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
+       .probe          = tegra20_ac97_probe,
+       .trigger        = tegra20_ac97_trigger,
+};
+
 static struct snd_soc_dai_driver tegra20_ac97_dai = {
        .name = "tegra-ac97-pcm",
-       .probe = tegra20_ac97_probe,
        .playback = {
                .stream_name = "PCM Playback",
                .channels_min = 2,
@@ -328,8 +328,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
                goto err;
        }
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       regs = devm_ioremap_resource(&pdev->dev, mem);
+       regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
        if (IS_ERR(regs)) {
                ret = PTR_ERR(regs);
                goto err_clk_put;
index d38b58305c6bedd5626eb29782ee2df5e9fb8faf..f11618e8f13ee250bf37fc1ec49a61b122cef502 100644 (file)
@@ -310,6 +310,7 @@ static int tegra20_i2s_startup(struct snd_pcm_substream *substream,
 }
 
 static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
+       .probe          = tegra20_i2s_probe,
        .set_fmt        = tegra20_i2s_set_fmt,
        .hw_params      = tegra20_i2s_hw_params,
        .trigger        = tegra20_i2s_trigger,
@@ -317,7 +318,6 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
 };
 
 static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
-       .probe = tegra20_i2s_probe,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
index d034803695a0617c500ecd6a3fb53325c35d865d..b0670aa4d9671140f04d3e877b5ead59944eb655 100644 (file)
@@ -241,6 +241,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
+       .probe = tegra20_spdif_probe,
        .hw_params = tegra20_spdif_hw_params,
        .trigger = tegra20_spdif_trigger,
        .startup = tegra20_spdif_startup,
@@ -248,7 +249,6 @@ static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
 
 static struct snd_soc_dai_driver tegra20_spdif_dai = {
        .name = "tegra20-spdif",
-       .probe = tegra20_spdif_probe,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
index 6868508585a0158f9a000d3e620d2a1294d61e67..9f9334e48049005f2ec84bc6603c3d753d9b1c36 100644 (file)
@@ -419,11 +419,6 @@ static int tegra_admaif_trigger(struct snd_pcm_substream *substream, int cmd,
        }
 }
 
-static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
-       .hw_params      = tegra_admaif_hw_params,
-       .trigger        = tegra_admaif_trigger,
-};
-
 static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -550,10 +545,15 @@ static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
+       .probe          = tegra_admaif_dai_probe,
+       .hw_params      = tegra_admaif_hw_params,
+       .trigger        = tegra_admaif_trigger,
+};
+
 #define DAI(dai_name)                                  \
        {                                                       \
                .name = dai_name,                               \
-               .probe = tegra_admaif_dai_probe,                \
                .playback = {                                   \
                        .stream_name = dai_name " Playback",    \
                        .channels_min = 1,                      \
index 6442806030956e088e3e0dcf3fdd78351bde5c9a..81eaece511304ca1b4f6b0509dd367ce9a3348e8 100644 (file)
@@ -304,6 +304,7 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
 }
 
 static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
+       .probe          = tegra30_i2s_probe,
        .set_fmt        = tegra30_i2s_set_fmt,
        .hw_params      = tegra30_i2s_hw_params,
        .trigger        = tegra30_i2s_trigger,
@@ -311,7 +312,6 @@ static const struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
 };
 
 static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
-       .probe = tegra30_i2s_probe,
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
index 983d69b951b003f79267bc8ae6eaae5c55a62891..544cb3da50eb092b8ed8b8dde5c17ff37558095a 100644 (file)
@@ -257,18 +257,7 @@ static struct platform_driver davinci_evm_driver = {
        },
 };
 
-static int __init evm_init(void)
-{
-       return platform_driver_register(&davinci_evm_driver);
-}
-
-static void __exit evm_exit(void)
-{
-       platform_driver_unregister(&davinci_evm_driver);
-}
-
-module_init(evm_init);
-module_exit(evm_exit);
+module_platform_driver(davinci_evm_driver);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver");
index 97dd1634b6becb67557fc243a8bf23ef8c3b4505..07c8b2259208dc95ee479cb1496d24d576d718f9 100644 (file)
@@ -601,16 +601,6 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
 #define DAVINCI_I2S_FORMATS    (SNDRV_PCM_FMTBIT_S16_LE | \
                                 SNDRV_PCM_FMTBIT_S32_LE)
 
-static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
-       .shutdown       = davinci_i2s_shutdown,
-       .prepare        = davinci_i2s_prepare,
-       .trigger        = davinci_i2s_trigger,
-       .hw_params      = davinci_i2s_hw_params,
-       .set_fmt        = davinci_i2s_set_dai_fmt,
-       .set_clkdiv     = davinci_i2s_dai_set_clkdiv,
-
-};
-
 static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -622,8 +612,18 @@ static int davinci_i2s_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+       .probe          = davinci_i2s_dai_probe,
+       .shutdown       = davinci_i2s_shutdown,
+       .prepare        = davinci_i2s_prepare,
+       .trigger        = davinci_i2s_trigger,
+       .hw_params      = davinci_i2s_hw_params,
+       .set_fmt        = davinci_i2s_set_dai_fmt,
+       .set_clkdiv     = davinci_i2s_dai_set_clkdiv,
+
+};
+
 static struct snd_soc_dai_driver davinci_i2s_dai = {
-       .probe = davinci_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index 172fea764a31c8f39935e95f6f113a8277d2c585..7e7d665a5504af05bfdefbfd86124a7a6b53a98e 100644 (file)
@@ -1616,18 +1616,6 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
-static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
-       .startup        = davinci_mcasp_startup,
-       .shutdown       = davinci_mcasp_shutdown,
-       .trigger        = davinci_mcasp_trigger,
-       .delay          = davinci_mcasp_delay,
-       .hw_params      = davinci_mcasp_hw_params,
-       .set_fmt        = davinci_mcasp_set_dai_fmt,
-       .set_clkdiv     = davinci_mcasp_set_clkdiv,
-       .set_sysclk     = davinci_mcasp_set_sysclk,
-       .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
-};
-
 static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo)
 {
@@ -1716,6 +1704,19 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+       .probe          = davinci_mcasp_dai_probe,
+       .startup        = davinci_mcasp_startup,
+       .shutdown       = davinci_mcasp_shutdown,
+       .trigger        = davinci_mcasp_trigger,
+       .delay          = davinci_mcasp_delay,
+       .hw_params      = davinci_mcasp_hw_params,
+       .set_fmt        = davinci_mcasp_set_dai_fmt,
+       .set_clkdiv     = davinci_mcasp_set_clkdiv,
+       .set_sysclk     = davinci_mcasp_set_sysclk,
+       .set_tdm_slot   = davinci_mcasp_set_tdm_slot,
+};
+
 #define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_192000
 
 #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
@@ -1732,7 +1733,6 @@ static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
 static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        {
                .name           = "davinci-mcasp.0",
-               .probe          = davinci_mcasp_dai_probe,
                .playback       = {
                        .stream_name = "IIS Playback",
                        .channels_min   = 1,
@@ -1753,7 +1753,6 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        },
        {
                .name           = "davinci-mcasp.1",
-               .probe          = davinci_mcasp_dai_probe,
                .playback       = {
                        .stream_name = "DIT Playback",
                        .channels_min   = 1,
index 825c70a443dad1c2b4ff9ff2e76282bfb68c38e8..5b5eccf303abafa13efaa5002b05e0e8c0f5c774 100644 (file)
@@ -401,15 +401,6 @@ static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
        return -EINVAL;
 }
 
-static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
-       .startup        = omap_dmic_dai_startup,
-       .shutdown       = omap_dmic_dai_shutdown,
-       .hw_params      = omap_dmic_dai_hw_params,
-       .prepare        = omap_dmic_dai_prepare,
-       .trigger        = omap_dmic_dai_trigger,
-       .set_sysclk     = omap_dmic_set_dai_sysclk,
-};
-
 static int omap_dmic_probe(struct snd_soc_dai *dai)
 {
        struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
@@ -438,10 +429,19 @@ static int omap_dmic_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
+       .probe          = omap_dmic_probe,
+       .remove         = omap_dmic_remove,
+       .startup        = omap_dmic_dai_startup,
+       .shutdown       = omap_dmic_dai_shutdown,
+       .hw_params      = omap_dmic_dai_hw_params,
+       .prepare        = omap_dmic_dai_prepare,
+       .trigger        = omap_dmic_dai_trigger,
+       .set_sysclk     = omap_dmic_set_dai_sysclk,
+};
+
 static struct snd_soc_dai_driver omap_dmic_dai = {
        .name = "omap-dmic",
-       .probe = omap_dmic_probe,
-       .remove = omap_dmic_remove,
        .capture = {
                .channels_min = 2,
                .channels_max = 6,
@@ -488,12 +488,10 @@ static int asoc_dmic_probe(struct platform_device *pdev)
 
        dmic->dma_data.filter_data = "up_link";
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
+       dmic->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu");
        if (IS_ERR(dmic->io_base))
                return PTR_ERR(dmic->io_base);
 
-
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &omap_dmic_component,
                                              &omap_dmic_dai, 1);
index 21fa7b9787997c6d6e5b2f5c266adf92a9be31e5..fdabed5133e836d78fa375c6b261705096b3229e 100644 (file)
@@ -70,8 +70,8 @@ static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
 
        fck_src = clk_get(mcbsp->dev, src);
        if (IS_ERR(fck_src)) {
-               dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
-               return -EINVAL;
+               dev_info(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
+               return 0;
        }
 
        pm_runtime_put_sync(mcbsp->dev);
@@ -1254,18 +1254,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-static const struct snd_soc_dai_ops mcbsp_dai_ops = {
-       .startup        = omap_mcbsp_dai_startup,
-       .shutdown       = omap_mcbsp_dai_shutdown,
-       .prepare        = omap_mcbsp_dai_prepare,
-       .trigger        = omap_mcbsp_dai_trigger,
-       .delay          = omap_mcbsp_dai_delay,
-       .hw_params      = omap_mcbsp_dai_hw_params,
-       .set_fmt        = omap_mcbsp_dai_set_dai_fmt,
-       .set_clkdiv     = omap_mcbsp_dai_set_clkdiv,
-       .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
-};
-
 static int omap_mcbsp_probe(struct snd_soc_dai *dai)
 {
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
@@ -1288,9 +1276,21 @@ static int omap_mcbsp_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops mcbsp_dai_ops = {
+       .probe          = omap_mcbsp_probe,
+       .remove         = omap_mcbsp_remove,
+       .startup        = omap_mcbsp_dai_startup,
+       .shutdown       = omap_mcbsp_dai_shutdown,
+       .prepare        = omap_mcbsp_dai_prepare,
+       .trigger        = omap_mcbsp_dai_trigger,
+       .delay          = omap_mcbsp_dai_delay,
+       .hw_params      = omap_mcbsp_dai_hw_params,
+       .set_fmt        = omap_mcbsp_dai_set_dai_fmt,
+       .set_clkdiv     = omap_mcbsp_dai_set_clkdiv,
+       .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
+};
+
 static struct snd_soc_dai_driver omap_mcbsp_dai = {
-       .probe = omap_mcbsp_probe,
-       .remove = omap_mcbsp_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 16,
index 0b18a7bfd3fd73f5cd9179d7b35fc658dd76f8c1..d7d9f708f1fdece01b66d5ce4ff06a0610ce62d7 100644 (file)
@@ -404,13 +404,6 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
-       .startup        = omap_mcpdm_dai_startup,
-       .shutdown       = omap_mcpdm_dai_shutdown,
-       .hw_params      = omap_mcpdm_dai_hw_params,
-       .prepare        = omap_mcpdm_prepare,
-};
-
 static int omap_mcpdm_probe(struct snd_soc_dai *dai)
 {
        struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
@@ -457,6 +450,17 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
+static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
+       .probe          = omap_mcpdm_probe,
+       .remove         = omap_mcpdm_remove,
+       .startup        = omap_mcpdm_dai_startup,
+       .shutdown       = omap_mcpdm_dai_shutdown,
+       .hw_params      = omap_mcpdm_dai_hw_params,
+       .prepare        = omap_mcpdm_prepare,
+       .probe_order    = SND_SOC_COMP_ORDER_LATE,
+       .remove_order   = SND_SOC_COMP_ORDER_EARLY,
+};
+
 #ifdef CONFIG_PM_SLEEP
 static int omap_mcpdm_suspend(struct snd_soc_component *component)
 {
@@ -502,10 +506,6 @@ static int omap_mcpdm_resume(struct snd_soc_component *component)
 #define OMAP_MCPDM_FORMATS     SNDRV_PCM_FMTBIT_S32_LE
 
 static struct snd_soc_dai_driver omap_mcpdm_dai = {
-       .probe = omap_mcpdm_probe,
-       .remove = omap_mcpdm_remove,
-       .probe_order = SND_SOC_COMP_ORDER_LATE,
-       .remove_order = SND_SOC_COMP_ORDER_EARLY,
        .playback = {
                .channels_min = 1,
                .channels_max = 5,
@@ -563,8 +563,7 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
        mcpdm->dma_data[0].filter_data = "dn_link";
        mcpdm->dma_data[1].filter_data = "up_link";
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
+       mcpdm->io_base = devm_platform_ioremap_resource_byname(pdev, "mpu");
        if (IS_ERR(mcpdm->io_base))
                return PTR_ERR(mcpdm->io_base);
 
index 4e8d5f7532bae23da1e55a8abc26f4188f820d11..7c5188477b7c90c4667dbc89eec7c4dd151f8d28 100644 (file)
@@ -355,30 +355,7 @@ static int uniphier_aio_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
-const struct snd_soc_dai_ops uniphier_aio_i2s_ops = {
-       .set_sysclk  = uniphier_aio_set_sysclk,
-       .set_pll     = uniphier_aio_set_pll,
-       .set_fmt     = uniphier_aio_set_fmt,
-       .startup     = uniphier_aio_startup,
-       .shutdown    = uniphier_aio_shutdown,
-       .hw_params   = uniphier_aio_hw_params,
-       .hw_free     = uniphier_aio_hw_free,
-       .prepare     = uniphier_aio_prepare,
-};
-EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ops);
-
-const struct snd_soc_dai_ops uniphier_aio_spdif_ops = {
-       .set_sysclk  = uniphier_aio_set_sysclk,
-       .set_pll     = uniphier_aio_set_pll,
-       .startup     = uniphier_aio_startup,
-       .shutdown    = uniphier_aio_shutdown,
-       .hw_params   = uniphier_aio_hw_params,
-       .hw_free     = uniphier_aio_hw_free,
-       .prepare     = uniphier_aio_prepare,
-};
-EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ops);
-
-int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
+static int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
 {
        struct uniphier_aio *aio = uniphier_priv(dai);
        int i;
@@ -403,9 +380,8 @@ int uniphier_aio_dai_probe(struct snd_soc_dai *dai)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(uniphier_aio_dai_probe);
 
-int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
+static int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
 {
        struct uniphier_aio *aio = uniphier_priv(dai);
 
@@ -413,7 +389,138 @@ int uniphier_aio_dai_remove(struct snd_soc_dai *dai)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(uniphier_aio_dai_remove);
+
+static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
+{
+       int ret;
+
+       ret = uniphier_aio_dai_probe(dai);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
+{
+       int ret;
+
+       ret = uniphier_aio_dai_probe(dai);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops = {
+       .probe          = uniphier_aio_ld11_probe,
+       .remove         = uniphier_aio_dai_remove,
+       .set_sysclk     = uniphier_aio_set_sysclk,
+       .set_pll        = uniphier_aio_set_pll,
+       .set_fmt        = uniphier_aio_set_fmt,
+       .startup        = uniphier_aio_startup,
+       .shutdown       = uniphier_aio_shutdown,
+       .hw_params      = uniphier_aio_hw_params,
+       .hw_free        = uniphier_aio_hw_free,
+       .prepare        = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_i2s_ld11_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops = {
+       .probe          = uniphier_aio_ld11_probe,
+       .remove         = uniphier_aio_dai_remove,
+       .set_sysclk     = uniphier_aio_set_sysclk,
+       .set_pll        = uniphier_aio_set_pll,
+       .startup        = uniphier_aio_startup,
+       .shutdown       = uniphier_aio_shutdown,
+       .hw_params      = uniphier_aio_hw_params,
+       .hw_free        = uniphier_aio_hw_free,
+       .prepare        = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2 = {
+       .probe          = uniphier_aio_ld11_probe,
+       .remove         = uniphier_aio_dai_remove,
+       .set_sysclk     = uniphier_aio_set_sysclk,
+       .set_pll        = uniphier_aio_set_pll,
+       .startup        = uniphier_aio_startup,
+       .shutdown       = uniphier_aio_shutdown,
+       .hw_params      = uniphier_aio_hw_params,
+       .hw_free        = uniphier_aio_hw_free,
+       .prepare        = uniphier_aio_prepare,
+       .compress_new   = snd_soc_new_compress,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_ld11_ops2);
+
+const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops = {
+       .probe          = uniphier_aio_pxs2_probe,
+       .remove         = uniphier_aio_dai_remove,
+       .set_sysclk     = uniphier_aio_set_sysclk,
+       .set_pll        = uniphier_aio_set_pll,
+       .set_fmt        = uniphier_aio_set_fmt,
+       .startup        = uniphier_aio_startup,
+       .shutdown       = uniphier_aio_shutdown,
+       .hw_params      = uniphier_aio_hw_params,
+       .hw_free        = uniphier_aio_hw_free,
+       .prepare        = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_i2s_pxs2_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops = {
+       .probe          = uniphier_aio_pxs2_probe,
+       .remove         = uniphier_aio_dai_remove,
+       .set_sysclk     = uniphier_aio_set_sysclk,
+       .set_pll        = uniphier_aio_set_pll,
+       .startup        = uniphier_aio_startup,
+       .shutdown       = uniphier_aio_shutdown,
+       .hw_params      = uniphier_aio_hw_params,
+       .hw_free        = uniphier_aio_hw_free,
+       .prepare        = uniphier_aio_prepare,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops);
+
+const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2 = {
+       .probe          = uniphier_aio_pxs2_probe,
+       .remove         = uniphier_aio_dai_remove,
+       .set_sysclk     = uniphier_aio_set_sysclk,
+       .set_pll        = uniphier_aio_set_pll,
+       .startup        = uniphier_aio_startup,
+       .shutdown       = uniphier_aio_shutdown,
+       .hw_params      = uniphier_aio_hw_params,
+       .hw_free        = uniphier_aio_hw_free,
+       .prepare        = uniphier_aio_prepare,
+       .compress_new   = snd_soc_new_compress,
+};
+EXPORT_SYMBOL_GPL(uniphier_aio_spdif_pxs2_ops2);
 
 static void uniphier_aio_dai_suspend(struct snd_soc_dai *dai)
 {
index 7b3cf5d751f69c5ce564dd58d6869b92d603ca21..15dbded6380432c80548e7ae4b721ce66f6f1f88 100644 (file)
@@ -188,36 +188,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_ld11[] = {
        [AUD_PLL_HSC0] = { .enable = true, },
 };
 
-static int uniphier_aio_ld11_probe(struct snd_soc_dai *dai)
-{
-       int ret;
-
-       ret = uniphier_aio_dai_probe(dai);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
-       if (ret < 0)
-               return ret;
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
-       if (ret < 0)
-               return ret;
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
 static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
        {
                .name    = AUD_GNAME_HDMI,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_PCMOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -234,12 +207,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_NAME_PCMIN2,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .capture = {
                        .stream_name = AUD_NAME_PCMIN2,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -247,12 +218,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_GNAME_LINE,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_PCMOUT2,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -267,12 +236,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_NAME_HPCMOUT1,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_HPCMOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -280,12 +247,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 8,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_NAME_PCMOUT3,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_PCMOUT3,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -293,12 +258,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_NAME_HIECOUT1,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_HIECOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -306,12 +269,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_spdif_ops,
+               .ops = &uniphier_aio_spdif_ld11_ops,
        },
        {
                .name    = AUD_NAME_EPCMOUT2,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_EPCMOUT2,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -321,12 +282,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_NAME_EPCMOUT3,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_EPCMOUT3,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -336,19 +295,16 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_ld11_ops,
        },
        {
                .name    = AUD_NAME_HIECCOMPOUT1,
-               .probe   = uniphier_aio_ld11_probe,
-               .remove  = uniphier_aio_dai_remove,
-               .compress_new = snd_soc_new_compress,
                .playback = {
                        .stream_name = AUD_NAME_HIECCOMPOUT1,
                        .channels_min = 1,
                        .channels_max = 1,
                },
-               .ops = &uniphier_aio_spdif_ops,
+               .ops = &uniphier_aio_spdif_ld11_ops2,
        },
 };
 
index 899904f7ffd6d653b0ec933ba1acbc94c78ab950..305cb2a1253dac14261307befbe2b30719b0e209 100644 (file)
@@ -141,36 +141,9 @@ static const struct uniphier_aio_pll uniphier_aio_pll_pxs2[] = {
        [AUD_PLL_HSC0] = { .enable = true, },
 };
 
-static int uniphier_aio_pxs2_probe(struct snd_soc_dai *dai)
-{
-       int ret;
-
-       ret = uniphier_aio_dai_probe(dai);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A1, 0, 0, 36864000);
-       if (ret < 0)
-               return ret;
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F1, 0, 0, 36864000);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_A2, 0, 0, 33868800);
-       if (ret < 0)
-               return ret;
-       ret = snd_soc_dai_set_pll(dai, AUD_PLL_F2, 0, 0, 33868800);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
 static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
        {
                .name    = AUD_GNAME_HDMI,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_HPCMOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -178,12 +151,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_pxs2_ops,
        },
        {
                .name    = AUD_GNAME_LINE,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_PCMOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -198,12 +169,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_pxs2_ops,
        },
        {
                .name    = AUD_GNAME_AUX,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_PCMOUT2,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -218,12 +187,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_i2s_ops,
+               .ops = &uniphier_aio_i2s_pxs2_ops,
        },
        {
                .name    = AUD_NAME_HIECOUT1,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_HIECOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -231,12 +198,10 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_spdif_ops,
+               .ops = &uniphier_aio_spdif_pxs2_ops,
        },
        {
                .name    = AUD_NAME_IECOUT1,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
                .playback = {
                        .stream_name = AUD_NAME_IECOUT1,
                        .formats     = SNDRV_PCM_FMTBIT_S32_LE,
@@ -244,31 +209,25 @@ static struct snd_soc_dai_driver uniphier_aio_dai_pxs2[] = {
                        .channels_min = 2,
                        .channels_max = 2,
                },
-               .ops = &uniphier_aio_spdif_ops,
+               .ops = &uniphier_aio_spdif_pxs2_ops,
        },
        {
                .name    = AUD_NAME_HIECCOMPOUT1,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
-               .compress_new = snd_soc_new_compress,
                .playback = {
                        .stream_name = AUD_NAME_HIECCOMPOUT1,
                        .channels_min = 1,
                        .channels_max = 1,
                },
-               .ops = &uniphier_aio_spdif_ops,
+               .ops = &uniphier_aio_spdif_pxs2_ops2,
        },
        {
                .name    = AUD_NAME_IECCOMPOUT1,
-               .probe   = uniphier_aio_pxs2_probe,
-               .remove  = uniphier_aio_dai_remove,
-               .compress_new = snd_soc_new_compress,
                .playback = {
                        .stream_name = AUD_NAME_IECCOMPOUT1,
                        .channels_min = 1,
                        .channels_max = 1,
                },
-               .ops = &uniphier_aio_spdif_ops,
+               .ops = &uniphier_aio_spdif_pxs2_ops2,
        },
 };
 
index 0b03571aa9f05cb21376bb2acc6b90735fa956f5..09ccb47337fd01dd80c61fa508b44963ed90433b 100644 (file)
@@ -306,12 +306,14 @@ static inline struct uniphier_aio *uniphier_priv(struct snd_soc_dai *dai)
 int uniphier_aiodma_soc_register_platform(struct platform_device *pdev);
 extern const struct snd_compress_ops uniphier_aio_compress_ops;
 
-int uniphier_aio_dai_probe(struct snd_soc_dai *dai);
-int uniphier_aio_dai_remove(struct snd_soc_dai *dai);
 int uniphier_aio_probe(struct platform_device *pdev);
 int uniphier_aio_remove(struct platform_device *pdev);
-extern const struct snd_soc_dai_ops uniphier_aio_i2s_ops;
-extern const struct snd_soc_dai_ops uniphier_aio_spdif_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_i2s_ld11_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_i2s_pxs2_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_ld11_ops2;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops;
+extern const struct snd_soc_dai_ops uniphier_aio_spdif_pxs2_ops2;
 
 u64 aio_rb_cnt(struct uniphier_aio_sub *sub);
 u64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub);
index 44e88dad85841e53211ea98099c5c077d81f60b6..cde0dd8e2569145895f28242ec79e41debea42ff 100644 (file)
@@ -683,6 +683,7 @@ static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)
 
 static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
        {
+               .probe = ux500_msp_dai_of_probe,
                .set_sysclk = ux500_msp_dai_set_dai_sysclk,
                .set_fmt = ux500_msp_dai_set_dai_fmt,
                .set_tdm_slot = ux500_msp_dai_set_tdm_slot,
@@ -695,7 +696,6 @@ static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
 };
 
 static struct snd_soc_dai_driver ux500_msp_dai_drv = {
-       .probe                 = ux500_msp_dai_of_probe,
        .playback.channels_min = UX500_MSP_MIN_CHANNELS,
        .playback.channels_max = UX500_MSP_MAX_CHANNELS,
        .playback.rates        = UX500_I2S_RATES,
index 0393940c706a6199451337f7cedffee597b2cd20..b8adb59455ef5c97a081e1a850e9a7b705287ef6 100644 (file)
@@ -35,3 +35,8 @@ CONFIG_DAMON_DBGFS=y
 
 CONFIG_SECURITY=y
 CONFIG_SECURITY_APPARMOR=y
+
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TOPOLOGY_BUILD=y